1、配置文件配置属性值
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
crypto:
provider: BC
publicKey: xxxxxxxxx
privateKey: xxxxxxxxxxx
2、工具类及密钥对生成及内容加解密
package com.uc.config;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
@Component
public class SM2Utils {
public static String provider;
public static String publicKeyString;
public static String privateKeyString;
public static String getProvider() {
return provider;
}
@Value("${crypto.provider}")
public void setProvider(String provider) {
SM2Utils.provider = provider;
}
public static String getPublicKeyString() {
return publicKeyString;
}
@Value("${crypto.publicKey}")
public void setPublicKeyString(String publicKeyString) {
SM2Utils.publicKeyString = publicKeyString;
}
public static String getPrivateKeyString() {
return privateKeyString;
}
@Value("${crypto.privateKey}")
public void setPrivateKeyString(String privateKeyString) {
SM2Utils.privateKeyString = privateKeyString;
}
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 生成新的公钥、私钥
* @return
*/
public static Map<String, String> getKey() {
KeyPairGenerator keyPairGenerator = null;
try {
keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
try {
keyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();
String publicKeyString = Base64.getEncoder().encodeToString(publicKeyBytes);
String privateKeyString = Base64.getEncoder().encodeToString(privateKeyBytes);
Map<String, String> map = new HashMap<>();
map.put("publicKey", publicKeyString);
map.put("privateKey", privateKeyString);
return map;
}
/**
* 根据公钥字符串获取公钥对象
* @return
* @throws Exception
*/
public static PublicKey getPublicKeyFromString() throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
return keyFactory.generatePublic(keySpec);
}
/**
* 根据私钥字符串获取私钥对象
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKeyFromString() throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
return keyFactory.generatePrivate(keySpec);
}
/**
* 加密
* @param obj
* @return
* @throws Exception
*/
public static String encryptObject(Object obj) throws Exception {
JSONObject jsonObject = JSONUtil.parseObj(obj);
String data = jsonObject.toString();
Cipher cipher = Cipher.getInstance("SM2", provider);
cipher.init(Cipher.ENCRYPT_MODE, getPublicKeyFromString());
byte[] encryptedData = cipher.doFinal(data.getBytes());
return Hex.toHexString(encryptedData);
}
/**
* 解密
* @param encryptedText
* @param targetType
* @return
* @param <T>
* @throws Exception
*/
public static <T> T decryptObject(String encryptedText, Class<T> targetType) throws Exception {
Cipher cipher = Cipher.getInstance("SM2", provider);
cipher.init(Cipher.DECRYPT_MODE, getPrivateKeyFromString());
byte[] encryptedData = Hex.decode(encryptedText);
byte[] decryptedData = cipher.doFinal(encryptedData);
String data = new String(decryptedData);
return JSONUtil.toBean(data, targetType);
}
/**
* 私钥签名
*/
public static String signByPrivateKey(Object obj) throws Exception {
// 要加密的对象转String,再转btye[]
String dataStr = StrUtil.toString(obj);
byte[] data = dataStr.getBytes();
Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(getPrivateKeyFromString());
sig.update(data);
return Hex.toHexString(sig.sign());
}
/**
* 公钥验签
*/
public static boolean verifyByPublicKey(Object obj, String sign) throws Exception {
// 解密后的对象转String,再转btye[]
String dataStr = StrUtil.toString(obj);
byte[] data = dataStr.getBytes();
byte[] signature = Hex.decode(sign);
Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
sig.initVerify(getPublicKeyFromString());
sig.update(data);
return sig.verify(signature);
}
}
3、调用
/**
* 获取公钥、私钥
* @param query
* @return
* @throws Exception
*/
@GetMapping("/key")
public R<Map<String, String>> getKey(String query) throws Exception {
Map<String, String> key = SM2Utils.getKey();
return R.ok(key);
}
/**
* 加密
* @param test1VO
* @return
* @throws Exception
*/
@GetMapping("/encrypt")
public R<Map<String, String>> encrypt(Test1VO test1VO) throws Exception {
String s = SM2Utils.encryptObject(test1VO);
String s1 = SM2Utils.signByPrivateKey(test1VO);
Map<String, String> map = new HashMap<>();
map.put("encrypt", s);
map.put("sign", s1);
return R.ok(map);
}
/**
* 解密
* @param query
* @param sign
* @return
* @throws Exception
*/
@GetMapping("/decrypt")
public R<Test1VO> decrypt(String query, String sign) throws Exception {
Test1VO test2VO = SM2Utils.decryptObject(query, Test1VO.class);
boolean verify = SM2Utils.verifyByPublicKey(test2VO, sign);
if (!verify) {
throw new Exception("验签失败");
}
return R.ok(test2VO);
}