SM2加密解密网上很多人都是bouncycastle库,但我实际使用的时候却遇到了很多坑
1、和前端SM2不适配,前端和后端能分别使用SM2加密解密,前端加密后端却无法解密
2、前端生成加密有0-C1C2C3;1-C1C3C2两种模式可选,但使用BC库却完全没有相关方法,甚至一开始我都不知道这是干什么的
3、搞清楚加密模式了,用前端生成的密钥对,放到后端去用居然还会报错
1.引入依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.57</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>1.57</version>
</dependency>
公共常量
/**sm2曲线参数名称*/
public static final String CRYPTO_NAME_SM2 = "sm2p256v1";
/**sm2-签名id*/
public static final String SIGN_ID = "1234567812345678";
前端sm加密库用sm-crypto
2.生成密钥对,此处需要注意BC库的密钥格式和标准密钥有一定差别,注意看注释
/**
* 获取sm2密钥对
* BC库使用的公钥=64个字节+1个字节(04标志位),BC库使用的私钥=32个字节
* SM2秘钥的组成部分有 私钥D 、公钥X 、 公钥Y , 他们都可以用长度为64的16进制的HEX串表示,
* <br/>SM2公钥并不是直接由X+Y表示 , 而是额外添加了一个头,当启用压缩时:公钥=有头+公钥X ,即省略了公钥Y的部分
* @param compressed 是否压缩公钥(加密解密都使用BC库才能使用压缩)
* @return
*/
public static KeyPairOfString getSm2Keys(boolean compressed){
//获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
//1.创建密钥生成器
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
//2.初始化生成器,带上随机数
try {
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
} catch (NoSuchAlgorithmException e) {
logger.error("生成公私钥对时出现异常:", e);
}
//3.生成密钥对
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters)asymmetricCipherKeyPair.getPublic();
ECPoint ecPoint = publicKeyParameters.getQ();
// 把公钥放入map中,默认压缩公钥
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
String publicKey = Hex.toHexString(ecPoint.getEncoded(compressed));
ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate();
BigInteger intPrivateKey = privateKeyParameters.getD();
// 把私钥放入map中
String privateKey = intPrivateKey.toString(16);
logger.debug("\npublicKey:{}\nprivateKey:{}", publicKey, privateKey);
return new KeyPairOfString(publicKey, privateKey);
}
/**
* 密钥对保存类,保存一对