/**
* (分组密码算法)国密对称加密算法
*/
@Slf4j
public abstract class SM4Util {
static {
Security.addProvider(new BouncyCastleProvider());
}
private static final Charset ENCODING = StandardCharsets.UTF_8;
public static final String ALGORITHM_NAME = "SM4";
// 加密算法/分组加密模式/分组填充方式
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";
// 128-32位16进制;256-64位16进制
public static final int DEFAULT_KEY_SIZE = 128;
public static final String DEFAULT_KEY = "86C63180C2806ED1F47B859DE501215B";
public static final String DEFAULT_IV = "8F5CB6272B594B53AD1A2197361378DC";
private static Cipher generateCipherECB(String algorithmName, int mode, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
cipher.init(mode, new SecretKeySpec(key, ALGORITHM_NAME));
return cipher;
}
private static Cipher generateCipherCBC(String algorithmName, int mode, byte[] key, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
cipher.init(mode, new SecretKeySpec(key, ALGORITHM_NAME), new IvParameterSpec(iv));
return cipher;
}
public static String generateKey() {
try {
return HexUtil.byteToHex(generateKey(DEFAULT_KEY_SIZE));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
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();
}
protected static byte[] encryptECBPadding(byte[] data, byte[] key) throws Exception {
Cipher cipher = generateCipherECB(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
protected static byte[] decryptECBPadding(byte[] encrypted, byte[] key) throws Exception {
Cipher cipher = generateCipherECB(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
return cipher.doFinal(encrypted);
}
protected static byte[] encryptCBCPadding(byte[] data, byte[] key, byte[] iv) throws Exception {
Cipher cipher = generateCipherCBC(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv);
return cipher.doFinal(data);
}
protected static byte[] decryptCBCPadding(byte[] encrypted, byte[] key, byte[] iv) throws Exception {
Cipher cipher = generateCipherCBC(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv);
return cipher.doFinal(encrypted);
}
public static String encrypt(String source) {
return encrypt(source, DEFAULT_KEY);
}
public static String encrypt(byte[] source) {
return encrypt(source, DEFAULT_KEY);
}
public static String encrypt(String source, String hexKey) {
return encrypt(source.getBytes(ENCODING), hexKey);
}
public static String encrypt(byte[] source, String hexKey) {
byte[] cipherArray;
try {
cipherArray = encryptECBPadding(source, ByteUtils.fromHexString(hexKey));
return ByteUtils.toHexString(cipherArray);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
public static byte[] decrypt(String encrypted) {
return decrypt(encrypted, DEFAULT_KEY);
}
public static String decryptToString(String encrypted) {
return decryptToString(encrypted, DEFAULT_KEY);
}
public static String decryptToString(String encrypted, String hexKey) {
return new String(decrypt(encrypted, hexKey), ENCODING);
}
public static byte[] decrypt(String encrypted, String hexKey) {
try {
return decryptECBPadding(ByteUtils.fromHexString(encrypted), ByteUtils.fromHexString(hexKey));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return encrypted.getBytes(StandardCharsets.UTF_8);
}
public static String encrypt(String source, String hexKey, String iv) {
return encrypt(source.getBytes(ENCODING), hexKey, iv);
}
public static String encrypt(byte[] source, String hexKey, String iv) {
byte[] cipherArray;
try {
cipherArray = encryptCBCPadding(
source
, ByteUtils.fromHexString(hexKey)
, ByteUtils.fromHexString(iv));
return ByteUtils.toHexString(cipherArray);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("数据加密失败", e);
}
}
public static String decryptToString(String encrypted, String hexKey, String iv) {
return new String(decrypt(encrypted, hexKey, iv), ENCODING);
}
public static byte[] decrypt(String encrypted, String hexKey, String iv) {
try {
if (StringUtils.isBlank(encrypted)) {
return new byte[] {};
}
return decryptCBCPadding(
ByteUtils.fromHexString(encrypted)
, ByteUtils.fromHexString(hexKey)
, ByteUtils.fromHexString(iv));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return encrypted.getBytes(StandardCharsets.UTF_8);
}
}