• RS256 DSA 算法之一 java具体使用 非对称加密算法 总结心得


    1.背景

    有个需求 需要在java 使用 非对称加密 RS256 算法,网上博客都翻篇了,基本都是赋值粘贴,没有个是可用的,80%都是粘贴了一篇 c#语言写的代码,

    什么风气?以前的博客氛围哪里去了?不开心,我要的是 java ,java ,java !

    经过两天测试,终于琢磨透了,但是与网上的介绍却有点出入,

    网上的解说是:
    说法一:RS256 是公钥加密,私钥解密;
    说法二:RS256 是私钥加密。公钥解密,因此只需要保存好私钥即可

    可是我的实验结果都推翻了上面的说明,我的结论是

    私钥加密得到签名密钥,公钥用来对签名密钥和原始数据做校验是否被篡改过,以达到中途防止被抓包的风险,那么公私钥都不可泄露

    经查找大量资料知道,这个是DSA非对称算法,全称是 Digital Signature Algorithm,该数字签名算法是 Schnorr 和 ElGamal 签名算法的变种,基于模算数和离散对数的复杂度
    网上的解说是RSA算法,对于内容,公钥加密后,只有私钥才可以解密,私钥加密后,只有公钥才可以解密,

    DSA和RSA的使用各有利弊
    (1)DSA 算法只适用于纯后端的加密解密签名传输,作为校验没有被篡改内容
    (2)RSA 算法不仅仅可以用于后端,还可以用作为前端跨服务器的令牌校验,特别是跨域微服务
    
    

    2.心得总结

    这是私钥加密,公钥验证,发送方保存私钥,接收方保存公钥;
    发送方使用私钥加密原始数据后,将得出签名密钥,于是将签名密钥和原始数据一起传给接收方;
    接收方得到签名密钥和原始数据后,使用公钥对签名密钥和原始数据做校验是否一致,以确保数据传输过程中没有被抓包,
    即便别人得到了传输数据,因为没有私钥,因此无法获取新的密钥签名,密钥签名和原始数据必须一致,因此达到数据无法伪造的效果
    类似于https,https是传输中途所有数据乱码加密,到达服务器根据协议解密,而RS256非对称加密是中途不加密,只在发送方根据私钥 对发送的原始数据计算出一个签名密钥,然后与原始数据一起传输到接收方,中途数据是明文的,到达接收方使用公钥验证数据是否被篡改过,检验通过才处理, 当然可以配置https协议一起使用,双重保险

    依赖只需要引入jdk 的rt.jar即可,是jdk的基础依赖包

    3.完整的java代码

    package cn.cenxi.appapi.goods.controller;
    
    import java.security.*;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    
    /**
     * 这是私钥加密,公钥验证,发送方保存私钥,接收方保存公钥;
     * 发送方使用私钥加密原始数据后,将得出签名密钥,于是将签名密钥和原始数据一起传给接收方;
     * 接收方得到签名密钥和原始数据后,使用公钥对签名密钥和原始数据做校验是否一致,以确保数据传输过程中没有被抓包,
     * 即便别人得到了传输数据,因为没有私钥,因此无法获取新的密钥签名,密钥签名和原始数据必须一致,因此达到数据无法伪造的效果
     * <p>
     * 类似于https,https是传输中途所有数据乱码加密,到达服务器根据协议解密,而RS256非对称加密是中途不加密,只在发送方根据私钥
     * 对发送的原始数据计算出一个签名密钥,然后与原始数据一起传输到接收方,中途数据是明文的,到达接收方使用公钥验证数据是否被篡改过,检验通过才处理,
     * 当然可以配置https协议一起使用,双重保险
     */
    
    public class mk {
    
        //实例密钥对生成器的加密算法键名【非对称加密】
        private static final String KEY_ALGORITHM = "RSA";
        //密钥长度
        private static final int KEY_SIZE = 1024;
    
        //实例签名工厂的算法键名【非对称加密】
        public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    
        //公钥key名
        private static final String PUBLIC_KEY = "publicKey";
        //私钥key名
        private static final String PRIVATE_KEY = "privateKey";
    
    
        /**
         * 生成公、私钥
         * 根据需要返回String或byte[]类型
         */
        private static Map<String, String> createRSAKeys() throws NoSuchAlgorithmException {
            //密钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            //初始化配置,参数:密钥长度,安全随机数
            keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());
            //生产公钥私钥键值对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            //获取公钥
            PublicKey publicKey = keyPair.getPublic();
            //获取私钥
            PrivateKey privateKey = keyPair.getPrivate();
            //将公钥转为字符串【方便存储】
            String publicKeyValue = Base64.getEncoder().encodeToString(publicKey.getEncoded());
            //将私钥转为字符串【方便存储】
            String privateKeyValue = Base64.getEncoder().encodeToString(privateKey.getEncoded());
            //存入map返回
            Map<String, String> map = new HashMap<>();
            map.put(PUBLIC_KEY, publicKeyValue);
            map.put(PRIVATE_KEY, privateKeyValue);
            return map;
        }
    
        /**
         * 将公钥字符串恢复为公钥对象
         */
        public static PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
            byte[] byteKey = Base64.getDecoder().decode(key);
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(byteKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            return keyFactory.generatePublic(x509EncodedKeySpec);
        }
    
        /**
         * 将私钥字符串恢复为私钥对象
         */
        public static PrivateKey getPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
            byte[] byteKey = Base64.getDecoder().decode(key);
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(byteKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        }
    
    
        /**
         * 签名
         *
         * @param key         私钥字符串
         * @param requestData 原始数据
         */
        public static String sign(String key, String requestData) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
            //将私钥字符串恢复为私钥对象
            PrivateKey privateKey = getPrivateKey(key);
            //实例加密工厂对象
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            //设置私钥
            signature.initSign(privateKey);
            //设置原始数据
            signature.update(requestData.getBytes());
            //执行,获取签名密钥
            byte[] signed = signature.sign();
            //将签名密钥转字符串
            return Base64.getEncoder().encodeToString(signed);
        }
    
        /**
         * 验签
         *
         * @param key         公钥字符串
         * @param requestData 原始数据
         * @param signstr     签名密钥
         */
        public static boolean verifySign(String key, String requestData, String signstr) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
            //将公钥字符串恢复为公钥对象
            PublicKey publicKey = getPublicKey(key);
            //实例加密工厂对象
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            //设置验证公钥
            signature.initVerify(publicKey);
            //设置原始数据
            signature.update(requestData.getBytes());
            //设置签名密钥后做校验,返回校验结果,true为通过,false为失败
            return signature.verify(Base64.getDecoder().decode(signstr));
    
        }
    
        /**
         * 测试
         */
        public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException {
            //生成随机公、私钥
            Map<String, String> keyPairMap = createRSAKeys();
    
            String privateKeyStr = keyPairMap.get(PRIVATE_KEY);
            System.out.println("生成随机私钥: " + privateKeyStr);
    
            String publicKeyStr = keyPairMap.get(PUBLIC_KEY);
            System.out.println("生成随机公钥: " + publicKeyStr);
    
            System.out.println("===开始RSA公、私钥测试===");
            String str = "你大爷撒娇打啥电话手机卡";
    
            //私钥加密得出签名密钥
            String sign = sign(privateKeyStr, str);
            System.out.println("===签名密钥字符串:" + sign);
    
            //公钥验证是否被篡改
            boolean res = verifySign(publicKeyStr, str, sign);
            System.out.println("===验签结果:" + res);
        }
    }
    View Code

    4.测试

     

  • 相关阅读:
    javascript 原型和构造函数
    react native与原生的交互
    项目中git的用法
    web页面的回流,认识与避免
    js 中的算法题,那些经常看到的
    js中this的四种调用模式
    JS面向对象的几种写法
    模块化加载require.js
    es6新语法
    vue组件化开发
  • 原文地址:https://www.cnblogs.com/c2g5201314/p/16582926.html
Copyright © 2020-2023  润新知