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.测试

 

 

posted @ 2022-08-13 14:10  岑惜  阅读(1027)  评论(0编辑  收藏  举报