本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
jsrsasign 前端 RSA 加密 node 端解密
BilyLiang · 225浏览 · 发布于2023-03-23 +关注

有些场景下需要前端做加密,比如登录的时候,用户输入的密码需要传输给后端,为了保证安全,最好前端先加密后传输,后端接收到之后,再解密拿到明文。
需要在不同端进行加密解密的话 RSA 非对称加密算法最适合。

一、RSA 简介

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。
正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
RSA允许你选择公钥的大小。512位的密钥被视为不安全的;768位的密钥不用担心受到除了国家安全管理(NSA)外的其他事物的危害;RSA在一些主要产品内部都有嵌入,像 Windows、网景 Navigator、 Quicken和 Lotus Notes。

二、jsrsasign

RSA 加密的第三方库有很多,用的比较多的是 node-rsa 和 jsrsasign。但是 node-rsa 最近更新已经是三年前了,jsrsasign 更新的比较频繁,几天前才有更新,周下载量30万次,算是比较靠谱的。
jsrsasign 官方文档地址:kjur.github.io/jsrsasign/

三、openssl 生成公钥和私钥

加密解密需要用到 pem 格式的公钥和私钥,秘钥可以通过 openssl 自己生成。

openssl 生成私钥

打开终端,输入 openssl回车之后就进入了 OpenSSL 命令行的交互。
生成私钥命令:

genrsa -out /your_path/rsa_pricate.pem 2048


-out指定了输出的路径,最后的 2048 表示生成 2048 位的秘钥。
image.png
打开生成的 pem 文件,可以看到如下格式的内容。

-----BEGIN RSA PRIVATE KEY-----
xxxxxxxxxxxxx
-----END RSA PRIVATE KEY-----

根据私钥生成公钥

公钥是根据私钥生成的,继续在 OpenSSL 交互式命令行里输入以下命令

rsa -in /your_path/rsa_pricate.pem -pubout -out /your_path/rsa_public.pem


把 your_path替换成你电脑中的真实路径即可。执行完后得到公钥:

-----BEGIN PUBLIC KEY-----
xxxxxxxxxxxxx
-----END PUBLIC KEY-----


四、前端加密

安装依赖

npm install jsrsasign jsrsasign-util


如果用了 TS,还需要安装对应的类型提示

npm i --save-dev @types/jsrsasign


然后对密码进行加密。

import { KJUR, KEYUTIL, RSAKey } from 'jsrsasign'

function encryptKey(password: string) {
  const keyObj = KEYUTIL.getKey(publicKey);
  const encryptPwd = KJUR.crypto.Cipher.encrypt(password, keyObj as RSAKey, 'RSAOAEP')
  console.log('密文:', encryptPwd)
}

publicKey就是上一节生成的公钥的文本,先通过 KEYUTIL.getKey(publicKey)获取秘钥的对象,再通过 KJUR.crypto.Cipher.encrypt()进行加密。
encrypt(s, keyObj, algName)方法有三个参数:

  • s: 要加密的文字

  • keyObj: 通过 KEYUTIL 获取的公钥的对象

  • algName: 加密的方法名

algName 有以下几种取值:

  • RSA - RSA/ECB/PKCS1Padding (default for RSAKey)

  • RSAOAEP - RSA/ECB/OAEPWithSHA-1AndMGF1Padding

  • RSAOAEP224 - RSA/ECB/OAEPWithSHA-224AndMGF1Padding(*)

  • RSAOAEP256 - RSA/ECB/OAEPWithSHA-256AndMGF1Padding

  • RSAOAEP384 - RSA/ECB/OAEPWithSHA-384AndMGF1Padding(*)

  • RSAOAEP512 - RSA/ECB/OAEPWithSHA-512AndMGF1Padding(*)

调用加密方法加密一串英文:encryptKey('Hello Javascript'),得到密文如下:

密文: 9999d156ce02a130c51c3a94c1010aa8ead62499a373f51f57177894b8634baab62a968c12306c46a2aee
8358bd224a0138c7d7c38678a56ed2f6537667b67bdf8b5b7fd555091283609b7077e7146a0cd0f3644f2ad1680b
b9cf9ee104305b19153eef15950f9d2b3fdd0074ed420169e6cf63d8aa95aeda7a4dc28f201119eef1f6e354e7e1
8d43c27e528104fdfecf4363fdb676c96ef5ffc8ba1b99c1bff6955970bf71c4220a7f81e34080f854f43738b414
d798c70232719e12d22398e8d36f414556c6dc297525e391be63a5542b2e15834c1870af1ab109c74cf2b094d778
a4abc0e82ed43ad0664f2a09806c4d98df9d71e9338236e6e8f7115720e


五、node 端解密

node 端依然可以用 jsrsasign 来解密,跟前端一样安装依赖

npm install jsrsasign jsrsasign-util


如果用了 TS,还需要安装对应的类型提示

npm i --save-dev @types/jsrsasign


解密方法如下:

import { KEYUTIL, KJUR, RSAKey } from 'jsrsasign';

decryptKey(key: string) {
  const keyObj = KEYUTIL.getKey(privateKey);
  const name = KJUR.crypto.Cipher.decrypt(key, keyObj as RSAKey, 'RSAOAEP');
  console.log('明文:', name);
}


privateKey是第三节生成的私钥的文本,通过 KEYUTIL.getKey()获取私钥的对象,然后再通过 KJUR.crypto.Cipher.decrypt()进行解密。需要注意的是第三个参数 algName要与前端加密时的方法一样。
输出:

明文: Hello Javascript

这样前端用公钥加密,node 端用私钥解密就完成了。

六、中文乱码问题解决

通过上面的方法,加密解密英文没问题,但加密中文解密出来会是乱码。
比如原文是 Javascript你好我是密码,解密之后得到的是 Javascript}/Æ,后面的中文乱码了。<br />看网上的解决方法有些是修改解密方法,其实最简单的方法是在加密的时候,先用 encodeURI()对中文进行编码之后再进行加密,解密的时候,先解密再用 decodeURI()`将解密后的文本进行转码得到正确的中文。
完整的代码如下:

import { KEYUTIL, KJUR, RSAKey } from 'jsrsasign';

// 加密
function encryptKey(password: string) {
  const keyObj = KEYUTIL.getKey(publicKey);
  const encryptPwd = KJUR.crypto.Cipher.encrypt(encodeURI(password), keyObj as RSAKey, 
  'RSAOAEP')
  console.log('密文:', encryptPwd)
}

// 解密
decryptKey(key: string) {
  const keyObj = KEYUTIL.getKey(privateKey);
  const name = decodeURI(
    KJUR.crypto.Cipher.decrypt(key, keyObj as RSAKey, 'RSAOAEP') || '',
  );
  console.log('明文:', name);
}



相关推荐

RN开发环境的npm私库本地debug调试

manongba · 698浏览 · 2019-05-09 17:03:46
你不知道的浏览器渲染原理

追忆似水年华 · 1373浏览 · 2019-05-09 22:47:56
基于iview的router常用控制方式

追忆似水年华 · 999浏览 · 2019-06-03 10:39:21
编程小知识之 JavaScript 文件读取

manongba · 717浏览 · 2019-06-10 09:16:16
10个省时间的 PyCharm 技巧 赶快收藏!

· 703浏览 · 2019-06-10 09:32:01
加载中

0评论

评论
我是湖南最靓仔的那条仔,希望来到这里能够交道志同道合的朋友,一起学习,不断进步!!!
分类专栏
小鸟云服务器
扫码进入手机网页