Python 与 JavaScript 中的 HMAC SHA256

2024-01-03

我想用 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>

Outputs

Python

TdhfUQfym16HyWQ8wxQeNVvJKr/tp5rLKHYQSpURLpw=
pQ5NzK3KIWjqc75AXBvWgLK8X0kZvjRHXrLAdxIN+Bk=
8srAvMucCd91CWI7DeCFjxJrEYllaaH63wmVlMk0W+I=

JavaScript

TdhfUQfym16HyWQ8wxQeNVvJKr/tp5rLKHYQSpURLpw=
pQ5NzK3KIWjqc75AXBvWgLK8X0kZvjRHXrLAdxIN+Bk=
31QxOpifnpFUpx/sn336ZmmjkYbLlNrs8NP9om6nPeY=

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

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


您尝试提供给 CryptoJs 的 Base64 编码机密不代表 CryptoJS 所需的有效 UTF-8 字符串。您可以使用这个工具 https://onlineutf8tools.com/convert-hexadecimal-to-utf8检查有效性。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>
    function sign_string(key_b64, to_sign) {
        var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);
        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>

我还找到了一种可以使用原始字节作为密钥的方法。这适用于最后一个键,但不适用于前两个键。

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>
    function sign_string(key_b64, to_sign) {
        try {
            var key = CryptoJS.enc.Base64.parse(key_b64).toString(CryptoJS.enc.Utf8);
        }
        catch {
            var key = CryptoJS.enc.Hex.parse(toHex(atob(key_b64)));
        }
        var hash = CryptoJS.HmacSHA256(to_sign, key);
        var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
        document.write(hashInBase64 + '<br>');
    }
    
    function toHex(str) {
        var result = '';
        for (var i=0; i<str.length; i++) {
          if (str.charCodeAt(i).toString(16).length === 1) {
            result += '0' + str.charCodeAt(i).toString(16);
          } else {
            result += str.charCodeAt(i).toString(16);
          }
        }
        return result;
    }

    sign_string('VGhpcyBpcyBhIHByaW50YWJsZSBzdHJpbmcuCg==', "my message")
    sign_string('dGhlIHdpbmQgb2YgTXQuIEZ1amkK', "my message")
    sign_string('pkmNNJw3alrpIBi5t5Pxuym00M211oN86IhLZVT8', "my message")
    sign_string('xTsHZGfWUmnIpSu+TaVraECU88O3j9qVjlwTWGb/C8k=', "my message")
</script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 与 JavaScript 中的 HMAC SHA256 的相关文章

