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

Node.js加密WebCrypto客户端解密:数据类型适配问题求助

解决RSA-OAEP密钥对跨端加密的数据类型适配问题

我帮你梳理下这个流程里最容易踩的坑,主要集中在密钥格式转换、二进制数据传输编码和异步逻辑处理这几个点上,直接上修正后的代码和关键说明:

客户端代码修正

首先,你的密钥生成和导出逻辑里有异步时序的问题,建议用async/await来避免变量未就绪的情况,同时处理好服务器返回加密数据后的解码步骤:

// 客户端密钥生成(改用async/await更清晰)
const crypto = window.crypto.subtle;
let publicKeyToExport;
let privateKeyToStore;

const generateKeypair = async () => {
  try {
    const keyPair = await crypto.generateKey(
      {
        name: 'RSA-OAEP',
        modulusLength: 2048,
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: { name: 'SHA-256' },
      },
      true,
      ['encrypt', 'decrypt']
    );
    publicKeyToExport = keyPair.publicKey;
    privateKeyToStore = keyPair.privateKey;
    console.log('密钥对生成完成:', keyPair);
  } catch (err) {
    console.error('密钥生成失败:', err);
  }
};

// 导出公钥并发送到服务器,同时处理加密后的返回数据
const exportPublicKeyAndEncrypt = async () => {
  if (!publicKeyToExport) {
    console.error('请先生成密钥对!');
    return;
  }
  try {
    const jwkPublicKey = await crypto.exportKey('jwk', publicKeyToExport);
    const response = await fetch('/key2', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(jwkPublicKey),
    });

    if (!response.ok) throw new Error('服务器请求失败');
    const encryptedData = await response.json();
    
    // 解密服务器返回的加密数据
    const decryptedBuffer = await crypto.decrypt(
      { name: 'RSA-OAEP' },
      privateKeyToStore,
      // 把base64字符串转回Uint8Array
      Uint8Array.from(atob(encryptedData.data), c => c.charCodeAt(0))
    );
    
    // 转成明文字符串
    const plaintext = new TextDecoder().decode(decryptedBuffer);
    console.log('解密后的明文:', plaintext);
  } catch (err) {
    console.error('处理失败:', err);
  }
};

Node.js服务器端代码修正

重点是正确导入JWK格式的公钥,以及加密后把二进制数据转成base64(因为JSON不能直接存二进制):

首先确保你已经安装了依赖:

npm install node-webcrypto-ossl

然后是服务器逻辑:

const express = require('express');
const { Crypto } = require('node-webcrypto-ossl');
const app = express();
const crypto = new Crypto();

// 解析JSON请求体
app.use(express.json());

app.post('/key2', async (req, res) => {
  try {
    const jwkPublicKey = req.body;
    // 导入JWK格式的公钥,注意算法参数要和客户端完全匹配
    const publicKey = await crypto.subtle.importKey(
      'jwk',
      jwkPublicKey,
      {
        name: 'RSA-OAEP',
        hash: { name: 'SHA-256' },
      },
      true,
      ['encrypt']
    );

    // 要加密的字符串,先转成Uint8Array
    const plaintext = 'Hello from server!';
    const plaintextBuffer = new TextEncoder().encode(plaintext);
    
    // 加密数据
    const encryptedBuffer = await crypto.subtle.encrypt(
      { name: 'RSA-OAEP' },
      publicKey,
      plaintextBuffer
    );
    
    // 把二进制转成base64字符串,方便JSON传输
    const encryptedBase64 = btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer)));
    
    res.json({ data: encryptedBase64 });
  } catch (err) {
    console.error('服务器加密失败:', err);
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('服务器运行在3000端口'));

关键适配点说明

  1. 密钥格式一致性:客户端导出的是JWK格式,服务器导入时必须严格匹配算法参数(RSA-OAEP + SHA-256),否则会出现密钥不兼容的错误。
  2. 二进制数据传输:加密后的结果是ArrayBuffer,不能直接用JSON序列化,所以要转成base64字符串,客户端拿到后再转回Uint8Array进行解密。
  3. 异步逻辑处理:用async/await替代链式then,避免回调地狱,同时确保密钥生成完成后再执行导出和加密请求,防止变量未初始化。
  4. 编码解码统一:服务器用TextEncoder把字符串转成Uint8Array加密,客户端用TextDecoder把解密后的ArrayBuffer转回字符串,保持编码一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:59:21