为 jsencrypt 增加私钥加密公钥解密的方法逻辑

首先声明,使用 RSA 非对称加密,正常的使用情景是公钥加密、私钥解密。

因为正常使用情景下,公钥是公开的,如果将私钥加密的数据发出去,使用公钥解密,其实理论上并没有起到加密的作用。

私钥加密、公钥解密的使用场景是在于防篡改,确定私钥发来的数据是正确的。

其实某种程度来说,确实就没必要再实现私钥加密,公钥解密的逻辑了。

不过出于强迫症的角度,理论上私钥是可以用于加密的,公钥也可以用于解密,那为什么不实现一下呢。。。

在 .NET 中,使用 BouncyCastle 是可以轻易实现的,但在 JavaScript 中,几乎所有 RSA 的算法库都没有进行支持。

好在有这种奇奇怪怪的需求的人们不少,jsencrypt 也算是使用比较广泛的一个 JavaScript 中的 RSA 算法库了,

总结了一下网上大家的思路,基于 jsencrypt 已有的公钥加密、私钥解密逻辑,修改了一套私钥加密、公钥解密的逻辑出来。

这里面比较核心的点,是 PKCS #1: RSA Encryption Version 1.5 的数据块组成

本身在 jsencrypt 中,私钥公钥的算法都是通用的,只是基于 pkcs 的封装有一些差异,导致无法使用私钥加密、公钥解密。

在此记录一下,

在需要加密时,在进行 RSA 运算前,需要先将源数据 D 封装为 Encryption block(EB)。

其中 PKCS #1: RSA Encryption Version 1.5 的数据块组成如下:

EB = 0x00 + BT + PS + 0x00 + D

说明:EB 为转化后的字节数组(一般以 16 进制表示),EB字节数组长度 = 密钥长度 / 8

0x00:第一位固定为 0x00
BT:公钥加密:0x02,私钥加密:0x00 或 0x01

PS:填充位,除固定位和数据位外,对 EB 的其余字节位进行填充,一般至少保留 8 位。
BT = 0x00 时全部填充 0x00(此种情景下,数据部分的首位字节必须非零,否则将无法准确的识别数据区)
BT = 0x01 时全部填充 0xFF
BT = 0x02 时随机产生数字填充(不允许填充 0x00)

0x00:源数据 D 的前一个字节,固定为 0x00,用于分隔填充位与数据区
D:源数据,填充在 EB 最后,因以上组成部分,源数据字节数组最大长度 = 密钥长度 / 8 - (1 + 1 + 8 + 1),即:EB长度-11

一般 RSA 密钥长度为 1024 位,则:
EB字节数组长度 = 1024 / 8 = 128
源数据字节数组最大长度 = 128 - 11 = 117

同理,解密就是在 RSA 运算后,按以上结构将数据再进行取出即可。

参考文章:

https://www.cnblogs.com/wsss/p/11516318.html

https://datatracker.ietf.org/doc/html/rfc2313#section-8.1

https://github.com/lwenhaoCN/RSA

https://blog.csdn.net/junxuezheng/article/details/109824552

因为看 jsencrypt 项目已经很久不怎么更新了,感觉也不太会有大更新了,直接 fork 了一个进行修改,后续可以直接用了。

修改好的 jsencrypt 项目地址:https://github.com/xwgli/jsencrypt

posted @ 2024-05-09 19:18  不是豆豆  阅读(110)  评论(0编辑  收藏  举报
友情链接:迷途