背景
- 先对内容进行签名,保证数据完整性(sm3杂凑之后再使用sm2签名)
- 再对内容进行加密,保证数据传输过程中的安全(sm4加解密)
- 再从加密内容进行解密,再签名,并于之前的签名进行比较,一致表示内容没有被修改
java实现
- bouncycastle 这个库已经对sm2、sm3、sm4算法进行了全面支持,所以我们也就不造轮子,直接引入到我们工程里面
<!--国密依赖包-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.57</version>
</dependency>
- 对于每次操作或请求,我们不可能都随机生成一个密钥,我们要固定一个密钥,后端解析只需要拿到我们这个固定的密钥就可以去解析内容呢。
//产生对称秘钥
public static byte[] generateSM4Key() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("SM4", new BouncyCastleProvider());
kg.init(new SecureRandom());
return kg.generateKey().getEncoded();
}
- 记住生成的byte[]数组,我使用了BASE64编码了下
private static final String PRIVATE_KEY = "v2lBTzHwze0+SL+HtpnsGg==";
private void initSM4() throws Exception {
SM4_KEY = new SecretKeySpec(new BASE64Decoder().decodeBuffer(PRIVATE_KEY), "SM4");
cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding", new BouncyCastleProvider());
}
@SneakyThrows
private byte[] softDecrypt(byte[] apiInfo) {
cipher.init(Cipher.DECRYPT_MODE, SM4_KEY);
return cipher.doFinal(apiInfo);
}
@SneakyThrows
private byte[] softEncrypt(String apiInfo) {
cipher.init(Cipher.ENCRYPT_MODE, SM4_KEY);
return cipher.doFinal(apiInfo.getBytes());
}
- sm2密钥生成
这个相对来说复杂点,需要自己重新计算,等我找到更好的办法后,再来更新。
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
SecureRandom secureRandom = new SecureRandom();
keyPairGenerator.initialize(sm2Spec, secureRandom);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 密钥存储
// 私钥 D
BigInteger D = ((BCECPrivateKey) privateKey).getD();
// 公钥 X
BigInteger ecPointX = ((BCECPublicKey) publicKey).getQ().getX().toBigInteger();
// 公钥 Y
BigInteger ecPointY = ((BCECPublicKey) publicKey).getQ().getY().toBigInteger();
X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(PRIVATE_D, ecParameterSpec);
BCECPrivateKey privateKey = new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
return privateKey;
X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECParameterSpec ecParameterSpec = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
ECCurve curve = ecParameterSpec.getCurve();
ECPoint point = curve.createPoint(PUBLIC_X, PUBLIC_Y);
ECParameterSpec ecps = new ECParameterSpec(curve, ecParameterSpec.getG(), ecParameterSpec.getN());
ECPublicKeySpec keySpec = new ECPublicKeySpec(point, ecps);
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
PublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
return publicKey;
@SneakyThrows
private boolean softVerifySign(byte[] apiInfo, byte[] signValue) {
signature.initVerify(SIGN_PUBLIC_KEY);
signature.update(apiInfo);
return signature.verify(signValue);
}
@SneakyThrows
private byte[] softSign(byte[] apiInfo) {
signature.initSign(SIGN_PRIVATE_KEY);
signature.update(apiInfo);
return signature.sign();
}
private byte[] softSM3Digest(byte[] apiInfo) {
byte[] md = new byte[32];
SM3Digest sm3 = new SM3Digest();
sm3.update(apiInfo, 0, apiInfo.length);
sm3.doFinal(md, 0);
return md;
}
- 上述只是粗糙介绍了下,等我码云代码上传或者加q交流 1660426556