Javascript 和 Python 中哈希的区别

Difference between hashing in Javascript and Python

(有一些非常相似的帖子 - 我读过它们,解决方案似乎主要是关于 Python 字符串编码,我认为我已经控制住了但显然仍然没有)

我正在尝试将 NPM 包移植到 Python,但我无法从每个脚本中获得相同的结果。我已将其简化为:

import sys
import hashlib
from binascii import hexlify
print("Python", sys.version)

test1 = "abcdefg".encode("utf-8")
print(hexlify(test1), hashlib.sha256(test1).hexdigest())
test2 = "abcdefg".encode("latin1")
print(hexlify(test2), hashlib.sha256(test2).hexdigest())
test3 = "abcdefg".encode("ascii")
print(hexlify(test3), hashlib.sha256(test3).hexdigest())
test4 = b"abcdefg"
print(hexlify(test4), hashlib.sha256(test4).hexdigest())
test5 = bytes([0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67])
print(hexlify(test5), hashlib.sha256(test5).hexdigest())
var js_sha3 = require('js-sha3')
var crypto = require('crypto');
var buffer = require('buffer');
console.log("Javascript:", process.version)

function toHex(str) {
  return new Buffer.from(str).toString('hex')
}

var test1 = "abcdefg"
console.log(toHex(test1).toString('hex'), js_sha3.sha3_256(test1))
var test2 = Buffer.from("abcdefg")
console.log(toHex(test2), js_sha3.sha3_256(test2))
var test3 = "abcdefg"
console.log(toHex(test3), crypto.createHash('sha3-256').update(test3).digest("hex"))
var test4 = Buffer.from("abcdefg")
console.log(toHex(test4), crypto.createHash('sha3-256').update(test4).digest("hex"))
var test5 = buffer.Buffer.from("abcdefg", 'hex')
console.log(toHex(test5), js_sha3.sha3_256(test5))

但是,输出如下所示:

Python 3.7.4 (default, Sep  7 2019, 18:27:02) 
[Clang 10.0.1 (clang-1001.0.46.4)]
b'61626364656667' 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
b'61626364656667' 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
b'61626364656667' 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
b'61626364656667' 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
b'61626364656667' 7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a
Javascript: v12.15.0
61626364656667 7d55114476dfc6a2fbeaa10e221a8d0f32fc8f2efb69a6e878f4633366917a62
61626364656667 7d55114476dfc6a2fbeaa10e221a8d0f32fc8f2efb69a6e878f4633366917a62
61626364656667 7d55114476dfc6a2fbeaa10e221a8d0f32fc8f2efb69a6e878f4633366917a62
61626364656667 7d55114476dfc6a2fbeaa10e221a8d0f32fc8f2efb69a6e878f4633366917a62
abcdef 8b8a2a6bc589cd378fc57f47d5668c58b31167b2bf9e632696e5c2d50fc16002

但是,将 abcdefg 输入 https://emn178.github.io/online-tools/sha256.html *(由 js-sha3 支持)returns 7d1a54....

所以,我的问题是 - 我在 Javascript 和 Python 中对 SHA-256 的使用有何不同?我错过了什么? (我不会试图声称其中一个实现已损坏!)

[edit] 如果我使用 MD5 而不是 SHA-256,结果匹配,更加神秘!

x = bytes("thequickbrownfox", "utf-8")
print(hashlib.md5(x).hexdigest())
print(hashlib.sha256(x).hexdigest())
var x = "thequickbrownfox"
console.log(crypto.createHash('md5').update(x).digest("hex"))
console.log(crypto.createHash('sha3-256').update(x).digest("hex"))

输出:

308fb76dc4d730360ee33932d2fb1056
bd484b82d7875e115c7273e9c6102ca4946b7c55fe905012be9152b87fe09568
308fb76dc4d730360ee33932d2fb1056
4822316e0d7a7a2ce1bb6489e57c73ca5db4c7c660c79c3c65839bd4aaf4ef10

这当然是正确的,对于相同的给定输入,哈希函数产生相同的摘要。然而,棘手的是,其中许多哈希函数接受以字节为单位的输入。这意味着这里将给定字符串编码成不同的取决于平台。但是,您还需要考虑到不同的编程语言可能会有细微的差异,例如我不熟悉python,但它可能会在输入的末尾添加一个空的space and/or 对不同的特殊字符使用不同的 Unicode 表示。即使是输入中的一个字节变化也会产生完全不同的输出,正如人们对哈希函数所期望的那样。

总而言之,如果您想找到创建不同哈希的原因,您应该对哈希函数的输入执行二进制比较。或者以十六进制或 base 64 打印出 SHA-256 的输入。

今天我学到了 sha256sha3-256 之间非常重要的区别。