【问题标题】:How does jwt implement RSA256 signature verification in nodejsjwt如何在nodejs中实现RSA256签名验证
【发布时间】:2020-12-14 08:43:02
【问题描述】:

我试图了解 JWT 如何执行 RS256 签名验证的内部工作原理。签名算法的工作原理如下:

  1. 散列原始数据
  2. 使用 RSA 私钥加密哈希

为了验证它遵循以下步骤:

  1. 使用 RSA 公钥解密
  2. 将解密生成的哈希与原始消息的 SHA256 哈希匹配。

在尝试在其中一个 jwt 上进行测试时 eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA

我发现从签名中获得的哈希包含一些额外的字符。 例如。上述 jwt 十六进制编码的情况下,原始消息的 SHA256 是

8041fb8cba9e4f8cc1483790b05262841f27fdcb211bc039ddf8864374db5f53

但是上面jwt的签名解密后得到的hash是 3031300d0609608648016503040201050004208041fb8cba9e4f8cc1483790b05262841f27fdcb211bc039ddf8864374db5f53

在哈希前面有3031300d060960864801650304020105000420 额外字符。

这些字符代表什么,从消息和签名中获得的哈希值不应该相同吗?

【问题讨论】:

    标签: node.js cryptography jwt rsa digital-signature


    【解决方案1】:

    rfc7518 3.3 定义 JWS 算法 RS256,384,512:

       This section defines the use of the RSASSA-PKCS1-v1_5 digital
       signature algorithm as defined in Section 8.2 of RFC 3447 [RFC3447]
       (commonly known as PKCS #1), using SHA-2 [SHS] hash functions.
    

    rfc3447 8.2 定义了 RASS-PKCS1-v1_5

       RSASSA-PKCS1-v1_5 combines the RSASP1 and RSAVP1 primitives with the
       EMSA-PKCS1-v1_5 encoding method.   ....
    

    EMSA-PKCS1-v1_5 在rfc3447 9.2 中定义为:

       1. Apply the hash function to the message M to produce a hash value
          H:
    
             H = Hash(M).
    
          If the hash function outputs "message too long," output "message
          too long" and stop.
    
       2. Encode the algorithm ID for the hash function and the hash value
          into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
          the Distinguished Encoding Rules (DER), where the type DigestInfo
          has the syntax
    
          DigestInfo ::= SEQUENCE {
              digestAlgorithm AlgorithmIdentifier,
              digest OCTET STRING
          }
    
          The first field identifies the hash function and the second
          contains the hash value.  Let T be the DER encoding of the
          DigestInfo value (see the notes below) and let tLen be the length
          in octets of T.
    
       3. If emLen < tLen + 11, output "intended encoded message length too
          short" and stop.
    
       4. Generate an octet string PS consisting of emLen - tLen - 3 octets
          with hexadecimal value 0xff.  The length of PS will be at least 8
          octets.
    
       5. Concatenate PS, the DER encoding T, and other padding to form the
          encoded message EM as
    
             EM = 0x00 || 0x01 || PS || 0x00 || T.
    
       6. Output EM. [added: which is then modexp'ed with d by RSASP1 to
       sign, or matched to the value modexp'ed with e by RSAVP1 to verify]
    
       Notes.
    
       1. For the six hash functions mentioned in Appendix B.1, the DER
          encoding T of the DigestInfo value is equal to the following:
    
          MD2:     (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04
                       10 || H.
          MD5:     (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04
                       10 || H.
          SHA-1:   (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H.
          SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
                       04 20 || H.
          SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00
                       04 30 || H.
          SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00
                          04 40 || H.
    

    正如预期的那样,您发现的前缀与注释 1 中为 SHA-256 哈希的 DigestInfo 结构的第 2 步中指定的编码完全对应。

    注意 rfc3447=PKCS1v2.1 已被 rfc8017=PKCS1v2.2 取代,但该领域唯一相关的变化是添加了 JWS 不使用的 SHA512/224 和 SHA512/256 哈希。

    将签名和验证描述为“加密”和“解密”哈希(实际上,编码也就是哈希的填充)被认为是过时的。它最初是在几十年前使用的,并且仅用于 RSA 而不是其他签名算法,因为用于加密和解密与签名和验证的 modexp 操作之间的数学相似性,但发现将这些视为相同或可互换的结果在易受攻击和损坏的系统实现中。具体见rfc3447 5.2:

       The main mathematical operation in each primitive is
       exponentiation, as in the encryption and decryption primitives of
       Section 5.1.  RSASP1 and RSAVP1 are the same as RSADP and RSAEP
       except for the names of their input and output arguments; they are
       distinguished as they are intended for different purposes.
    

    nodejs 使用这个过时的术语,因为它使用 OpenSSL,它的前身 SSLeay 可以追溯到 1990 年代初期,当时这个错误仍然很常见。 然而,这并不是一个真正的编程/开发问题,更多的是关于 crypto.SX 和 security.SX 的主题;查看我在https://security.stackexchange.com/questions/159282/can-openssl-decrypt-the-encrypted-signature-in-an-amazon-alexa-request#159289 收集的一些链接。

    【讨论】:

    • 谢谢@dave_thompson_085。这真的很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2018-12-27
    • 2014-05-29
    • 2018-12-13
    • 2016-07-10
    • 2017-06-20
    • 2016-08-28
    • 2019-11-14
    相关资源
    最近更新 更多