前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jsrsasign 前端 RSA 加密 node 端解密

jsrsasign 前端 RSA 加密 node 端解密

作者头像
solocoder
发布2023-04-23 16:14:49
3.4K0
发布2023-04-23 16:14:49
举报
文章被收录于专栏:大前端客栈大前端客栈

有些场景下需要前端做加密,比如登录的时候,用户输入的密码需要传输给后端,为了保证安全,最好前端先加密后传输,后端接收到之后,再解密拿到明文。 需要在不同端进行加密解密的话 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-rsajsrsasign。但是 node-rsa 最近更新已经是三年前了,jsrsasign 更新的比较频繁,几天前才有更新,周下载量30万次,算是比较靠谱的。 jsrsasign 官方文档地址:https://kjur.github.io/jsrsasign/

三、openssl 生成公钥和私钥

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

openssl 生成私钥

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

代码语言:javascript
复制
genrsa -out /your_path/rsa_pricate.pem 2048

-out指定了输出的路径,最后的 2048 表示生成 2048 位的秘钥。

image.png
image.png

打开生成的 pem 文件,可以看到如下格式的内容。

代码语言:javascript
复制
-----BEGIN RSA PRIVATE KEY-----
xxxxxxxxxxxxx
-----END RSA PRIVATE KEY-----

根据私钥生成公钥

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

代码语言:javascript
复制
rsa -in /your_path/rsa_pricate.pem -pubout -out /your_path/rsa_public.pem

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

代码语言:javascript
复制
-----BEGIN PUBLIC KEY-----
xxxxxxxxxxxxx
-----END PUBLIC KEY-----

四、前端加密

安装依赖

代码语言:javascript
复制
npm install jsrsasign jsrsasign-util

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

代码语言:javascript
复制
npm i --save-dev @types/jsrsasign 

然后对密码进行加密。

代码语言:javascript
复制
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'),得到密文如下:

代码语言:javascript
复制
密文: 9999d156ce02a130c51c3a94c1010aa8ead62499a373f51f57177894b8634baab62a968c12306c46a2aee8358bd224a0138c7d7c38678a56ed2f6537667b67bdf8b5b7fd555091283609b7077e7146a0cd0f3644f2ad1680bb9cf9ee104305b19153eef15950f9d2b3fdd0074ed420169e6cf63d8aa95aeda7a4dc28f201119eef1f6e354e7e18d43c27e528104fdfecf4363fdb676c96ef5ffc8ba1b99c1bff6955970bf71c4220a7f81e34080f854f43738b414d798c70232719e12d22398e8d36f414556c6dc297525e391be63a5542b2e15834c1870af1ab109c74cf2b094d778a4abc0e82ed43ad0664f2a09806c4d98df9d71e9338236e6e8f7115720e

五、node 端解密

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

代码语言:javascript
复制
npm install jsrsasign jsrsasign-util

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

代码语言:javascript
复制
npm i --save-dev @types/jsrsasign 

解密方法如下:

代码语言:javascript
复制
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()`将解密后的文本进行转码得到正确的中文。 完整的代码如下:

代码语言:javascript
复制
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);
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、RSA 简介
  • 二、jsrsasign
  • 三、openssl 生成公钥和私钥
    • openssl 生成私钥
      • 根据私钥生成公钥
      • 四、前端加密
      • 五、node 端解密
      • 六、中文乱码问题解决
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档