Java实现常用加密算法-SM4
参考博客:https://blog.csdn.net/m0_46713218/article/details/143099878
参考博客:sm4前后端加密集成
pom:
<!-- SM4加密依赖包 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
SM4加解密工具类:
package com.test.encrypt;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
/**
* @description com.test.encrypt
* @author: chengyu
* @date: 2024-11-11 19:34
*/
public class EncryptUtils {
/**
* 指定加密算法
*/
private static final String ALGORITHM_NAME = "SM4";
/**
* BC中SM4默认使用ECB模式和PKCS5Padding填充方式
*/
private static final String ALGORITHM_ECB_PKCS5PADDING = "SM4/ECB/PKCS5Padding";
/**
* SM4算法目前只支持128位(即密钥16字节)
*/
private static final int DEFAULT_KEY_SIZE = 128;
static {
// 防止内存中出现多次BouncyCastleProvider的实例
if (null == Security.getProvider(BouncyCastleProvider.PROVIDER_NAME)) {
Security.addProvider(new BouncyCastleProvider());
}
}
/**
* 生成密钥
* <p>建议使用org.bouncycastle.util.encoders.Hex将二进制转成HEX字符串</p>
*
* @return 密钥16位
* @throws Exception 生成密钥异常
*/
public static String generateKey() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
kg.init(DEFAULT_KEY_SIZE, new SecureRandom());
return Hex.toHexString(kg.generateKey().getEncoded());
}
/**
* SM4对称加解密 加密
*
* @param plainString 待加密的字符串
* @param key 密钥
* @return 密文
*/
public static String sm4Encrypt(String plainString, String key) {
String cipherString = null;
try {
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToBytes(key), ALGORITHM_NAME);
// 获取Cipher对象实例
Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME);
// 初始化Cipher为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(plainString.getBytes(StandardCharsets.UTF_8));
// 输出为Base64编码
cipherString = Base64.getEncoder().encodeToString(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return cipherString;
}
/**
* SM4对称加解密 解密
* @param cipherString 密文
* @param key 密钥
* @return 明文
*/
public static String sm4Decrypt(String cipherString, String key) {
String plainString = null;
try {
// 创建密钥规范
SecretKeySpec secretKeySpec = new SecretKeySpec(hexStringToBytes(key), ALGORITHM_NAME);
// 获取Cipher对象实例
Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME);
// 初始化Cipher为解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 获取加密byte数组
byte[] cipherBytes = cipher.doFinal(Base64.getDecoder().decode(cipherString));
// 输出为字符串
plainString = new String(cipherBytes);
} catch (Exception e) {
e.printStackTrace();
}
return plainString;
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString != null && !hexString.equals("")) {
hexString = hexString.toUpperCase();
if (hexString.length() % 2 != 0) {
hexString = "0" + hexString;
}
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for(int i = 0; i < length; ++i) {
int pos = i * 2;
d[i] = (byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
} else {
return null;
}
}
private static byte charToByte(char c) {
return (byte)"0123456789ABCDEF".indexOf(c);
}
}
测试类:
package com.test.encrypt;
import java.util.Locale;
/**
* @description com.test.encrypt
* @author: chengyu
* @date: 2024-11-11 19:32
*/
public class TestSm4 {
/**
* 默认国密sm4 key值,128bit=32位16进制字符串
*/
public static final String SM4_HEX_KEY_NJTK = "A7C9D1A8D93E6CFD7A175D1505598B1E";
public static void main(String[] args) throws Exception {
String key = EncryptUtils.generateKey().toUpperCase();
System.out.println("生成的密钥key: " + key);
String data = "P1sw@d4Dw";
String encrypt = EncryptUtils.sm4Encrypt(data, SM4_HEX_KEY_NJTK);
System.out.println("使用SM4开源包加密后:" + encrypt);
String decrypt = EncryptUtils.sm4Decrypt(encrypt, SM4_HEX_KEY_NJTK);
System.out.println("使用SM4开源包解密后:" + decrypt);
String decrypt2 = AlgUtil.decryptBySm4(SM4_HEX_KEY_NJTK, encrypt);
System.out.println("使用SM4 KL包解密后:" + decrypt2);
}
}
--