1、创建切面
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AutoSmUtil {
}
2、实现切面功能
@Aspect
@Component
public class AutoSmUtilImpl {
@Value("${sm2.publicKey}")
String publicKey_a;
String publicKey_b="jHNE9tDymZU0BgZCX4slK7+SBOencVLnI3GvHiczb1Oy1Qb6rGoi/uL/nbJaSPfzTXA==";
@Value("${sm2.privateKey}")
String privateKey_a;
String privateKey_b="UBgi2hRANCAASv8TQMEMH7gRmS+epXm2Mc0T20PKZlTQGBkJfiyUrv5IE56dxUucjca8eJzNvU7LVBvqsaiL+4v+dslpI9/NNc";
@Around("@annotation(com.sgcc.payment.allinpay.annotation.AutoSmUtil)")
public Object autoSmUtilImpl(ProceedingJoinPoint joinPoint) throws Throwable {
//base64转密钥
byte[] publicKeyByte =SecureUtil.decode(publicKey_a+publicKey_b);
byte[] privateKeyByte = SecureUtil.decode(privateKey_a+privateKey_b);
SM2 sm2 = SmUtil.sm2(privateKeyByte, publicKeyByte);
Object[] args = joinPoint.getArgs();
// 在这里对参数进行修改
String prams1 = decrypt(sm2, JSONObject.parseObject(JSONObject.toJSONString(args[0])).getString("prams"));
// Log.info("请求",prams1);
args[0] = JSONObject.parseObject(prams1);
// 修改完成后,可以继续调用原方法并传入修改后的参数
String result = JSONObject.toJSONString(joinPoint.proceed(args));
// Log.info("响应" ,result);
//加密 先转json在转string
result = encrypt(sm2,result);
R r = new R();
r.setData(result);
r.setCode(200);
r.setMsg("成功");
return r;
}
//解密
private String decrypt(SM2 sm2,String encryptedPassword) {
byte[] decode = Base64.decode(encryptedPassword);
//密文
// System.out.println("密文:" + encryptedPassword);
//解密
String decryptStr = StrUtil.utf8Str(sm2.decrypt(decode, KeyType.PrivateKey));
// System.out.println("解密后的原文:" + decryptStr);
//sm2(sm3+原文)
//截取头部的sm3和原文校验
String sm3 = decryptStr.substring(0, 64);
String returnValue = decryptStr.substring(64);
//sm3校验
if (!sm3.equals(SmUtil.sm3(returnValue))) {
throw new RuntimeException("sm3校验失败");
}
return returnValue;
}
//加密
private String encrypt(SM2 sm2,String returnValue) {
//sm2(sm3+原文)
// System.out.println("sm3加密后的原文:"+SmUtil.sm3(returnValue)+returnValue);
return Base64.encode(sm2.encrypt(SmUtil.sm3(returnValue)+returnValue, KeyType.PublicKey));
}
public static void main(String[] args) {
//需要加密的明文
String text = "我是一段测试aaaa";
//创建sm2 对象
SM2 sm2 = SmUtil.sm2();
//这里会自动生成对应的随机秘钥对 , 注意! 这里一定要强转,才能得到对应有效的秘钥信息
byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
//这里公钥不压缩 公钥的第一个字节用于表示是否压缩 不压缩才是65的长度
byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
//原始公私秘钥
byte[] oldprivateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
byte[] oldpublicKey = BCUtil.encodeECPublicKey(sm2.getPublicKey());
System.out.println("原始私钥: " + HexUtil.encodeHexStr(oldprivateKey));
System.out.println("原始公钥: " + HexUtil.encodeHexStr(oldpublicKey));
//这里得到的 压缩后的公钥 ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(true);
// byte[] publicKeyEc = BCUtil.encodeECPublicKey(sm2.getPublicKey());
//打印当前的公私秘钥
System.out.println("变换私钥: " + HexUtil.encodeHexStr(privateKey));
System.out.println("变换公钥: " + HexUtil.encodeHexStr(publicKey));
//还原公私秘钥
//将密钥还原回sm2对象
PrivateKey privateKey1 = sm2.getPrivateKey();
PublicKey publicKey1 = sm2.getPublicKey();
SM2 huanyuan = SmUtil.sm2(privateKey1,publicKey1);
//打印还原后的公私秘钥
System.out.println("还原私钥: " + HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(huanyuan.getPrivateKey())));
System.out.println("还原公钥: " + HexUtil.encodeHexStr(BCUtil.encodeECPublicKey(huanyuan.getPublicKey())));
//sm3计算
String s1 = SmUtil.sm3(text);
//得到明文对应的字节数组
byte[] dateBytes = (s1+text).getBytes();
System.out.println("数据: " + HexUtil.encodeHexStr(dateBytes));
//sm2计算
String s = HexUtil.encodeHexStr(sm2.encrypt(dateBytes));
System.out.println("加密后: " +s);
//sm2解密
String s2 = new String(sm2.decrypt(HexUtil.decodeHex(s)));
System.out.println("解密后: " + s2);
//这里需要手动设置,sm2 对象的默认值与我们期望的不一致
sm2.setMode(SM2Engine.Mode.C1C2C3);
sm2.setEncoding(new PlainDSAEncoding());
//sm2计算签名
byte[] sign = sm2.sign(dateBytes, null);
System.out.println("签名: " + HexUtil.encodeHexStr(sign));
//sm2 校验 验签
boolean verify = sm2.verify(dateBytes, sign);
//sm3 检验
boolean verify1 = SmUtil.sm3(s2.substring(64)).equals(s2.substring(0,64));
System.out.println("Sm2验签"+verify);
System.out.println("Sm3验签"+verify1);
}
}
3、使用
直接在接口上@AutoSmUtil