自定义接口aop,实现自动加解密

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,我们可以使用自定义注解来实现AOP(面向切面编程)。AOP是一种编程范型,它允许开发者在程序运行时动态地将代码切入到已有代码的特定位置。 下面是一个简单的示例,演示如何使用自定义注解实现AOP。 首先,我们需要定义一个自定义注解: ``` @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Loggable { } ``` 这个注解用来标记需要记录日志的方法。它的@Target注解指定了它只能用于方法上,@Retention注解指定了它的生命周期是运行时。 接下来,我们创建一个切面类,用来实现AOP的逻辑: ``` @Aspect @Component public class LoggingAspect { @Before("@annotation(com.example.Loggable)") public void logMethodCall(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("Method " + methodName + " called"); } } ``` 这个类使用Spring AOP框架提供的@Aspect注解来标记它是一个切面类。它的@Before注解指定了它要在被@Loggable注解标记的方法之前执行。JoinPoint参数包含了被拦截的方法的信息,我们可以从中获取方法名等信息。 最后,在需要记录日志的方法上加上@Loggable注解即可: ``` @Component public class MyService { @Loggable public void doSomething() { // do something } } ``` 当doSomething()方法被调用时,LoggingAspect中的logMethodCall()方法会被执行,记录方法调用信息。 这就是使用自定义注解实现AOP的基本步骤。当然,实际应用中会更加复杂,需要更多的切面逻辑和注解参数等。但是这个简单的示例可以帮助你理解如何使用自定义注解实现AOP

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值