目前使用 jsencrypt 和 node-forge 通过 RSA 解密和加密消息,其中 jsencrypt 用于前端,node-forge 用于后端。
import { JSEncrypt } from 'jsencrypt'
import * as forge from 'node-forge';
const message = 'data....'
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( message, 'RSA-OAEP')
console.log('encrpted:', encrypted)
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 decrypted = privateK.decrypt(encrypted, 'RSA-OAEP')
console.log('original:', decodeURIComponent(decrypted))
这有效。
然后尝试使用具有相同 pub/pri 密钥和消息的 jsencrypt。
const encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
let encrypedQuery = encrypt.encrypt( message );
console.log( encrypedQuery );
try{
const privateK = forge.pki.privateKeyFromPem(privateKey)
const decrypted2 = privateK.decrypt(encrypedQuery)
console.log('original::', decodeURIComponent(decrypted2))
}catch(err){
console.log(err);
}
这将输出一个错误,提示“加密消息长度无效。”
第二段代码中的问题是由于 JSEncrypt 端返回 Base64 编码的密文,而 node-forge 需要 binary/latin1 字符串而引起的编码问题。可以使用
forge.util.decode64()
(或atob()
) 修复此问题:请注意,第一个代码片段使用 OAEP 作为填充(明确指定),而第二个代码片段应用 PKCS#1 v1.5 填充(JSEncrypt专门使用 PKCS#1 v1.5,node-forge默认应用它)。
由于填充在同一个代码片段中是一致的,因此解密有效。但是,不可能用第二个代码片段解密用第一个代码片段生成的密文,反之亦然。
带有 OAEP 的 JSEncrypt:
虽然 node-forge 默认支持 PKCS#1 v1.5 和 OAEP 作为填充,但是常规 JSEncrypt 库的填充是 PKCS#1 v1.5,无法更改。因此,两个库之间的互操作只能使用 PKCS#1 v1.5。
正如评论中提到的,较旧的 PKCS#1 v1.5 填充容易受到某些攻击,而 OAEP 是更安全的替代方案。如果您想将 JSEncrypt 与 OAEP 一起使用: Github 上
有一个 JSEncrypt拉取请求和一个使用 OAEP 扩展 JSEncrypt 的分支,这可能是您的一个选择。但是,这对 OAEP 和 MGF1 摘要都使用 SHA-256,而 node-forge 默认应用 SHA-1,但也支持其他摘要。由于 JSEncrypt 端的摘要无法更改,因此必须将 node-forge 端的摘要更改为 SHA-256 才能进行互操作,例如: