【问题标题】:How can I use version 2.0 of PHPSeclib to get a signed string as I did in version 1.0?如何使用 PHPSeclib 2.0 版来获取签名字符串,就像我在 1.0 版中所做的那样?
【发布时间】:2017-08-15 11:18:44
【问题描述】:

在我参与的一个项目中,一位队友添加了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),将生成如下所示的字符串。此字符串在请求标头中发送,下面的字符串是内部 API 控制台日志中的输出。

Rsh1dv5ZGaPjCb6pgEsMrXwZbAeVgxVK / + 5d5bxu7BfDzaILl ++ / PI / WxDP4H2qJ7Ayp6QnYXGckIIYX9l9fKOJoShOZOkB19RxaNdBL5vLjKk409XVRY / GKGz3kHmZmTcyBYDPQaT / VFOQTd7 + o0d1mBY4EbHadI3f + kahHz4U = EM>

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

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 的控制台日志中(在记录请求标头中收到的值时)。

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

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

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

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

更新:

基于Álvaro Gonzálezthe comment,发现2.0 版sign() 方法返回原始二进制哈希。我可以使用base64_encode() 对其进行base-64 编码,但该字符串比1.0 版生成的字符串(172 个字符)短很多(88 个字符)。

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 = P>

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

mYT/MSb9UOuDDQ1RV893Ix7xh21IRHINs6o1PnhdhffgTAIeX4le1rfd+EzoPPJN9pvvwirm3CAbkeubGjXgWQ==

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

【问题讨论】:

  • 你是如何打印这个的?当您将输出写入文件并在“好”的编辑器中打开它时,您是否看到同样的问题?
  • 好问题@ArtjomB。我更新了帖子以包含该信息。原始字符串通过 console.log() 写入 nginx 的日志。我将新代码库中的输出包含到 laravel 的日志中(并在 notepad++ 中打开日志)。
  • @SamOnela 这与 Unicode 无关(Unicode 的全部目的是处理文本,这显然是二进制数据)。在 v1 中,您得到了一个编码为 base64 的哈希值。在 v2 中,您将获得原始二进制哈希。正如他们警告的那样,v2 API 不是最终版本,在 v3 之前可能随时更改。您应该首先比较两个哈希值,看看它们是否相同。
  • 感谢@Álvaro González 指出这一点。在手动对原始哈希进行 base-64 编码后,我更新了问题以处理不同的字符串长度...

标签: php rsa phpseclib encryption-asymmetric


【解决方案1】:

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

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

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

【讨论】:

  • 抱歉,我忘了提及我使用了namespace alias 来表示RSA as Crypt_RSA,以试图使其更接近现有代码。我为此更新了我的帖子。我检查了密钥并尝试使用与旧项目中相同的密钥文件。我还意识到我没有以相同的方式来制定消息(即没有将时间戳转换为字符串,并附加了请求路径的额外部分)。现在它按预期工作。感谢您的指导!
猜你喜欢
  • 2015-12-24
  • 1970-01-01
  • 2014-09-08
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多