【问题标题】:OpenSSL decrypt JSBN encryptedOpenSSL 解密 JSBN 加密
【发布时间】:2017-01-14 08:32:27
【问题描述】:

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

一些数据(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 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= -----结束 RSA 私钥-----

服务器接收此加密数据。看来 JSEncrypt b64_encodes 了它,所以我们必须使用来解密

openssl_private_decrypt(base64_decode($result_obj['data']), $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+Flx

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

【问题讨论】:

  • base64_decode($decrypted) 产生一个长度为 6 的字符串,遗憾的是,它的字节甚至不是我要寻找的第一个字节。但也许你的意思是别的?
  • 好吧,我已经检查了 strlen,以及返回长度为 6 的数组的 unpack("C*", $decrypted),并允许我检查每个字节的字节
  • 我期望的字节数:[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],我收到的那个:[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]
  • 并且count返回但数字1,我​​想它会查找数组的维数。
  • 已编辑。已经谢谢了

标签: php openssl rsa


【解决方案1】:

为了后人,我发现了问题。 实际上,它在于两个库之间的填充不兼容。

因此我在 PHP 中将解密模式设置为“无填充”:

openssl_private_decrypt(base64_decode($result_obj['data']), $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($解密)

是我所期望的!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多