我正在生成以下字符串的SHA256
{
"billerid": "MAHA00000MUM01",
"authenticators":
[
{
"parameter_name": "CA Number",
"value": "210000336768"
}
],
"customer":
{
"firstname": "ABC",
"lastname": "XYZ",
"mobile": "9344895862",
"mobile_alt": "9859585525",
"email": "abc@billdesk.com",
"email_alt": "abc2@billdesk.com",
"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 计算以上字符串的SHA256:053353867b8171a8949065500d7313c69fe7517c9d69eaff11164c35fcb14457
此网站(https://emn178.github.io/online-tools/sha256.html)将SHA256命名为eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253
我正在使用Javascript中的CryptoJs库计算SHA256,这也为eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253提供了此结果。
我希望计算的SHA256为:053353867b8171a8949065500d7313c69fe7517c9d69eaff11164c35fcb14457
为什么这些在不同位置的SHA256计算有区别?
答案 0 :(得分:4)
您遇到的问题是由于 encoding 差异造成的。相同字符串的编码可能产生不同结果的原因有很多:
还有可能导致不同结果的不可见错误:
0x00
可能是最好的示例); 除了任何(结构化)文本可能存在的所有这些差异之外,JSON数据结构还可以具有等效的值。最好的例子可能是数字前的+
前导字符。这完全是虚假的,但仍会导致不同的文本表示形式,但数字的值相同。
如果字符串的编码不同,则哈希算法的二进制输入也不同,对于普通的密码哈希,您得到的结果相差约50%。产生相同输入的方法称为规范化(或C14N,因为规范化的C和N之间有14个字符)。
很早以前就为XML定义了canonical form。对于JSON并非如此,即使JSON的规范化要容易得多。毕竟,JSON具有较少复杂的规则集。有尝试规范化JSON,请参见例如this draft RFC明确提到密码哈希:
顺便说一下,例如,当加密散列应用于JSON时 文档,单个物理表示形式允许哈希 通过消除以下内容中的差异来表示文档的逻辑内容 内容如何以JSON编码。
This draft RFC看起来更全面。
现在您可以保留RFC草案之一。如果要保留换行符,则可以使用这些定义良好的规则来序列化JSON,并将其用作哈希函数的输入,同时保持JSON本身不变。这样,格式不同的 JSON仍会生成相同的哈希。
[Input JSON] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value]
[Input JSON'] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value']
如果Input JSON
和Input JSON'
在结构/语义上相同,则哈希输出将是相同的,因为规范化将消除差异。
请注意,JSON Web签名(JWS)方面解决了此问题。签名毕竟在内部使用哈希。签名位于包含的有效负载上,并且仅使用该有效负载的编码。只要中间系统不重新编码JSON,就可以了。签名不必相同,它们只需要验证数据即可。
不幸的是,散列并非如此。但是,实际上,您可以将JSON定义为文件并使用相同的推理。缺点当然是如果得到差异,则必须执行二进制比较以找到差异,然后追溯引入变更的位置。在语义相同的情况下(例如,在替换或更新JSON库时),工作系统可能会破坏哈希。