React向Python传输RSA加密数据时密文长度与密钥不匹配问题
解决RSA-OAEP加密后后端解密报错"Ciphertext length must be equal to key size."
问题场景
在React前端通过Web Crypto API用RSA-OAEP加密数据,Base64编码后传给Python后端,后端解码后解密时抛出错误:Ciphertext length must be equal to key size.,即使已完成Base64编解码转换,问题依然存在。
错误原因
- Base64编码方式错误:前端直接用
window.btoa()处理加密后的ArrayBuffer,btoa仅支持UTF-8字符串,将ArrayBuffer直接传入会被强制转换为字符串,导致二进制数据损坏,后端解码后得到的密文长度与4096位密钥要求的512字节不符。 - 公钥导入时的字符串截取问题:原代码截取PEM内容的方式可能因换行符、空格等字符导致截取不完整,公钥导入错误会生成无效密文。
修复方案
1. 修正前端Base64编码逻辑
替换window.btoa()为正确的ArrayBuffer转Base64方法:
function arrayBufferToBase64(buffer) { const uint8Array = new Uint8Array(buffer); let binary = ''; const len = uint8Array.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(uint8Array[i]); } return window.btoa(binary); }
传输数据时使用该函数:
encrypt(rsa_key, "test") .then((data) => { axiosInstance.post(`auth/token/`, { hash: arrayBufferToBase64(data), }) // ... 后续代码 })
2. 修正公钥导入的内容截取逻辑
原代码的substring可能因PEM中的换行符导致截取错误,改为过滤所有非Base64字符:
async function importRsaKey(pem) { // 提取PEM中的Base64内容,过滤换行、空格等无关字符 const pemContents = pem.replace(/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\s/g, ''); // base64解码为二进制字符串 const binaryDerString = window.atob(pemContents); // 转换为ArrayBuffer const binaryDer = str2ab(binaryDerString); const key = await crypto.subtle.importKey( "spki", binaryDer, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"] ); return key; }
注:确保
str2ab函数正确将二进制字符串转为ArrayBuffer,标准实现如下:function str2ab(str) { const buf = new ArrayBuffer(str.length); const bufView = new Uint8Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; }
3. 确认后端解密参数一致性
后端的解密参数(RSA-OAEP、SHA-256)已与前端匹配,无需修改,但要确保settings.RSA_SECRET_KEY是生成公钥对应的私钥,且密钥未被篡改。
验证
修改后,前端加密后的密文Base64编码正确,后端解码后得到512字节的密文,即可正常解密。
内容的提问来源于stack exchange,提问作者ChrisD
相关产品推荐
相关产品推荐

