SM2加密解密工具
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
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 java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* SM2加密工具
*
* @author zj
* @since 2023-11-21
*/
public class SM2Util {
/**
* SM2默认曲线
*/
public static final String SM2_DEFAULT_CURVE = "sm2p256v1";
/**
* 锁
*/
protected static final Lock lock = new ReentrantLock();
/**
* 全局单例的 org.bouncycastle.jce.provider.BouncyCastleProvider 对象
*/
public static final Provider PROVIDER;
private static final SM2Engine ENGINE;
private static final Digest DIGEST = new SM3Digest();
static {
PROVIDER = new BouncyCastleProvider();
Security.addProvider(PROVIDER);
ENGINE = new SM2Engine(DIGEST, SM2Engine.Mode.C1C3C2);
}
public static void main(String[] args) {
KeyPair keyPair = SM2Util.generateKeyPairForSM2();
String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
System.out.println("privateKey====="+privateKey);
System.out.println("publicKey====="+publicKey);
// 业务报文加密
String text = "{\"m_head\":{\"srvid\":\"TPChannelLogin\",\"req_time\":\"20231215160300\",\"req_seq\":\"69048390\",\"channel_id\":\"otherchannel\",\"channel_pwd\":\"019651970372c85bcff74ce0d3ac0352\",\"sessionid\":\"E2BCR9HLK9VDN12G7SU8SK0PR9BNCCZM\",\"usessionid\":\"DIHSCVEQYNNRKBW1Z1KDORW0HRE618IN\",\"version\":\"v1.0\",\"sign\":\"825c31fa21dc725528bafdbd8eaeab15\"},\"m_body\":{\"checknum\":\"230882\",\"password\":\"240822\",\"channel_id\":\"otherchannel\"}}";
// String privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgFH7DGMzfPhZIAHY7QKVeCkXGUYeHLkfosmnPKcOCStqgCgYIKoEcz1UBgi2hRANCAARkNRN4b237bLm9QhNytpytZCjx5buP9VfzvwUXleO6qUcKhL9UWhVDrG1odeyNLgqXmQIqbUxl8n6iHSnVTAJ7";
// String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEZDUTeG9t+2y5vUITcracrWQo8eW7j/VX878FF5XjuqlHCoS/VFoVQ6xtaHXsjS4Kl5kCKm1MZfJ+oh0p1UwCew==";
String encrypt = encrypt(text, publicKey);
System.out.println();
System.out.println("加密数据======="+encrypt);
System.out.println();
// System.out.println("解密数据======="+decrypt(
// "BLEi5Zn3lYbRSAAh+1ChM+lQOaNKPjrBLA30UbEiWJiqtWbCi5uQZ3J7S6XhlbmfEBqpaOX3UA/bDHEsobWJih7eiJu2jn8RecwB3l392gWjkKdbF97VqArHwQLUb1I0cPCspBOT4mHkNM/Vq/l1knn7/A/jI43XW1G1arkOC54AiJoC74EdeKe2LWUL60ohkHKv7IbIthzYp+p5WCTL/Vnpd/GBXRLdBU1Gve5zWcIYfhOeath2A+jKib8NqSpIqPaCJz2iTSbrMqybCFMJ/31np9PH0YZF53Xlbi9X1zqvf2gM3fDrL9abWiesIfGPaJ4AJowJZYDVpMc5XyX3BnIxGZV32e38cgMhFrMumJk6WnXEKEP6Y/HbcgKUtA8RTt6DN+3RRpr857YSporWBdhUHCKsR1BZW5bEMmPtFBW+CRch41s9HqtRCRQT9QsJUANqg/lQuiRDhoIVI0Gv58n3MScOSYdioSaU87iFaRpbFIRix7gzsPsHkg+ZAx4ZsiBTC7Dsy2mLR5G+2JsAvnesgdUNvuqMr6RVXXmcs8rW7ZUGsrbCcKP+1PyK3FKQBGjNGnRt16v0lDNb6URPKv1ZU6+i6KA+UGht06MepivQkXVWcbFKzLy7MKmemyiaUnTwLVl3nVza+RyZWSxaC8ONtgiUwdmScfvN6BfPSXsBaVzxVJFbKRX4q9o/S2kJqhz9qtcDypivaFR3mmnHzS2Uhsjm6LC92CgtE3On2bUwtpLHwQL32JIwjufbHVjMZ3z8ir7+mbFSR11Hcte5Cp6OCu+UW2HbLFmQjHs5QQ2lYDcKzXZ2gaJsP/Vf5cKi9wjj0pvOZljukV0zxk5NcvbfGh5h7ji8HGsueio3qDCV8EecsNzBH+sm8rq6oth+7uJS9Qxa22dtshc=",
// privateKey));
System.out.println("解密数据======="+decrypt(encrypt, privateKey));
}
/**
* 解密
*
* @param encryptData SM2密文
* @param privateKey 私钥参数
* @return 加密后的bytes
*/
public static String decrypt(String encryptData, String privateKey) {
ECPrivateKeyParameters privateKeyParameters = generatePrivateKey(Base64.getDecoder().decode(privateKey));
byte[] data = Base64.getDecoder().decode(encryptData);
lock.lock();
try {
DIGEST.reset();
ENGINE.init(false, privateKeyParameters);
return new String(ENGINE.processBlock(data, 0, data.length), StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
/**
* 加密,SM2非对称加密的结果由C1,C2,C3三部分组成,其中:
*
* <pre>
* C1 生成随机数的计算出的椭圆曲线点
* C2 密文数据
* C3 SM3的摘要值
* </pre>
*
* @param data 被加密的str
* @param publicKey 公钥参数
* @return 加密后的字符串
*/
public static String encrypt(String data, String publicKey) {
ECPublicKeyParameters pubKeyParameters = generatePublicKey(Base64.getDecoder().decode(publicKey));
lock.lock();
byte[] bytes;
try {
DIGEST.reset();
ENGINE.init(true, new ParametersWithRandom(pubKeyParameters));
byte[] preBytes = data.getBytes(StandardCharsets.UTF_8);
bytes = ENGINE.processBlock(preBytes, 0, preBytes.length);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
return Base64.getEncoder().encodeToString(bytes);
}
/**
* 生成用于非对称加密的公钥和私钥
*
* @return {@link KeyPair}
*/
public static KeyPair generateKeyPairForSM2() {
// SM2算法需要单独定义其曲线生成
final ECGenParameterSpec sm2p256v1 = new ECGenParameterSpec(SM2_DEFAULT_CURVE);
return generateKeyPair("EC", 256, new SecureRandom(), sm2p256v1);
}
/**
* 生成用于非对称加密的公钥和私钥
*
* @param algorithm 算法
* @param keySize 密钥模(modulus )长度(单位bit)
* @param random {@link SecureRandom} 对象,创建时可选传入seed
* @param params {@link AlgorithmParameterSpec}
* @return {@link KeyPair}
*/
public static KeyPair generateKeyPair(String algorithm, int keySize, SecureRandom random,
AlgorithmParameterSpec... params) {
final KeyPairGenerator keyPairGen;
try {
keyPairGen = KeyPairGenerator.getInstance(algorithm, PROVIDER);//
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
// 密钥模(modulus )长度初始化定义
if (keySize > 0) {
if (null != random) {
keyPairGen.initialize(keySize, random);
} else {
keyPairGen.initialize(keySize);
}
}
// 自定义初始化参数
if (params != null) {
for (AlgorithmParameterSpec param : params) {
if (null == param) {
continue;
}
try {
if (null != random) {
keyPairGen.initialize(param, random);
} else {
keyPairGen.initialize(param);
}
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
}
}
return keyPairGen.generateKeyPair();
}
/**
* 生成公钥,仅用于非对称加密<br>
* 采用X509证书规范<br>
*
* @param key 密钥,必须为DER编码存储
* @return 公钥 {@link ECPublicKeyParameters}
*/
private static ECPublicKeyParameters generatePublicKey(byte[] key) {
if (null == key) {
return null;
}
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
try {
PublicKey publicKey = KeyFactory.getInstance("EC", PROVIDER).generatePublic(x509EncodedKeySpec);
return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 生成私钥,仅用于非对称加密<br>
* 采用PKCS#8规范,此规范定义了私钥信息语法和加密私钥语法<br>
*
* @param key 密钥,PKCS#8格式
* @return 私钥 {@link PrivateKey}
*/
private static ECPrivateKeyParameters generatePrivateKey(byte[] key) {
if (null == key) {
return null;
}
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
try {
PrivateKey privateKey = KeyFactory.getInstance("EC", PROVIDER).generatePrivate(pkcs8EncodedKeySpec);
return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}