同一字符串的 SHA256 不同值

2024-02-12

我正在生成以下字符串的 SHA256

{
    "billerid": "MAHA00000MUM01",
    "authenticators": 
    [
        {
            "parameter_name": "CA Number",
            "value": "210000336768"
        }
    ],
    "customer": 
    {
        "firstname": "ABC",
        "lastname": "XYZ",
        "mobile": "9344895862",
        "mobile_alt": "9859585525",
        "email": "[email protected] /cdn-cgi/l/email-protection",
        "email_alt": "[email protected] /cdn-cgi/l/email-protection",
        "pan": "BZABC1234L",
        "aadhaar": "123123123123"
    },
    "metadata": 
    {
        "agent": 
        {
            "agentid": "DC01DC31MOB528199558"
        },
        "device": 
        {
            "init_channel": "Mobile",
            "ip": "124.124.1.1",
            "imei": "490154203237518",
            "os": "Android",
            "app": "AGENTAPP"
        }
    },
    "risk":
    [
        {
          "score_provider": "DC31",
          "score_value": "030",
          "score_type": "TXNRISK"
        },
        {
          "score_provider": "BBPS",
          "score_value": "030",
          "score_type": "TXNRISK"
        }
    ]
}

我从不同的来源获得不同的 SHA256 输出。 这个网站:https://www.freeformatter.com/sha256-generator.html#ad-output https://www.freeformatter.com/sha256-generator.html#ad-output计算上述字符串的 SHA256:053353867b8171a8949065500d7313c69fe7517c9d69eaff11164c35fcb14457

本网站(https://emn178.github.io/online-tools/sha256.html https://emn178.github.io/online-tools/sha256.html)给出 SHA256 作为 eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253

我在Javascript中使用CryptoJs库来计算SHA256,这也给出了eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253这个结果。

我希望 SHA256 计算为: 053353867b8171a8949065500d7313c69fe7517c9d69eaff11164c35fcb14457

为什么不同地方的 SHA256 计算存在差异?


您遇到的问题是由于encoding差异。同一字符串的编码可能产生不同结果的原因有多种:

  • 不同的行结尾(Windows 为 CR/LF,Linux 为 LF,经典 MacOS 为 CR);
  • 空白中的其他差异(制表符或空格、行结尾中的空白);
  • 不同的字符编码(Windows-1252、UTF-8 和 UTF-16 或internal语言实现中的字符表示);
  • 元信息的存在(字节顺序标记的存在);
  • 处理编码中特殊字符的不同方式(后跟组合波形符的字符以及带有组合波形符的字符,请参阅Unicode 等效项 https://en.wikipedia.org/wiki/Unicode_equivalence);

还可能存在一些看不见的错误,这些错误可能会产生不同的结果:

  • 存在不可打印的字符/控制代码(空值,0x00,在字符串末尾可能是最好的例子);

除了任何(结构化)文本可能存在的所有这些差异之外,JSON 数据结构也可以具有等效的值。最好的例子可能是领先的+数字前面的字符。这完全是虚假的,但仍然会导致不同的文本表示,但数字值相同。


如果字符串的编码不同,则哈希算法的二进制输入也会不同,并且您将得到的结果与常见加密哈希的位相差大约 50%。产生相同输入的方法称为规范化(或 C14N,因为规范化的 C 和 N 之间有 14 个字符)。

对于 XML规范形式 https://en.wikipedia.org/wiki/Canonical_XML很久以前就已经定义了。对于 JSON 来说情况并非如此,尽管 JSON 的规范化会容易得多。毕竟 JSON 的规则集要简单得多。有人尝试将 JSON 规范化,请参见例如本 RFC 草案 https://datatracker.ietf.org/doc/html/draft-staykov-hu-json-canonical-form-00明确提到加密哈希:

例如,当加密哈希应用于 JSON 时 文档,单个物理表示允许散列 通过消除变化来表示文档的逻辑内容 该内容如何以 JSON 进行编码。

本 RFC 草案 https://datatracker.ietf.org/doc/html/draft-rundgren-json-canonicalization-scheme-01顺便说一句,看起来更彻底一些。


现在您可以保留其中一份 RFC 草案。如果您想保留换行符,那么您可以使用这些定义明确的规则序列化 JSON,并将其用作哈希函数的输入,同时保持 JSON 本身不变。那样的话就不一样了格式化的JSON 仍会生成相同的哈希值。

[Input JSON] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value]
[Input JSON'] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value']

这里的哈希输出将是相同的,如果Input JSON and Input JSON'在结构/语义上是相同的,因为规范化会消除差异。


请注意,JSON Web 签名 (JWS) 回避了此问题。毕竟签名在内部使用哈希。签名位于包含的有效负载上,并且简单地使用该有效负载的编码。只要中间系统不重新编码 JSON 就可以了。签名不必相同,只需验证数据即可。

不幸的是,哈希值的情况并非如此。但是,实际上,您可以将 JSON 定义为文件并使用相同的推理。缺点当然是if如果你得到了差异,你将必须执行二进制比较来找到差异,然后追溯到引入更改的位置。工作系统可能会破坏哈希值,而语义仍然相同(例如,当替换或更新 JSON 库时)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

同一字符串的 SHA256 不同值 的相关文章

随机推荐