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端口'));
关键适配点说明
- 密钥格式一致性:客户端导出的是JWK格式,服务器导入时必须严格匹配算法参数(
RSA-OAEP+SHA-256),否则会出现密钥不兼容的错误。 - 二进制数据传输:加密后的结果是
ArrayBuffer,不能直接用JSON序列化,所以要转成base64字符串,客户端拿到后再转回Uint8Array进行解密。 - 异步逻辑处理:用
async/await替代链式then,避免回调地狱,同时确保密钥生成完成后再执行导出和加密请求,防止变量未初始化。 - 编码解码统一:服务器用
TextEncoder把字符串转成Uint8Array加密,客户端用TextDecoder把解密后的ArrayBuffer转回字符串,保持编码一致。
内容的提问来源于stack exchange,提问作者dendog
相关产品推荐
相关产品推荐

