尝试将 SHA-1 摘要从 Python 移植到浏览器 JavaScript 的不同结果

Different results trying to port SHA-1 digest from Python to browser JavaScript

主要问题

我有以下一小段遗留代码,我试图将其从 Python(仅使用标准库)移植到 JavaScript - 从我假设它创建的方法的名称abc 字符串的 SHA-1 摘要

import hashlib
import hmac

print(hmac.new(b"abc", None, hashlib.sha1).hexdigest())

我在 JS 的浏览器中搜索了如何做到这一点,并找到了 the following code in the Mozilla documentation

var msgUint8 = new TextEncoder().encode('abc');
var hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8);
var hashArray = Array.from(new Uint8Array(hashBuffer));
var hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
console.log(hashHex)

问题是,它们产生了两个完全不同的结果,我不知道为什么:

我尝试比较 b"abc"new TextEncoder().encode('abc') return 的字节,它们完全相同:0x61 0x62 0x63,所以问题出在其他地方,我不知道在哪里。

我需要 JavaScript 代码来 return 什么 Python 代码 return。有什么想法吗?


另外

我的最终目标是实际移植 this 代码(注意 b"hello" 而不是 None):

print(hmac.new(b"abc", b"hello", hashlib.sha1).hexdigest())

因此,如果您对此也有想法 - 我将不胜感激!

Python 代码计算基于 SHA1 的 HMAC。另一方面,JavaScript 代码计算 SHA-1 散列。 HMAC needs a key in addition to the data, while a cryptographic hash function 无需密钥即可工作。

第一个 Python 代码使用密钥 abc 消息。 HMAC 的发布结果是十六进制编码的:

cc47e3c0aa0c2984454476d061108c0b110177ae

第二个 Python 代码使用相同的密钥和消息 hello。 HMAC 的结果是十六进制编码的:

d373670db3c99ebfa96060e993c340ccf6dd079e

Java 代码确定 abc 的 SHA-1 散列。结果是

a9993e364706816aba3e25717850c26c9cd0d89d

所以所有结果都是正确的,但是是用不同的输入数据或算法生成的。


HMAC的计算可以用浏览器原生 WebCrypto-API实现如下:

(async () => {
    var hmac = await calcHMac('abc', 'hello');
    console.log('HMAC: ', buf2hex(hmac)); 
    var hmac = await calcHMac('abc', '');
    console.log('HMAC: ', buf2hex(hmac)); 
})();
    
async function calcHMac(rawkey, data) {
    var key = await window.crypto.subtle.importKey('raw', utf8Encode(rawkey), {name: 'HMAC', hash: 'SHA-1'},true, ['sign']);        
    var hmac = await window.crypto.subtle.sign('HMAC', key, utf8Encode(data));
    return hmac;
}
    
function utf8Encode(str){
    return new TextEncoder().encode(str);
}
    
function buf2hex(buffer) {
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); // from:  
}

并提供与两个 Python 代码相同的结果。

对 SHA-1 的评论:尽管 HMAC/SHA-1 被认为是安全的(与 SHA-1 相反),但有一些论点要求切换到 SHA-256,请参阅 here


WebCrypto API 有点麻烦。 Maurice Meyer 在评论中提到的库 CryptoJS 的功能相同的实现更简单,看起来像这样:

var hmac = CryptoJS.HmacSHA1('hello', 'abc');
console.log('HMAC: ', hmac.toString(CryptoJS.enc.Hex));

var hmac = CryptoJS.HmacSHA1('', 'abc');
console.log('HMAC: ', hmac.toString(CryptoJS.enc.Hex));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

但需要 CryptoJS 作为外部依赖。