You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js RSA加密数据后前端JS解密失败,报malformed utf8 data错误求助

Node.js RSA加密后前端解密出现「malformed utf8 data」错误的解决方案

问题背景

在Node.js中使用RSA公钥加密数据,将私钥传输到前端后,用JSEncrypt解密时始终出现「malformed utf8 data」错误,多次尝试无法解决。

核心原因

  1. 填充方式不兼容:Node.js的crypto模块默认使用RSA_PKCS1_OAEP_PADDING填充,但JSEncrypt默认仅支持RSA_PKCS1_V1_5(即PKCS1-PADDING),两者不匹配导致解密失败。
  2. 私钥格式损坏:EJS渲染私钥时使用<%= %>会自动转义HTML特殊字符,导致私钥的PEM格式丢失换行符,无法被JSEncrypt正确识别。

修复步骤及代码示例

1. 修改Node.js端加密逻辑,统一填充方式

将加密和解密的填充方式改为RSA_PKCS1_PADDING,与JSEncrypt兼容:

const crypto = require('crypto');

function generate_key() {
  const keys = crypto.generateKeyPairSync('rsa', {
    modulusLength: 2048,
    publicKeyEncoding: { type: 'spki', format: 'pem' },
    privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
  });
  const { privateKey, publicKey } = keys;
  return { privateKey, publicKey };
}

function enc(plainText, publicKey) {
  const buffer = Buffer.from(plainText, 'utf-8');
  const encrypted = crypto.publicEncrypt(
    { key: publicKey, padding: crypto.constants.RSA_PKCS1_PADDING }, // 改用PKCS1-V1_5填充
    buffer
  );
  return encrypted.toString('base64');
}

// Node.js端解密测试(验证加密正确性)
function dec(cipherText, privateKey) {
  const buffer = Buffer.from(cipherText, 'base64');
  const decrypted = crypto.privateDecrypt(
    { key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, // 匹配填充方式
    buffer
  );
  return decrypted.toString('utf-8');
}

// 业务逻辑示例
let { privateKey, publicKey } = generate_key();
const plaintext = 'This is the message to be encrypted';
const encrypted = enc(plaintext, publicKey);

// 渲染页面时传递参数
res.render('final', { privateKey: privateKey, encrypted: encrypted });

2. 修复前端EJS渲染逻辑,保留私钥格式

使用<%- %>代替<%= %>渲染私钥和加密数据,避免HTML转义破坏格式:

<script src="/jsencrypt.min.js"></script>
<script>
// 用<%- %>确保私钥的PEM格式完整保留
let privateKey = `<%- privateKey %>`;
let encrypted = `<%- encrypted %>`;

var crypt = new JSEncrypt();
crypt.setPrivateKey(privateKey);
var decrypted = crypt.decrypt(encrypted);

console.log('解密结果:', decrypted);
</script>

额外说明

  • 如果必须使用OAEP填充,需更换支持该填充方式的前端加密库(如forge或crypto-js),JSEncrypt原生不支持OAEP。
  • 传输私钥存在安全风险,实际生产环境中不建议将私钥暴露到前端,应采用前端加密、后端解密的模式,或使用对称加密结合非对称加密的方案。

内容的提问来源于stack exchange,提问作者devil_sm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:22:28