212 lines
14 KiB
Java
212 lines
14 KiB
Java
|
|
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());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|