前端JS(window.crypto)与后端Python(pycryptodome) RSA加密解密不兼容问题
RSA前端window.crypto加密后后端PyCryptodome无法解密的排查方案
结合你提到的后端自加密能正常解密、传输无异常的情况,问题大概率出在前后端加密解密的参数不匹配上,以下是针对性的排查点和解决方案:
1. 填充算法必须完全一致
前端window.crypto.subtle.encrypt默认使用RSA-OAEP填充,如果你后端解密用了PKCS1_v1_5,必然会失败。要确保两端填充算法统一:
- 前端明确指定填充配置:
async function encryptWithRSA(publicKey, plainText) { const encoder = new TextEncoder(); const data = encoder.encode(plainText); const encryptedBuffer = await window.crypto.subtle.encrypt( { name: "RSA-OAEP", hash: "SHA-256" // 同时明确哈希算法 }, publicKey, data ); // 转base64方便传输 return btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer))); } - 后端对应使用
PKCS1_OAEP解密:from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP from Crypto.Hash import SHA256 import base64 def decryptWithRSA(privateKeyPem, encryptedB64): privateKey = RSA.import_key(privateKeyPem) # 匹配前端的SHA-256哈希算法 cipher = PKCS1_OAEP.new(privateKey, hashAlgo=SHA256) encryptedData = base64.b64decode(encryptedB64) decryptedBytes = cipher.decrypt(encryptedData) return decryptedBytes.decode('utf-8')
2. 密钥格式与导入方式要匹配
前端导入公钥和后端加载密钥的格式必须对应:
- 前端如果从PEM格式公钥导入,要先去除头部、尾部和换行,转成ArrayBuffer:
async function importPublicKey(pem) { // 清理PEM格式的冗余内容 const cleanPem = pem.replace(/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\n/g, ''); const binaryDer = Uint8Array.from(atob(cleanPem), c => c.charCodeAt(0)); return window.crypto.subtle.importKey( "spki", binaryDer, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"] ); } - 后端直接用
RSA.import_key()加载PEM格式密钥即可,无需额外处理。
3. 明文处理与长度限制
- 前端加密前必须将字符串转成
ArrayBuffer(用TextEncoder),后端解密后要将字节数组转回字符串(用decode('utf-8'))。 - 注意RSA加密的明文长度限制:以2048位密钥+SHA-256为例,最大明文长度是
256 - 2*32 - 2 = 190字节,超过这个长度必须分段加密,或者改用「RSA加密对称密钥+对称密钥加密大文本」的混合加密方案。
4. 哈希算法必须匹配
前端RSA-OAEP配置的哈希算法(比如SHA-1/SHA-256)要和后端解密时指定的完全一致,不能一端用SHA-256,另一端用SHA-1。
内容的提问来源于stack exchange,提问作者7086cmd
相关产品推荐
相关产品推荐

