1 版本概述
原来项目中使用的是Bouncycastle1.46版本的,后由于项目需要,改成了1.60版本。本文基于1.60版本实现加密解密、本地存储、签名验签功能。本文代码已上线稳定运行,现整理干货如下。首先在项目中添加如下依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.60</version>
</dependency>
2 代码实现
编写加解密工具类,直接贴代码了(包含测试代码),略显粗糙,读者可优化该工具类GmUtil,详见生成密钥:generateKeyPair、加密:sm2Encrypt、解密sm2Decrypt等方法:3 密钥存储实现
若需要存储密钥,则上述生成的KeyPair对象无法存在特定的文件或数据库中,我们需要将其转化成字符串型的数据,方式如下:
/*
*
*KeyPair密钥转String型密钥
*/
public static List<String> getStringKey(KeyPair keyPair){
// 公钥转换
PublicKey publicKey = keyPair.getPublic();
BCECPublicKey localECPublicKEy = (BCECPublicKey)publicKey;
ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKEy.getQ(),ecDomainParameters);
byte[] publicKeyByte = ecPublicKeyParameters.getQ().getEncoded(false);
String publicKeyStr = TransferUtil.byteToHex(publicKeyByte);
PrivateKey privateKey = keyPair.getPrivate();
BCECPrivateKey bcecPrivateKey = (BCECPrivateKey)privateKey;
BigInteger privateKeyBI = bcecPrivateKey.getD();
byte[] privateKeyByte = TransferUtil.biConvert32Bytes(privateKeyBI);
String privateKeyStr = TransferUtil.byteToHex(privateKeyByte);
System.out.println("公钥: "+publicKeyStr);
System.out.println("私钥: "+privateKeyStr);
List<String> keyPairList = new ArrayList<>(2);
// 公私钥字符串存入list
byte[] temp = TransferUtil.hexToByte(privateKeyStr);
keyPairList.add(publicKeyStr);
keyPairList.add(privateKeyStr);
return keyPairList;
}
/*
*
*用String型公钥加密
*/
private static String encrypt(String data,String pubKey){
//构造ECPoint
ECPoint ecPoint = SM2Util.CURVE.decodePoint(TransferUtil.hexStringToBytes(pubKey));
ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(ecPoint,GmUtil.ecDomainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(true,new ParametersWithRandom(ecPublicKeyParameters,new SecureRandom()));
byte[] byteResult;
try{
byte[] byteData = data.getBytes();
byte[] temp = sm2Engine.processBlock(byteData,0,byteData.length);
byteResult = changeC1C2C3ToC1C3C2(temp);
}catch (InvalidCipherTextException e){
throw new RuntimeException(e);
}
return Hex.toHexString(byteResult);
}
/*
*
*用String私钥解密
*/
private static String decrypt(String encryptedData,String privateKey){
byte[] priKeyByte = TransferUtil.hexToByte(privateKey);
ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(new BigInteger(1,priKeyByte),ecDomainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false,ecPrivateKeyParameters);
byte[] result = null;
try{
byte[] encryptDataByte = TransferUtil.hexToByte(encryptedData);
byte[] temp = changeC1C3C2ToC1C2C3(encryptDataByte);
result = sm2Engine.processBlock(temp,0,temp.length);
}catch (Exception e){
e.printStackTrace();
}
return new String(result);
}
4 测试加解密:
//生成公私钥
KeyPair kp = generateKeyPair();
Lisy<String> keys = getStringKey(kp);
//加解密测试
String pub = "0471569510119CB9182D757942A36A61F052E155FCB795956445D33ACBA8972F0CAF47DDE468D48D7080640244C1BBC46199AFB88C974F6020B590B3DA5C1FBA00";
String pri = "8D704AE2D67CBF865224ADA883FE9F32D6CAFDEEC9A7E9D9999010856F71C2FB";
String temp = encrypt("hello world!",pub);
System.out.println("加密后的数据: "+temp);
System.out.println("解密出的数据: "+decrypt(temp,pri));