描述
使用sm2加密key,使用sm4加密内容,实现混合加密,sm2为类似RSA的非对称加密,sm4为类似AES的对称加密,混合加密的好处为提高效率和安全的均衡性
代码
package org.example.test;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SM2MixedSM4 {
static {
Security.addProvider(new BouncyCastleProvider()); // 注册BouncyCastle
}
public static SecretKey generateSM4Key() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4", "BC"); // 指定算法和提供商
keyGenerator.init(128); // SM4密钥长度固定128位
return keyGenerator.generateKey();
}
public static String secretKeyStr() throws NoSuchAlgorithmException, NoSuchProviderException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4", "BC"); // 指定算法和提供商
keyGenerator.init(128); // SM4密钥长度固定128位
byte[] encoded = keyGenerator.generateKey().getEncoded();
return Base64.getEncoder().encodeToString(encoded);
}
public static byte[] sm4Encrypt(byte[] plaintext, SecretKey key) throws Exception {
// 生成随机IV(16字节)
byte[] iv = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// 初始化加密器
Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
// 加密数据(最终密文 = IV + 加密内容)
byte[] ciphertext = cipher.doFinal(plaintext);
return concatenateArrays(iv, ciphertext); // 将IV与密文拼接
}
// 工具方法:拼接两个字节数组
private static byte[] concatenateArrays(byte[] a, byte[] b) {
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
public static byte[] sm4Decrypt(byte[] ciphertextWithIv, SecretKey key) throws Exception {
// 分离IV和密文(前16字节是IV)
byte[] iv = new byte[16];
byte[] ciphertext = new byte[ciphertextWithIv.length - 16];
System.arraycopy(ciphertextWithIv, 0, iv, 0, 16);
System.arraycopy(ciphertextWithIv, 16, ciphertext, 0, ciphertext.length);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// 初始化解密器
Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
// 解密数据
return cipher.doFinal(ciphertext);
}
public static void main(String[] args) throws Exception {
// // 初始化密钥生成器
// KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC");
// ECGenParameterSpec ecSpec = new ECGenParameterSpec("sm2p256v1");
// generator.initialize(ecSpec, new SecureRandom());
// KeyPair keyPair = generator.generateKeyPair();
//
// // 提取公钥和私钥
// PublicKey publicKey = keyPair.getPublic();
// PrivateKey privateKey = keyPair.getPrivate();
//
// System.out.println(Base64.toBase64String(publicKey.getEncoded()));
//
// System.out.println(Base64.toBase64String(privateKey.getEncoded()));
String publicStr = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAExDwKGxieYLPOHa4M8lwKKjY5YW+oK07w/YhE6fZmJtFeyRgz/DywukVWirCfmFT0axnU3741a6vt2uqLIAe9ZA==";
String privateStr = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQggFR8H5ZGWwuCmndzuv2OtHtMuK0UnZOiMqFVgorP1yGgCgYIKoEcz1UBgi2hRANCAATEPAobGJ5gs84drgzyXAoqNjlhb6grTvD9iETp9mYm0V7JGDP8PLC6RVaKsJ+YVPRrGdTfvjVrq+3a6osgB71k";
SecretKey secretKey = generateSM4Key();
String keyContent = Base64.getEncoder().encodeToString(secretKey.getEncoded());
byte[] decodePublicStr = org.bouncycastle.util.encoders.Base64.decode(publicStr);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decodePublicStr);
KeyFactory instance = KeyFactory.getInstance("EC", "BC");
PublicKey publicKey = instance.generatePublic(x509EncodedKeySpec);
// 转换公钥为BC格式参数
ECPublicKeyParameters pubKeyParams = (ECPublicKeyParameters)
ECUtil.generatePublicKeyParameter(publicKey);
// 初始化加密引擎(C1C3C2模式)
SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
engine.init(true, new ParametersWithRandom(pubKeyParams, new SecureRandom()));
// 加密key
byte[] plaintext = keyContent.getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = engine.processBlock(plaintext, 0, plaintext.length);
// 加密数据
String content = "你好,sim !";
byte[] contentBytes = sm4Encrypt(content.getBytes("UTF-8"), secretKey);
// 拼接key+ 数据
byte[] bytes = concatenateArrays(ciphertext, contentBytes);
String dataToTransfer = Base64.getEncoder().encodeToString(bytes);
System.out.println(dataToTransfer);
// 解密
byte[] decode = Base64.getDecoder().decode(dataToTransfer);
int keySize = 121;
byte[] encryptedKey = new byte[keySize];
byte[] encryptedDataBytes = new byte[decode.length - keySize];
System.arraycopy(decode, 0, encryptedKey, 0, keySize);
System.arraycopy(decode, keySize, encryptedDataBytes, 0, encryptedDataBytes.length);
byte[] decodePrivateStr = org.bouncycastle.util.encoders.Base64.decode(privateStr);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decodePrivateStr);
KeyFactory instance1 = KeyFactory.getInstance("EC", "BC");
PrivateKey privateKey = instance1.generatePrivate(pkcs8EncodedKeySpec);
// 转换私钥为BC格式参数
ECPrivateKeyParameters priKeyParams = (ECPrivateKeyParameters)
ECUtil.generatePrivateKeyParameter(privateKey);
// 初始化解密引擎(需与加密模式一致)
SM2Engine engine2 = new SM2Engine(SM2Engine.Mode.C1C3C2);
// 初始化解密引擎(需与加密模式一致)
engine2.init(false, priKeyParams);
// 解密key
byte[] decrypted = engine2.processBlock(encryptedKey, 0, encryptedKey.length);
byte[] decode1 = Base64.getDecoder().decode(new String(decrypted, StandardCharsets.UTF_8));
SecretKeySpec key = new SecretKeySpec(decode1,"SM4");
// 解密数据
byte[] decryptedData = sm4Decrypt(encryptedDataBytes, key);
String result = new String(decryptedData, "UTF-8");
System.out.println(result);
}
}