5

并没有体验多少库,只看了一个npm里最多人用的一个库:

node-forge接口文档

rsa小知识

  • 加密解密用的key是成对的,分别称为私钥和公钥,私钥必须存放在服务器等别人无法获取到的地方,公钥可以公开,谁都可以获取。
  • 不能把公钥当私钥,私钥当公钥使用,因为私钥可以提取出公钥。
  • 公钥加密的内容,只有私钥能解密,连公钥都不能解密自己加密的内容。
  • 私钥加密的过程称为签名(sign),因为公钥是公开的,谁都能解密,所以无法保密信息,只能用于验证签名者是私钥持有人。

前端代码

// 他们github有提供 forge.min.js , 不用webpack的项目也可以直接引用
import forge from 'node-forge'

const message = '要加密我了' // 原文长度有限制,而且中文还要url编码,所以不能加密太长的字符串。一般也只用来加密密码。
const publicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqM+l9ZWy1Frt6felFFLmfZNls\nVbU1dKpF8Rx83FtKCsztO5k/iV5N9BbfHFUg9Y40b/EK2j/BPc1xlLYAHMXn6563\nXCwZ4IuCxvfOwz9qT9gkKBxkI5b0rnikkSWTGlJEk2PdZ7Plc73Fa+bx3PvuKvMd\ncKWvd80+vt9+b/7hrwIDAQAB\n-----END PUBLIC KEY-----'
const publicK = forge.pki.publicKeyFromPem(publicKey)
const encrypted = publicK.encrypt(encodeURIComponent(message), 'RSA-OAEP') // 经过url编码,后端解密后需要url解码
console.log('密文:', encrypted) // 虽然乱码,但可以直接发给后端解密
const base64 = window.btoa(unescape(encodeURIComponent(encrypted)))
console.log('密文base64:', base64) // 一般会把它转为base64传给后端

ps. 以上代码建议使用try,因为加密中如果出现问题,会throw Error

nodejs端代码

const forge = require('node-forge')
const privateKey = '-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKoz6X1lbLUWu3p9\n6UUUuZ9k2WxVtTV0qkXxHHzcW0oKzO07mT+JXk30Ft8cVSD1jjRv8QraP8E9zXGU\ntgAcxefrnrdcLBngi4LG987DP2pP2CQoHGQjlvSueKSRJZMaUkSTY91ns+VzvcVr\n5vHc++4q8x1wpa93zT6+335v/uGvAgMBAAECgYArxUnou6qnL39rUvIol9ncyfy4\nRZpicuxPLGCdI7Y+ZmSpJciVdGhSN9Gh8xFZdozpo1gj6Fi5A4HQEeR0RvIF9Rgh\nERblj1rRWqxPcsIddOO9VaknQPICWKqEW9+E1bEcyNUblCHA4LGyQwmuEFUb/Tkj\nxAghIHuEBCe0GFiVwQJBAN5i5QSoOIpdFHA0c981E4VhHc/muXwjx1HfE1pcuuFb\nTy3OwEoZdFp3LIjBnBkPRneLTNjo5WTIwrmfsy6VDF8CQQDD7c6d/nKiJwIESlr+\n/idqXAPNR/iS1YX3Nqtk9jgrgf5zULHr2nbk7MDas5S9Z9XPdUmxtnP44dhoGvDk\nzyyxAkB7XBxyQuZqSkvGGjKUhJq5iC/DXddSd35fegEARSQdUktPu7qK4Cfc7vKz\nQcLXW9PZCFqukDJ/f6YU1fPNSTy9AkADQ78hms/GK+g4shR6EzoM56OYlA5sQ+qL\nh/mrIP8mmm/m8/1C9MzuW5OLEVr1HPnPDyE/OM8N4pV8hpZk+Z7BAkEAzaFstazA\nxLzZOBWhvOzzo722glZ7HVezhMocLu7Y3EOXP/nbx09JpU3U7Egp5UVp0aiknh/Q\nez4Cc4ksMedxdA==\n-----END PRIVATE KEY-----\n'
const privateK = forge.pki.privateKeyFromPem(privateKey)
const encrypted = Buffer.from(base64, 'base64').toString() // base64 为前端传过来的密文base64
const decrypted = privateK.decrypt(encrypted, 'RSA-OAEP')
console.log('原文:', decodeURIComponent(decrypted)) // decrypted 为原文

ps. 以上代码建议使用try,因为解密中如果出现问题,会throw Error

ps. 以上例子用了RSA-OAEP规则,其实rsa还有很多加密规则,我粗略查了一下,据说RSA-OAEP是目前比较新的方式,另外有一些旧的规则已经不推荐使用了,留着只是为了向上兼容。没有深入查下去,因为我怕接下来要研究密码学了...

ps. 如果觉得加密后的字符串是乱码不好看,或者担心传输会出问题,可以使用base64转一下,服务端接收到则先解析base64再解密。

生成密钥公钥对

const forge = require('node-forge')
const { rsa, publicKeyToRSAPublicKeyPem, privateKeyToPem } = forge.pki
rsa.generateKeyPair({ bits: 2048, workers: 2 }, function (err, keypair) {
  if (err) {
    return
  }

  // 这里就生成了字符串的公钥和密钥了,可以把生成结果保存起来
  console.log({
    publicKey: publicKeyToRSAPublicKeyPem(keypair.publicKey, 72).replace(/\r/g, ''),
    privateKey: privateKeyToPem(keypair.privateKey, 72).replace(/\r/g, '')
  })
})


黒之染
3.1k 声望47 粉丝

两年半个人练习生,喜欢ctrl+c/ctrl+v/delete