PHP用JS生成的RSA-OAEP公钥加密后JS解密失败求助
RSA-OAEP解密失败:DOMException排查与修复
问题根源
你遇到的解密错误,核心原因是加密和解密两端的RSA-OAEP哈希算法不匹配:
- 前端生成密钥及解密时,明确指定了SHA-256作为哈希算法
- PHP端使用
openssl_public_encrypt搭配OPENSSL_PKCS1_OAEP_PADDING时,默认采用SHA-1哈希算法
这种不一致会导致解密过程验证失败,抛出DOMException。
解决方案
1. 修正PHP端加密逻辑,指定SHA-256哈希
PHP的openssl_public_encrypt无法直接指定OAEP的哈希算法,需要改用更灵活的openssl_pkey_encrypt函数,并通过配置项明确指定SHA-256:
$pbkey = "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA52N7Q/kQxNrVaGCLOlD0IgrSROPWt029GTqRKMdFQSFMAZPD0V5TZPLDylbtmvLhDajKugYpjHfDGD44cXiYy1jZeVCiFas09gAGBKmgFY4Ixsl/+opF2hlPjvnugn2aPKpSLgoX9f1DpXBDEpuHJ+AVSTxL+C3uE1PgQPYy2ots15Km4W2AnV+p81UfLdafStQ40gbkUOHvzFkwizazm4q1Scjh2Fc+RR6FXy+ySp54yuRqHuMS8QTdXVMBChqs5lNwuu6V+BEryXMFbDx2fW9qCWShVTc2lq4KzvXRE/65L0sttMA7oP/WzsVW3zeNFgla8g4dxvCftwrwGviMay9N+vsa902TClR2xj7/JSzQXSW0E4Am4ZB4bCJh04f08M0nMBY6yWWV3+QpBG+9CeXHfwPrdqT2OR5N7Jq+xslCfbf4D/9itjDdvaBZP5Z6BYiOF3QzeTk+V2rfAWZdOUcuWAdP3gczQKdJM11bTxOKNCiYmBu773aDXCNFpaHDatqUgnNrVp7guOP1owOdd7qxWsplzylQUcWuhuWczs7/X/UPwT7vBTkg0pb8Ujrr+KyNmsxsJTefg1z4xcbxtgqgoDRxXu92V9iVl1HVssAM8IZdc+naEIyOjt+3OPZkaCwts38U7nYUDd96ovHjMs0hFlTxqsltwyfPFAVygLUCAwEAAQ==\n-----END PUBLIC KEY-----"; // 解析公钥 $publicKey = openssl_pkey_get_public($pbkey); if (!$publicKey) { die("公钥解析失败: " . openssl_error_string()); } // 配置OAEP参数,指定SHA-256哈希 $encryptOptions = [ 'oaep' => [ 'digest' => 'sha256' ] ]; $plaintext = "secret"; $encrypted = ''; // 执行加密 if (!openssl_pkey_encrypt($plaintext, $encrypted, $publicKey, $encryptOptions)) { die("加密失败: " . openssl_error_string()); } echo base64_encode($encrypted); // 释放资源 openssl_pkey_free($publicKey);
2. 确保前端辅助函数正确性
你的代码中用到了ab2str和str2ab但未给出实现,这两个函数的错误会导致编码/解码异常,正确实现如下:
// ArrayBuffer转字符串 function ab2str(buffer) { return new TextDecoder().decode(buffer); } // 字符串转ArrayBuffer function str2ab(str) { return new TextEncoder().encode(str); }
3. 优化前端解密函数(可选)
解密后返回的是ArrayBuffer,需要转换为字符串才能得到原始明文,修改Decrypt函数:
async function Decrypt(message) { const keys = GetKeys(); let pemPvKey = keys[0]; const pvkey = await window.crypto.subtle.importKey( "pkcs8", str2ab(window.atob(FormatPrivateKey(pemPvKey))), { name: "RSA-OAEP", hash: {name: "SHA-256"} }, false, ["decrypt"] ); const decryptedBuffer = await window.crypto.subtle.decrypt( { name: "RSA-OAEP" }, pvkey, str2ab(window.atob(message)) ); // 转换为明文字符串 return ab2str(decryptedBuffer); }
关键注意事项
- RSA-OAEP的哈希算法、密钥长度必须在加密/解密两端完全一致
- 避免使用
openssl_public_encrypt的默认OAEP配置,始终显式指定哈希算法 - 确保密钥的导出、存储、导入过程中没有出现编码或格式错误
内容的提问来源于stack exchange,提问作者user20117556
相关产品推荐
相关产品推荐

