如何像在 1.0 版中那样使用 PHPSeclib 2.0 版获取签名字符串?

How can I use version 2.0 of PHPSeclib to get a signed string as I did in version 1.0?

我参与的一个项目中,一位队友添加了 phpseclib (for php5),我们使用下面的代码对加密字符串进行签名,并将其与请求一起发送到内部 API 以进行验证过程。

function GetSignature($message) {
    $rsa = new Crypt_RSA();
    $sPath = PRIVATE_KEY_FILE; //defined elsewhere
    $sKey = file_get_contents($sPath);
    $rsa->LoadKey($sKey);
    $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
    return $rsa->sign($message);
};

对于包含与 URL 连接的时间戳的字符串(例如 1490239371+https://api-domain/api/endpoint),将生成如下所示的字符串。此字符串在请求 header 中发送,下面的字符串是内部 API 的控制台日志中的输出。

Rsh1dv5ZGaPjCb6pgEsMrXwZbAeVgxVK/+5d5bxu7BfDzaILl++/pi/WxDP4H2qJ7Ayp6QnYXGckIIYX9l9fKOJoShOZOkB19RxaNdBL5vLjKk409XVRY/GKGz3kHmZmTcyBYDPQaT/VFOQTd7+o0d1mBY4EbHadI3f+kahHz4U=

在一个较新的项目中,我试图重新创建它,因为我们需要利用相同的内部 API。较新的项目正在使用 composer(和 laravel),因此向其添加了 phpseclib version 2.0。常量已更改为 class 常量,但除此之外,方法似乎是相同的。下面是我添加的代码,用于在另一个代码库中复制以前的代码。

use phpseclib\Crypt\RSA as Crypt_RSA;
class EncyptionController {

    public static function GetSignature($message) {
        $rsa = new Crypt_RSA(); 
        $path = config('app.encryption_key_path') . '/certs/private.pem';
        $rsa->loadKey(file_get_contents($path));
        $rsa->setSignatureMode(Crypt_RSA::SIGNATURE_PKCS1);
        return $rsa->sign($message); 
    }

使用较新的代码,相同格式的字符串将生成包含 unicode 字符的加密字符串。下面的字符串出现在内部 API 的控制台日志中(当记录在请求 headers 中收到的值时)。

=���˭\u0003�uʂ\u000e_\u0013\u000bd)w�8�\u0018�����q

在 Laravels 日志中记录显示它带有 unicode 字符(没有编码的实体 - 我在 notepad++ 中打开它):

=žšîË­´uÊ‚_d)wË8ƒ”ñ‘¤úqýÁ‹þ:‹dºäÿLÈ?!F§?…ãIEìê*K®gUþèÎÅ

然后内部 API 使用 public 密钥解密编码的字符串。对于较新的代码库,这会失败。内部API在Nginx/NodeJS中实现,使用crypto and its verifier.verify()方法。

更新:

基于 by Álvaro González, it has come to light that the version 2.0 sign() method returns a raw binary hash. I can use base64_encode()对其进行base-64编码,但该字符串(88个字符)比1.0版本生成的字符串(172个字符)短很多。

return base64_encode($rsa->sign($message));

版本 1.0 字符串 - 172 个字符长:

Rsh1dv5ZGaPjCb6pgEsMrXwZbAeVgxVK/+5d5bxu7BfDzaILl++/pi/WxDP4H2qJ7Ayp6QnYXGckIIYX9l9fKOJoShOZOkB19RxaNdBL5vLjKk409XVRY/GKGz3kHmZmTcyBYDPQaT/VFOQTd7+o0d1mBY4EbHadI3f+kahHz4U=' "Rsh1dv5ZGaPjCb6pgEsMrXwZbAeVgxVK/+5d5bxu7BfDzaILl++/pi/WxDP4H2qJ7Ayp6QnYXGckIIYX9l9fKOJoShOZOkB19RxaNdBL5vLjKk409XVRY/GKGz3kHmZmTcyBYDPQaT/VFOQTd7+o0d1mBY4EbHadI3f+kahHz4U=

2.0 版字符串 - 88 个字符长:

mYT/MSb9UOuDDQ1RV893Ix7xh21IRHINs6o1PnhdhffgTAIeX4le1rfd+EzoPPJN9pvvwirm3CAbkeubGjXgWQ==

有没有设置签名字符串长度的方法?

在 v2.0 中是 RSA(),而不是 Crypt_RSA()。 http://phpseclib.sourceforge.net/2.0.html 详细说明。

无论如何,在 base64 中解码你的两个密文,然后得到每个的长度...第一个(由 phpseclib-php5 生成的)我得到 256 字节或 2048 位。第二个(phpseclib 2.0产生的那个)是64字节512位

我认为您为每个密钥使用了不同长度的不同密钥,这肯定会影响长度。