Springboot web RSA 加解密签名验签流程

醉卧沙场君莫笑,古来征战几人回?

1 前言

在日常的软件开发中,经常会遇到与外部系统的交互的场景,比如在支付、调用特定服务的场景,大多数通过网关来处理这样的情况,可以参考之前写的一篇文章进行了解 springcloud gateway auth2.0 security nacos 项目集成实践。在最近的工作中,接触到了网关加解密的内容,再加上之前也对接过支付场景,都涉及到了加解密验签的内容,正所谓温故而知新,在本文中将全方位讲解 RSA 加密、解密、签名、验签等内容,并结合 springboot 进行代码的编写,本文使用了 Hutool 来实现所有的操作过程。

2 RSA 算法原理

2.1 DH 密钥交换算法

RSA 是在工作中最常见的非对称加解密算法,其核心原理是 DH 密钥交换算法,这个涉及到了数论和离散对数的知识。通常来讲,密钥交换算法核心流程如下:

1 Alice 会生成一个质数 p 和 底数 g, 并设置一个自己的私钥 a, 通过指数运算 A = <math xmlns="http://www.w3.org/1998/Math/MathML"> g a ( m o d p ) g^{a}(mod\quad p) </math>ga(modp) , 然后将 p,g,A 发送给 Bob。

2 Bob 设置一个自己知道的私钥 b, 计算 B = <math xmlns="http://www.w3.org/1998/Math/MathML"> g b ( m o d p ) g^{b}(mod\quad p) </math>gb(modp) 发送给 Alice。

3 此时 Alice 可以通过 K = <math xmlns="http://www.w3.org/1998/Math/MathML"> B a ( m o d p ) B^{a}(mod\quad p) </math>Ba(modp) 得到密码, Bob 可以通过 K = <math xmlns="http://www.w3.org/1998/Math/MathML"> A b ( m o d p ) A^{b}(mod\quad p) </math>Ab(modp) 得到同样的公共密码。

2.2 RSA 公私钥生成算法

RSA 算法生成公钥 PK 和私钥 SK :

css 复制代码
1 选择两个比较大的质数 P 和 Q, 且 P 不能与 Q 相等。
2 将P、Q两个素数相乘得到一个N,即 N = PQ
3 将P、Q分别减一,再相乘,得到一个数 T,即 T=(Q-1)*(P-1)
4 选择一个整数 E,作为一个密钥,使 E 与 T 互为质数,且 E 必须小于 T
5 根据公式 DE mod T = 1 ,计算出 D 的值,作为另一个私钥。
6 通过上述步骤就可以求出 N,E,D 这三个数据,其中(N,E)作为公钥,(N,D)作为私钥。

明文为 M, 密文为 C, 则加密过程即 C = <math xmlns="http://www.w3.org/1998/Math/MathML"> M E ( m o d N ) M^{E}(mod\quad N) </math>ME(modN) 对应的解密过程即 M = <math xmlns="http://www.w3.org/1998/Math/MathML"> C D ( m o d N ) C^{D}(mod\quad N) </math>CD(modN)

3 Hutool 生成 公私钥

使用命令行模式 openssl 生成公私钥的命令如下所示:

bash 复制代码
# alias 表示使用这对公私密钥产生新的keystore入口的别名
# keyalg 产生公私钥对所用的算法,这里是RSA。
# keysize 密钥的长度
# sigalg 签名算法,MD5withRSA 即用RSA签名,然后用MD5哈希算法摘要
keytool -genkey -alias testkeypair -keyalg RSA -keysize 2048 -sigalg MD5withRSA

使用 Hutool 生成公私钥非常的简单,按照如下操作即可实现。默认情况下,使用的 RSA 算法是 RSA/ECB/PKCS1Padding

ini 复制代码
RSA rsa = new RSA();
//获得私钥
PrivateKey privateKey = rsa.getPrivateKey();
String privateKeyBase64 = rsa.getPrivateKeyBase64();
//获得公钥
PublicKey publicKey = rsa.getPublicKey();
String publicKeyBase64 = rsa.getPublicKeyBase64();
log.info("pub key :\n{}", publicKeyBase64);
log.info("pri key :\n{}", privateKeyBase64);

加密与解密流程,对于调用方来说,加密一般是指用服务方的公钥进行加密,加密完成后发送给服务方,服务方使用自己的私钥进行解密,反之亦然。

签名与验签流程,对于服务方而言,签名是指用自己的私钥对报文进行签名,调用方使用服务方的公钥进行验签,反之亦然。

4 加解密与加签验签

如下图所示,即是加密,解密, 加签,验签的主要方法。在整个过程中,需要注意的是需要按照字典顺序将参数进行排序,否则加解密或者加验签的操作会出现错误。

除了使用 TreeMap 来对参数进行排序外,还可以将参数转换成 json 格式,使用 MapSortField 来解决这个排序问题。 String str = JSONObject.toJSONString(resp, SerializerFeature.MapSortField);

5 调用过程分析

模拟服务端,接收客户端密文,验签并解密。加密返回报文并加签。

模拟客户端,发送加密报文,获取服务端内容并解密。

总结一下就是,公钥加密,私钥解密。私钥签名,公钥验签

6 总结

在本文中,主要分享了 DH 密钥交换算法和公私钥的生成方法, RSA 加解密、加验签的内容,并且结合 Hutool 工具类进行了验证和实验,具体的代码已经上传到 github, 欢迎大家点赞和 stars。项目 github 地址 springboot-auth

相关推荐
计算机小白一个14 分钟前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
孤雪心殇16 分钟前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
菠菠萝宝28 分钟前
【Java八股文】10-数据结构与算法面试篇
java·开发语言·面试·红黑树·跳表·排序·lru
不会Hello World的小苗35 分钟前
Java——链表(LinkedList)
java·开发语言·链表
Allen Bright1 小时前
【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程
java·开发语言
柃歌1 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌1 小时前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
是姜姜啊!2 小时前
redis的应用,缓存,分布式锁
java·redis·spring
梨落秋溪、2 小时前
输入框元素覆盖冲突
java·服务器·前端
hrrrrb2 小时前
【Java】Java 常用核心类篇 —— 时间-日期API(上)
java·开发语言