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

西门艳丽 阅读 54

我用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切换。是不是密钥格式有问题?或者加密方式有差异?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
博主春荣
这个问题很典型,CryptoJS的RSA加密结果需要base64解码后才能给PHP解密。

前端代码没问题,但你要注意CryptoJS的RSA.encrypt返回的是WordArray对象,.toString()得到的是base64编码的字符串。PHP那边得先解码再解密。

后端PHP代码改成这样:

// 接收前端传来的base64字符串
$encryptedData = $_POST['data']; // 或者从请求中获取

// 先base64解码
$encrypted = base64_decode($encryptedData);

// 读取私钥
$privateKey = openssl_pkey_get_private(file_get_contents('private.pem'));

// 解密
$decrypted = '';
openssl_private_decrypt($encrypted, $decrypted, $privateKey, OPENSSL_PKCS1_PADDING);

echo $decrypted;


关键点:openssl_private_decrypt第二个参数是输出参数,不是返回值。

如果还是报错,检查一下公钥格式是否正确。CryptoJS需要标准的PEM格式公钥:

const publicKey = -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw5Z...
-----END PUBLIC KEY-----
;


注意换行和横线都要有,不能是单行。

另外提醒一下,CryptoJS的RSA加密有长度限制,不能加密太长的内容。一般最多只能加密 密钥长度/8 - 11 字节,比如2048位密钥最多加密245字节左右的内容。如果要加密长数据,建议用AES加密数据,然后RSA只加密AES的密钥。
点赞
2026-03-18 20:14
司徒子源
这个问题的核心在于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命令)验证一下密钥对是否匹配。

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