Files
shz-backend/ruoyi-common/src/main/java/com/ruoyi/common/utils/SM4Utils.java

212 lines
14 KiB
Java
Raw Normal View History

2026-01-09 20:13:01 +08:00
package com.ruoyi.common.utils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SM4Utils {
static {
Security.addProvider(new BouncyCastleProvider());
}
private static final String ENCODING = "UTF-8";
public static final String ALGORITHM_NAME = "SM4";
/**
* 加密算法/分组加密模式/分组填充方式
* PKCS5Padding-以8个字节为一组进行分组加密
* 定义分组加密模式使用PKCS5Padding
*/
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
/** 128-32位16进制256-64位16进制 */
public static final int DEFAULT_KEY_SIZE = 128;
private static Pattern p = Pattern.compile("\\s*|\t|\r|\n");
/**
* 自动生成密钥
*
* @return
* @explain
*/
public static String generateKey() {
try {
return new String(Hex.encode(generateKey(DEFAULT_KEY_SIZE)));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param keySize
* @return
* @throws Exception
* @explain
*/
public static byte[] generateKey(int keySize) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
kg.init(keySize, new SecureRandom());
return kg.generateKey().getEncoded();
}
/**
* 生成ECB暗号
*
* @param algorithmName 算法名称
* @param mode 模式
* @param key
* @return
* @throws Exception
* @explain ECB模式电子密码本模式Electronic codebook
*/
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
cipher.init(mode, sm4Key);
return cipher;
}
/**
* sm4加密
*
* @param hexKey 16进制密钥忽略大小写
* @param paramStr 待加密字符串
* @explain 加密模式ECB
* 密文长度不固定会随着被加密字符串长度的变化而变化
*/
public static String encryptEcb(String hexKey, String paramStr) {
return encryptEcb(hexKey, paramStr, true);
}
/**
* sm4加密
*
* @param hexKey 16进制密钥忽略大小写
* @param paramStr 待加密字符串
* @param isHex 是否返回16进制的加密字符串
* @return 返回16进制的加密字符串或base64String
* @explain 加密模式ECB
* 密文长度不固定会随着被加密字符串长度的变化而变化
*/
public static String encryptEcb(String hexKey, String paramStr, boolean isHex) {
try {
String cipherText = "";
// 16进制字符串-->byte[]
byte[] keyData = ByteUtils.fromHexString(hexKey);
// String-->byte[]
byte[] srcData = paramStr.getBytes(ENCODING);
// 加密后的数组
byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData);
// byte[]-->hexString
if (isHex) {
cipherText = ByteUtils.toHexString(cipherArray);
} else {
// byte[]--> base64String
cipherText = Base64Utils.encodeToString(cipherArray);
if (cipherText != null && cipherText.trim().length() > 0) {
Matcher m = p.matcher(cipherText);
cipherText = m.replaceAll("");
}
}
return cipherText;
} catch (Exception e) {
return paramStr;
}
}
/**
* 加密模式之Ecb
*
* @param key
* @param data
* @return
* @throws Exception
* @explain
*/
public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* sm4解密
*
* @param hexKey 16进制密钥
* @param cipherText 16进制的加密字符串忽略大小写
* @return 解密后的字符串
* @throws Exception
* @explain 解密模式采用ECB
*/
public static String decryptEcb(String hexKey, String cipherText) {
return decryptEcb(hexKey, cipherText, true);
}
/**
* sm4解密
*
* @param hexKey 16进制密钥
* @param cipherText 16进制的加密字符串忽略大小写
* @return 解密后的字符串
* @throws Exception
* @explain 解密模式采用ECB
*/
public static String decryptEcb(String hexKey, String cipherText, boolean isHex) {
// 用于接收解密后的字符串
String decryptStr = "";
// hexString-->byte[]
byte[] keyData = ByteUtils.fromHexString(hexKey);
byte[] cipherData;
if (isHex) {
// hexString --> byte[]
cipherData = ByteUtils.fromHexString(cipherText);
} else {
// base64String --> byte[]
cipherData = Base64Utils.decodeFromString(cipherText);
}
try {
// 解密
byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData);
// byte[]-->String
decryptStr = new String(srcData, ENCODING);
} catch (Exception e) {
e.printStackTrace();
}
return decryptStr;
}
/**
* 解密
*
* @param key
* @param cipherText
* @return
* @throws Exception
* @explain
*/
public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
public static void main(String[] args) {
//加密
// System.out.println(encryptEcb("06e6af183547026dd66eae8c0827acc7","a3b129c34a0b06800c7506075ebee2af"));
//解密
System.out.println(decryptEcb("8c10e08760bb0f8465c8e8390c8c4670","fd24f99e4007788b0ea7a003ab96f7bcd0b677a5925ba1b111cadda9c108665d8d5788bac31694a2d5f83d629c74a4addde17d2fb32a5e4fa5068d857fec04c675de24b58d84de6331eebd6c191f5a4b0bddc30b0fe2462b8911c54d6149a1991509bdbb7de00257b753cd165e90e1b5cfaa1cf994e01d21df3725599c058ccf29ea5c6cc06ce2b91828c890bb164d61bc706a5093a814173605c0b36536d77a425f178f84e95d4058ca28811c7ddecce3515327555ff536579832e3ed0a26adabbf2ac22e443c12579d8d9bf066faf8db8d26ec316378dd12e97f7bdea0c51cdfb5c8f4ad199c4db29623bca807d9a26ec4fd1e59b562b588b8923253608eaa7c5d1ba4e47cf8d6eece514836cf8d18991157befab3df18bd8d38a5e1e208118977454f41f5327e02aad1d18203a1e0e71b7fc75510f532879ad037ff299a756ac1d665773ffd12e362825c45c4fd395e51a8f2a0cd94a2a671d09ef49f3e4845b58fd9959172460bb446c7911677a74e60259c6b1df5f9ddabc7da365b7ed285150de1f4ca551f43535deff943e9c63ec979bda9a7bb402f8f654cd5bf3b327a7671331e112d02fa6ad552391a032a53c512d469d13a07ae83e5c458caecad32587ebb06171b1db299e80b3bd2416c03579e679f5f0254900f97d216b296faa5fdd5d5b00d6da52bcd327cb66656c5dd659c6bd343070399fa8653e72734ce6cedba70c68c189f6a58258816c2c02ba5b368c5c2ed00c25ebd7a8e71534a4bfad9c06586c0111cfa9445345dce93330b53f6af32931ae3a8b6b2821dc8623846fda300eeb69484340c958e588521a903ff1ec2beb14d9d6c78506ff79957722a191406ea6345252e7dec630cb46869d4cb3160db78fbac93927598649de7ecf386138864cef931d56d1013936a922c46c3ed5d924a37e79142d5514fa46e48e0a38e1575c55d2d1053fe7cea649bc005ee49584d2f42a7525285ada0dbcbcfeab4c09efe2cf981f56ec18816d5cd5f90098bbba2257d8353922c4b2f009762f144031ebd0e5c6d7ce9437a4bde7f6e4972494242f69896947baf49ee71a50f2cfec157d9d5c5106e3a659153401d2df2d2f09e07fc62505e9995e6a3f206a0fd0fac830e76598bcae22d409dcf1ddcd134e0c3bb2db4d1bcb5fd4b65d55a9f268859aa16207ed998cc0ddf6cb840b38454aec10e5770e7150f0ce97db9bce166eefe096f26110ee71aa27cdbca6e42c3cd1a05179e5aa31af8f9ec6e54de3f4e51e739a66376025615c55b1eafaecade0333abe0397ffaa75d72a82c6d75df305c3d1b3d30c29058585dc4f1675c5afb1f9982c9c6f4caa6cc2ce90e57df8d0c26cb5c8e8e839f6361208fc8038882ed2914857585e76a72cde36ad6d144395eac688fb5fa8d46338df9639fb8bf86e20b39054a94981306408326161382d14e5bae5d641c44883cf13f22d9ccf1f0c06577c383f8dd230208a2920f59fe926f694a3790c62d647f4b4a0f609962a5caa015661549f2a6b4a9ed1d3ad0f5dd3a7877ce78f1d85ae4d97ca2e153e13d443cc4c5a06b6111ff989b25dea29eb85093623507f342c89d212aa72c4e5839fdfde5c5d905299c8ade53b816e382cb73aceec12af81154d64ca0cbcc3c98c317395dd726aafa975e69e700106a1b42b20f7ea77fb881980d19f6b2bee678e551736d1667726420f89fa5a3e3d28ee29414e3b25b83011b127928dc4ba49e003da2e2e5b4f8c01d002d229f48d309bda4b53ec8c0ae155df5f91c11ad3a3a2c6a0217f9a47feef49411fcbd0228e5593d60185701e0c377e5c47958d52b0f706b9be26998bffae5199cda51af5ad7fa79bf46dcd8fbb1f135827f791b547d870014ca69f5bfb5b0a73180d75c6d9f13603e4506a174a8607fe85477760c904099d7d4696716aa9bb1c8744a18fb1ae37210349a811423b1165afc28b500d1095e16a1594364c012f5f6cc3bd9f64a64187b01bcda4875ae7646540548a465c2b56caf38d98ce6a5d0f75b3c074fb2248e01cae9eb3e78dbc01302054c738d0be6a7ed37761b337c0343b453e06c9700dee8fc00a705e4a747e1a5d46588c8bace9c68eb3832f0600e46f54e85a4a3a44ea0c29c69b5c5d6b6491f0a3f0bdbd123bafe3f3dd987fcc52e30c5c6cf1e9f02f998ea2791dc72cc75dac6033198c38cec44671465120ec946145b7171a63234b531e54253f92ed2c115cfe700d35e103741744d5c29f5e466109e7aba25fb9bcc38c472ae17108e3027b68d97b8d1d90c880d92a919cbce9881d6905a33f6ce5421c570a57f056ba70966e6472f49cd3d4f48c3261e0b7ae75cb34394d692ff2b80e0d596123811bbabccf90991b5b2dc17623a0f547478fef1a1cc2df258785141e7153030d8afb58c1e214632124436cbab0c21996b5dc27704635a4b27531cfddeeadcf90fd57c681bc2b0527ffd0106692d57f36af689ea77b06bc4030fad5cdf7e60e1f03d168bd3ff798f55a629f65b8fe731fc872ad44f58176d46442e5e3afcdb69302ad58802b5ed684d3e6365a77d7e931fc691b6e7d6c63897ba5c70e6e94eb7db177a19e6d97905769fd2a40ce8ef94dc14eeced2b8dc90dd423b8255f5e926662387a52c628af72e760b94a55ea5eccc41865c503e738047d6351a4ab17b2d5139a29c830f37ba364830ecd5c47d987ae1be041b7ad0d29fa769e78266b51f49fe738d132ec7bd9c005be3b8caae434d11078cb9483ede152664954dedf3ca5aa508fdc4ab00120bfac8191851cf335a6197fb33b0dd17de0abfb2a045cf85f4a0dfcfb10846b1c2e10cb776727e27c5987a8
// System.out.println(generateKey());
}
}