前端用CryptoJS RSA加密后服务端解密报padding错误怎么办?

西门艳丽 阅读 23

我用CryptoJS的RSA.encrypt加密字符串,传到PHP服务端用openssl_private_decrypt解密时一直报错”error:0407106B:RSA routines:RSA_padding_check_PKCS1_type_1:number too small”。前后端都用了PKCS1Padding,密钥对是用openssl生成的,前端用的是PEM格式公钥,后端私钥是.pem文件直接读取的。试过base64编码解码都不行,加密后的数据是这样的:Tk1aQzJFQjA...

// 前端加密代码
const encrypted = CryptoJS.RSA.encrypt(
  message,
  publicKey,
  {padding: CryptoJS.pad.Pkcs1Padding}
).toString();

服务端PHP直接用了官方示例代码,参数都试过true/false切换。是不是密钥格式有问题?或者加密方式有差异?

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
司徒子源
这个问题的核心在于CryptoJS的RSA实现和OpenSSL的RSA处理方式存在差异。CryptoJS库默认会对数据进行Base64编码,而PHP这边用openssl_private_decrypt解密时,默认接收的是二进制格式的数据,这会导致填充模式不匹配。

调试看看,问题出在前端加密后的数据格式上。CryptoJS.RSA.encrypt返回的结果是Base64编码的字符串,而PHP的openssl_private_decrypt需要的是原始的二进制数据。所以你需要在服务端解密前,先把接收到的数据从Base64转回二进制。

解决方案分两步走:

第一步,前端代码不用改太多,但要确保加密后的结果确实是Base64编码的。你的前端代码看起来没问题,加密后调用toString()已经是Base64了。

第二步,服务端PHP解密时,先对接收到的数据做Base64解码,然后再传给openssl_private_decrypt。代码可以这么写:


$encryptedData = $_POST['encrypted']; // 假设从前端接收到的数据
$binaryData = base64_decode($encryptedData); // 转换为二进制数据

$privateKey = file_get_contents('path/to/private_key.pem');
$success = openssl_private_decrypt($binaryData, $decrypted, $privateKey, OPENSSL_PKCS1_PADDING);

if ($success) {
echo "解密成功: " . $decrypted;
} else {
echo "解密失败";
}


另外,建议你确认一下公钥和私钥的格式是否正确。前端用的公钥必须是PEM格式的,并且去掉换行符或特殊字符后再使用。如果还是有问题,可以用工具(比如OpenSSL命令)验证一下密钥对是否匹配。

调试这种跨语言加密解密问题挺烦人的,尤其是填充模式和数据格式不一致的时候。按上面的方法调整一下,应该就能解决问题了。
点赞 1
2026-02-16 19:06