随机推荐

  • 图解:python语言重路由问题测试

    贵公司有N服务器 信息通过连接从一台服务器流向另一台服务器 如果信息从服务器流出i到服务器j then 联系 i j 某些服务器连接 i i 是可能的 这意味着信息不会进一步流动 给定一个由 N 个整数组成的数组连接 您的任务是对连接数组值
  • 如何根据当前服务器找到最合适的缓冲区大小来读取或写入Stream

    我正在编写一个服务器 它将准备好并写入巨大的文件 数据库 我在很多地方使用了 Stream 读写函数 其中我使用 8192 作为缓冲区大小 我还从 TCP 套接字读取大量输入 我不知道将部署该服务的虚拟机的配置是什么 是否有任何内置函数可以
  • Lucene 通配符查询

    我有一个关于 Lucene 的问题 我有一个表单 并从中获取文本 我想在多个字段中执行全文搜索 假设我从输入中获取文本 textToLook 我有一个带有多个过滤器的 Lucene 分析器 其中之一是 lowerCaseFilter 因此当
  • lxml.objectify 和前导零

    当 objectify 元素打印在控制台上时 前导零会丢失 但它会保留在 text gt gt gt from lxml import objectify gt gt gt gt gt gt xml a b 01 b a gt gt gt
  • 在scala中,如何使类型类适用于Aux模式? - 第2部分

    这是以下问题的后续问题 在scala中 如何使类型类适用于Aux模式 https stackoverflow com questions 65838535 in scala how to make type class working fo
  • Python - 从类主体内部引用类名

    在Python中 我想要一个类属性 一个带有初始化值的字典 我写了这段代码 class MetaDataElement MD INVALID MD CATEGORY MD TAG range 3 mapInitiator2Type Meta
  • 将 DateTime 保存到 Cassandra Date 列

    Cassandra NET 驱动程序文档非常糟糕 我试图拼凑一些功能性的东西 但我浪费了很多时间试图更改我找到的 Java 文档中的代码 我正在尝试使用 Cassandra 驱动程序将数据写入一个简单的表 该表已经存在并且里面有日期 我创建
  • basicAuth configprerender basicAuth 配置

    我正在运行一个预渲染服务器 https prerender io documentation一切都很好 但现在我想使用设置一些安全性基本验证 https github com prerender prerender basicauth 在我
  • 表视图中的复选框单元格:用户无法选中它

    我需要使用复选框单元格的帮助 我目前将对象添加到表视图中 看起来没问题 直到我尝试构建和运行程序 但我无法选中该复选框 我目前正在使用一个表格视图 它显示项目运行时 每个项目都有一个复选框 这样我就可以有多个选择 我是 xcode 新手 这
  • 为网站的私人测试版添加安全层的最不显眼的方法是什么?

    假设我有一个 ASP NET 站点 在本例中为 MVC 它使用表单身份验证和典型的会员系统 该网站允许经过身份验证的用户和匿名用户 当我将网站作为私人测试版发布时 我想在应用程序之上添加另一层安全性 例如超级用户的 https superu
  • 组件如何对其子组件进行布局?

    我已经使用 React 几个星期了 所以我还远不 是专家 这就是问题所在 我正在构建一些布局其子组件的组件 这是一个Layout可以这样使用 var SomeComponent React createClass render functi
  • 确定列中 NA 值的数量

    我想数一下有多少个NA数据框列中的值 假设我的数据框被称为df 我正在考虑的列的名称是col 我想出的方法如下 sapply df col function x sum length which is na x 这是一个好的 最有效的方法吗
  • Kendo Grid:在 Angular 中获取小部件实例

    我试图在我的 Angular 控制器中获取 Kendo 网格的实例 因此我可以尝试连接一些事件 并调用方法 我知道这可能不是最佳实践 并且可能应该使用自定义指令 但是根据文档 http docs telerik com kendo ui A
  • 在 Guice 中模仿 Spring 配置文件

    在 Spring 中 如果我想要一组用于生产的对象 另一组用于本地开发 测试 我可以使用 Profile注解来指定不同的类 并通过在启动应用程序时提供系统属性来在它们之间进行切换 Guice 中是否有类似的内容 或者我需要自己手动检查某些属
  • 在 javascript 中访问 ASP HiddenField

    我已经在这里和谷歌搜索了几天 试图找出为什么我无法获取 javascript 中隐藏字段变量的值 访问时 该值返回为未定义 我在 UpdatePanel 中有一个 ASP HiddenField 它是 aspx 网页中自定义用户控件的一部分
  • 使用 Vuelidate 进行条件验证?

    我有一个表单 可以根据参数应用不同的验证action 存储在VUEX存储中 我试试这个 data function const validations sendToProject cardProject required recallToB
  • 如何调整背景颜色的大小并调整其位置?

    我有一个图像 当我将其悬停时 背景颜色会发生变化 但我想更改大小和位置 hoverme hover background color f7b0ee border radius 50 transition initial 0 5s ease
  • 如果没有冲突则自动远程合并

    如果没有冲突 有没有办法让推送自动接受并合并 我知道这是一个不好的做法 但我有一个特殊情况 即外围 git 存储库由机器人更新 如果没有冲突 有没有办法让推送自动接受并合并 推理流程应该颠倒过来 只有在尝试合并之后才能知道不存在冲突 当本地
  • 如何在 HTML 渲染器中对 HTML 内容进行分页

    I have a project where HTML code is converted to a PDF using HTML Renderer The HTML code contains a single table The PDF
  • Python 与 JavaScript 中的 HMAC SHA256

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