OpenSSL解密JSBN加密

时间:2016-09-06 19:33:13

标签: php openssl rsa

我在PHP中使用RSA解密了一些我在JS中加密的数据时遇到了麻烦:

一些数据(32字节,RSA足够短)是使用JSEncrypt加密的客户端和服务器的公钥。

服务器使用以下方法对其进行解密:

  

openssl_private_decrypt(base64_decode($ result_obj [' data']),$ decrypted,$ pkcs_private_key);

但这会返回44字节,所以很明显这是错误的!我已经逐字节检查了,似乎它几乎是在解密字符串中的某些位置删除字节,但不是那么简单。

我检查了padding openssl支持,它使用PKCS#1v1.5type1,而JSEncrypt似乎使用PKCS#1v1.5type2。可能是问题吗?我见过那些使用PKCS#1v1.5type2遇到openssl问题的人,所以Isuspect能够使用这个填充,但我无法弄清楚如何......任何帮助都赞赏!

编辑:要详细了解加密系统:

加密客户端的数据是一个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 PUBLIC KEY ----- \ nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyJ824ZiwMiCMrrHrDq1IKLwL8 \ nQWg + ZzwMprrG85k0nxEB8ZJn + s2lXhS4pOE0Nu6I9XiXjtyDbnT8kQvaWLve593v \ nDzC16wP9IKrAdmeV9CExMzKAHbFSvNTTn3TWjaKy9OnH + 7Uv / VVn63AQZXaqvY / W \ nbPVdTKn4Nx7vl + laOwIDAQAB \ n ----- END   公钥-----

     

-----开始RSA私钥----- MIICXAIBAAKBgQCyJ824ZiwMiCMrrHrDq1IKLwL8QWg + ZzwMprrG85k0nxEB8ZJn   + s2lXhS4pOE0Nu6I9XiXjtyDbnT8kQvaWLve593vDzC16wP9IKrAdmeV9CExMzKA HbFSvNTTn3TWjaKy9OnH + 7Uv / VVn63AQZXaqvY / WbPVdTKn4Nx7vl + laOwIDAQAB   AoGASP3b4HgkBgJk / ojNR4vSsg9u1rFpp1 + ej8Rj9A1sMM4XJse151ovlVhFfx02   k7EJ7B0 + ikHjAQppbe1zgMMoPUuDOQc9VF2A2Tsf71kMagbQpNrLNiTIu6DNwzHI   ivubmYBs73s2MyZmK7G8D / QRDs0qQNXdUfAKMBIUh9wQj0kCQQD5Urh18NWmW7w8   4MDFmjdalSbE9Dg38mfrlUne0KSCvwyX2zkoh / uc1eB + hqONwDkuw8VLTBgxDm + L   7jwOlmiVAkEAtu0uNEewMHi1oCIvRoS1n / UDqEHzuwFuxg + cNwAKJoN1ljqKIfqa   jFLGawkyHIK2fLhP8OSQeyDi3kSoIMJzjwJAT0737FRqsdt2emsIBxNyTjcpuPby   tyE921uGvwDhg9GgAOI0QWdYK2CBY94SQrIFvpF5veT7wQcVho6GviEsLQJABGj7   cC86RDDk0BOC6ERSzKRvjiLo6V1Demrt7TWHCR6qOxD2O5N7Hl7wgawbFSzhkWgw   JTKdeRp13b3x / 7gwaQJBAOpgGkEJKcwRFdamFYZwMGbueqkpqG / AmfNXblrOv70N   CkB9YP3skoZ69 + vFr1TJXfz23lHpwQdPkRXhjlc / GLS =   ----- END RSA私钥-----

服务器接收此加密数据。似乎JSEncrypt b64_encodes它,所以我们必须使用

解密
  

openssl_private_decrypt(BASE64_DECODE($ result_obj [&#39;数据&#39;]),   $ decrypted,$ 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 + 28eMTfRvjZmpq + 4 =

这就是openssl_private_decrypt尝试解密的内容。

1 个答案:

答案 0 :(得分:2)

对于子孙后代,我发现了问题。 实际上,它存在于两个库之间不兼容的填充中。

因此我将解密模式设置为&#34;无填充&#34;用PHP:

  

openssl_private_decrypt(BASE64_DECODE($ result_obj [&#39;数据&#39;]),   $ decrypted,$ pkcs_private_key,OPENSSL_NO_PADDING);

我已经在PHP中用JS完成了unpadding:

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($解密)

是我的期望!