【问题标题】:Different results trying to port SHA-1 digest from Python to browser JavaScript尝试将 SHA-1 摘要从 Python 移植到浏览器 JavaScript 的不同结果
【发布时间】:2021-03-10 03:38:03
【问题描述】:

主要问题

我有以下一小段遗留代码,我正试图将其从 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)

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

  • cc47e3c0aa0c2984454476d061108c0b110177ae - Python
  • a9993e364706816aba3e25717850c26c9cd0d89d - JavaScript

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

我需要 JavaScript 代码来返回 Python 代码返回的内容。有什么想法吗?


另外

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

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

所以,如果您对此也有任何想法 - 我将不胜感激!

【问题讨论】:

  • 您需要特定的库(因为您的示例使用 WebCrypto)还是与使用的 JavaScript 库无关?
  • @Topaco 理想情况下,它可以在 Firefox 和 Chrome 上运行而无需外部依赖

标签: javascript python cryptography sha1


【解决方案1】:

Python 代码计算基于 SHA1 的 HMAC。另一方面,JavaScript 代码计算 SHA-1 哈希。除了数据之外,HMAC 还需要密钥,而 cryptographic hash function 无需密钥即可工作。

第一个 Python 代码使用密钥 abcempty 消息。 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: https://stackoverflow.com/a/40031979/9014097 
}

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

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


WebCrypto API 有点麻烦。与CryptoJS(Maurice Meyer 的评论中提到的库)功能相同的实现更简单,如下所示:

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 作为外部依赖项。

【讨论】:

  • 非常感谢!!这解释了我想知道的一切:)祝你有美好的一天。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多