Python 与 JavaScript 中的 HMAC SHA256

我想用JavaScript重新实现某个用Python编写的API客户端。我无法复制 HMAC SHA256 签名功能。对于某些键,输出是相同的,但对于某些键,输出是不同的。在解码其 Base64 表示后,当密钥由可打印字符组成时,输出似乎是相同的。


Python

#!/usr/bin/env python3


import base64

import hashlib

import hmac


def sign_string(key_b64, to_sign):

    key = base64.b64decode(key_b64)

    signed_hmac_sha256 = hmac.HMAC(key, to_sign.encode(), hashlib.sha256)

    digest = signed_hmac_sha256.digest()

    return base64.b64encode(digest).decode()


print(sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message"))

print(sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message"))

print(sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message"))

JavaScript

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script>


<script>

    function sign_string(key_b64, to_sign) {

        key = atob(key_b64)

        var hash = CryptoJS.HmacSHA256(to_sign, key);

        var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);

        document.write(hashInBase64 + '<br>');

    }

    sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")

    sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")

    sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")

</script>

产出

Python


TdhfUQfym16HyWQ8wxQeNVvJKr/tp5rLKHYQSpURLpw=

pQ5NzK3KIWjqc75AXBvWgLK8X0kZvjRHXrLAdxIN+Bk=

8srAvMucCd91CWI7DeCFjxJrEYllaaH63wmVlMk0W+I=

JavaScript


TdhfUQfym16HyWQ8wxQeNVvJKr/tp5rLKHYQSpURLpw=

pQ5NzK3KIWjqc75AXBvWgLK8X0kZvjRHXrLAdxIN+Bk=

31QxOpifnpFUpx/sn336ZmmjkYbLlNrs8NP9om6nPeY=

如您所见,前两个是相同的,而最后一个是不同的。


如何更改 JavaScript 代码以使其行为与 python 代码相同?


喵喵时光机
浏览 316回答 1
1回答

互换的青春

您尝试提供给 CryptoJs 的 base64 编码秘密并不代表 CryptoJS 需要的有效 UTF-8 字符串。您可以使用此工具检查有效性。atob()编码不可知,只是逐字节转换,不检查它是否是有效的 UTF-8。在这里,我用 CryptoJS 自己的解码器对 base64 密码进行了解码,它抛出了一个错误,说它是无效的 UTF-8:<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script><script>&nbsp; &nbsp; function sign_string(key_b64, to_sign) {&nbsp; &nbsp; &nbsp; &nbsp; var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);&nbsp; &nbsp; &nbsp; &nbsp; var hash = CryptoJS.HmacSHA256(to_sign, key);&nbsp; &nbsp; &nbsp; &nbsp; var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);&nbsp; &nbsp; &nbsp; &nbsp; document.write(hashInBase64 + '<br>');&nbsp; &nbsp; }&nbsp; &nbsp; sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")&nbsp; &nbsp; sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")&nbsp; &nbsp; sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")</script>我还找到了一种可以使用原始字节作为密钥的方法。这适用于最后一个键,但不适用于前两个键。var key = CryptoJS.enc.Hex.parse(toHex(atob(key_b64)));现在,如果您将这两种方法结合起来,您就可以获得真正的解决方案。这个最终代码给出了与 python 相同的输出:<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script><script>&nbsp; &nbsp; function sign_string(key_b64, to_sign) {&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var key = CryptoJS.enc.Hex.parse(toHex(atob(key_b64)));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var hash = CryptoJS.HmacSHA256(to_sign, key);&nbsp; &nbsp; &nbsp; &nbsp; var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);&nbsp; &nbsp; &nbsp; &nbsp; document.write(hashInBase64 + '<br>');&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; function toHex(str) {&nbsp; &nbsp; &nbsp; &nbsp; var result = '';&nbsp; &nbsp; &nbsp; &nbsp; for (var i=0; i<str.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (str.charCodeAt(i).toString(16).length === 1) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result += '0' + str.charCodeAt(i).toString(16);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result += str.charCodeAt(i).toString(16);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; }&nbsp; &nbsp; sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")&nbsp; &nbsp; sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")&nbsp; &nbsp; sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")&nbsp; &nbsp; sign_string('xTsHZGfWUmnIpSu+TaVraECU88O3j9qVjlwTWGb/C8k=', "my message")</script>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python