在PHP中解密一些我使用RSA在JS中加密的数据时遇到麻烦:
一些数据(32字节,对RSA来说足够短)在客户端使用JSEncrypt和服务器的公钥加密。
服务器使用:
openssl_private_decrypt(base64_decode($result_obj['data']), $decrypted, $pkcs_private_key);
但是这返回44字节,所以很明显这是错误的!我一个字节一个字节地检查过,似乎它几乎是在解密字符串的某些位置删除字节之后,但也不是那么简单。
我已经检查了填充openssl支持,它使用pkcs# 1v1.5type1,而JSEncrypt似乎使用pkcs# 1v1.5type2。这是问题所在吗?我见过使用pkcs# 1v1.5type2的openssl有问题的人,所以我怀疑它能够使用这个填充,但我不知道如何…任何帮助,感谢!
编辑:告诉更多关于加密系统的信息:
客户端加密的数据是一个32字节的数组。在这个例子中,我将使用数组[182、13、97、94、164、102、129、70、192、52、94、65、243、190、57、48、153、161、46、32、122、64、53、237、62、130、60、1、22、184、28、231]。
加密使用:
arr2str(arr: number[]): string {
var result = '';
for (var i = 0; i < arr.length; i++) {
result += String.fromCharCode(arr[i]);
}
return result;
}
encryptRSA(data: number[], key: string): string {
var enc = new window.JSEncrypt();
enc.setPublicKey(key);
return enc.encrypt(this.arr2str(data));
}
该密钥是由服务器私钥生成的pkcs# 1公钥。我们将使用键
-----BEGIN公钥-----'nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyJ824ZiwMiCMrrHrDq1IKLwL8'nQWg+ZzwMprrG85k0nxEB8ZJn+s2lXhS4pOE0Nu6I9XiXjtyDbnT8kQvaWLve593v'nDzC16wP9IKrAdmeV9CExMzKAHbFSvNTTn3TWjaKy9OnH+7Uv/VVn63AQZXaqvY/W'nbPVdTKn4Nx7vl+laOwIDAQAB'n-----结束公共密钥——
-----BEGIN RSA私钥----- MIICXAIBAAKBgQCyJ824ZiwMiCMrrHrDq1IKLwL8QWg+ZzwMprrG85k0nxEB8ZJn紫外线/VVn63AQZXaqvY/WbPVdTKn4Nx7vl + s2lXhS4pOE0Nu6I9XiXjtyDbnT8kQvaWLve593vDzC16wP9IKrAdmeV9CExMzKA HbFSvNTTn3TWjaKy9OnH + 7 + laOwIDAQABAoGASP3b4HgkBgJk/ojNR4vSsg9u1rFpp1 + ej8Rj9A1sMM4XJse151ovlVhFfx02k7EJ7B0 + ikHjAQppbe1zgMMoPUuDOQc9VF2A2Tsf71kMagbQpNrLNiTIu6DNwzHIivubmYBs73s2MyZmK7G8D/QRDs0qQNXdUfAKMBIUh9wQj0kCQQD5Urh18NWmW7w84 mdfmjdalsbe9dg38mfrlune0kscvwyx2zkoh/uc1eB + hqONwDkuw8VLTBgxDm + L7 jwolmivakeatu0uneewmhi1ocivros1n/UDqEHzuwFuxg + cNwAKJoN1ljqKIfqajFLGawkyHIK2fLhP8OSQeyDi3kSoIMJzjwJAT0737FRqsdt2emsIBxNyTjcpuPbytyE921uGvwDhg9GgAOI0QWdYK2CBY94SQrIFvpF5veT7wQcVho6GviEsLQJABGj7cC86RDDk0BOC6ERSzKRvjiLo6V1Demrt7TWHCR6qOxD2O5N7Hl7wgawbFSzhkWgwJTKdeRp13b3x/7 gwaqjbaopggkejkcwrfdamfyzwmgbueqkpqg/AmfNXblrOv70NCkB9YP3skoZ69 + vFr1TJXfz23lHpwQdPkRXhjlc/gl =-----结束RSA私钥-----
服务器接收这个加密的数据。看起来JSEncrypt b64_对它进行了编码,所以我们必须使用
进行解密openssl_private_decrypt (base64_decode ($ result_obj[‘数据’]),解密,pkcs_private_key美元);
然而,我收到字节数组:
[194、182、13、97、94、194、164、102、194、129、70、195、128、52、94、65、195、179、194、190、57、48、194、153、194、161、46、32、122、64、53、195、173、62、194、130、60、1、22、194、184、28、195、167].
也许这与JS的arr2str函数有关。然而,我看不出如何不使用它,因为JSEncrypt期望加密字符串。我认为这个函数没有修改字节…
为了示例的完整性,JSEncrypt返回编码后的数据:
E728nXaCUUSTzuGLB5QIkodddyUMUMR0rEM5Ad7qL3SEtGJVukMjsQt7NAaRyXz1P3n2qK/iBGcuUBy2bPg5pTwk1twVZc2BzXueZYcKxxOby8AkNTgF9YMPlh1FMjD5c0UAiwcb7DnykvbsulG4h + FlxEy + 28 emtfrvjzmpq + 4 =
这是openssl_private_decrypt尝试解密的内容
为了子孙后代,我发现了问题所在。实际上,它在于两个库之间的填充不兼容。
因此我在PHP中将解密模式设置为"no padding":
openssl_private_decrypt (base64_decode ($ result_obj[‘数据’]),$decrypted, $pkcs_private_key, OPENSSL_NO_PADDING);
我把在JS中完成的取消填充变成了PHP:
function pkcs1unpad2($b, $bits = 4096) {
$i = 0;
$n = ($bits + 7) >> 3;
$l = strlen($b);
while($i < $l && ord($b[$i]) == 0)
++$i;
if(ord($b[$i]) != 2)
return null;
++$i;
while(ord($b[$i]) != 0)
if(++$i >= $l)
return null;
$ret = "";
while(++$i < $l) {
$c = ord($b[$i]) & 255;
if($c < 128) {
$ret .= chr($c);
} elseif(($c > 191) && ($c < 224)) {
$ret .= chr((($c & 31) << 6) | (ord($b[$i+1]) & 63));
++$i;
} else {
$ret .= chr((($c & 15) << 12) | ((ord($b[$i+1]) & 63) << 6) | (ord($b[$i+2]) & 63));
$i += 2;
}
}
return $ret;
}
pcks1unpad2(解密)
是我所期望的!