正确使用Google Apps Script计算带十六进制密钥的HMAC

正确使用google apps script计算带十六进制密钥的hmac

本文详细介绍了在Google Apps Script中正确计算HMAC签名的方法,特别是当密钥以十六进制字符串形式提供时。核心挑战在于将十六进制密钥和消息内容准确转换为Google Apps Script Utilities.computeHmacSignature函数所需的字节数组格式,以确保与PHP等其他语言生成的HMAC结果一致。通过示例代码,我们演示了如何进行正确的字节转换,避免常见的编码陷阱,从而成功实现API认证。

理解HMAC与字节表示

HMAC(Keyed-Hash Message Authentication Code)是一种使用加密哈希函数和密钥来验证消息完整性和真实性的机制。在API认证中,HMAC被广泛应用。当在不同编程环境(如PHP与Google Apps Script)中实现HMAC时,一个常见的挑战是确保密钥和消息的底层字节表示方式一致。特别是当密钥以十六进制字符串形式提供时,需要将其正确转换为二进制字节序列。

PHP的hash_hmac函数在处理字符串类型的密钥时,会将其解释为二进制数据。例如,chr(hexdec(‘C7’))会将十六进制C7(十进制199)转换为一个字节值为199的字符。然而,Google Apps Script中的Utilities.computeHmacSignature函数对输入类型有更严格的要求,通常期望密钥和消息都是字节数组(byte[])。

常见错误:字符串与字节的混淆

在Google Apps Script中,初次尝试将十六进制密钥转换为字符串时,可能会使用String.fromCharCode(parseInt(“C7”, 16))。这种方法会将十六进制值解析为Unicode字符,而不是原始的字节。例如,parseInt(“C7”, 16)得到199,String.fromCharCode(199)会生成一个Unicode字符,其字节表示可能与原始的二进制字节199不同,尤其是在不同的字符编码环境下。这会导致Utilities.computeHmacSignature函数对密钥的解释出现偏差,从而计算出错误的HMAC值。

原始的Google Apps Script尝试:

// 错误示例:将十六进制转换为Unicode字符var klucz = String.fromCharCode(parseInt("C7",16)) + String.fromCharCode(parseInt("7C",16)) + ...;// ...var hmac = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, wiadomosc, klucz);

这种方法未能正确地将十六进制表示的二进制密钥转换为Utilities.computeHmacSignature所期望的字节数组,导致计算结果与PHP不一致。

正确的HMAC计算方法

为了在Google Apps Script中正确计算HMAC,需要确保以下两点:

十六进制密钥转换为字节数组。消息内容转换为字节数组。

1. 密钥的十六进制到字节数组转换

给定一个十六进制密钥字符串(例如C77C96EEF6F6995B),我们需要将其分解为每两个字符一组的十六进制对,然后将每对转换为其对应的十进制数值。由于Java(Google Apps Script底层)的byte类型是有符号的,范围是-128到127,因此对于大于127(即0x7F)的无符号字节值,需要进行相应的调整(减去256)以匹配Java的带符号字节表示。

以下是实现此转换的JavaScript代码片段:

/** * 将十六进制字符串转换为Google Apps Script Utilities函数所需的字节数组。 * 对于大于127的无符号字节值,转换为其对应的带符号字节表示。 * @param {string} hexString 十六进制密钥字符串,例如 "C77C96EEF6F6995B"。 * @returns {number[]} 字节数组。 */function hexToSignedByteArray(hexString) {    return hexString.match(/.{2}/g).map(e => {        const byteValue = parseInt(e, 16);        // 如果字节值大于127(即最高位为1),则转换为带符号的负数        return byteValue > 127 ? byteValue - 256 : byteValue;    });}// 示例使用var hexKey = "C77C96EEF6F6995B";var kluczByteArray = hexToSignedByteArray(hexKey);// kluczByteArray 现在是一个如 [-57, 124, -106, -18, -10, -10, -103, 91] 的数组

这个hexToSignedByteArray函数确保了十六进制密钥被正确地解析为Google Apps Script Utilities函数所期望的byte[](实际上是number[],其中数字代表字节值,并处理了符号位)。

2. 消息内容的字节数组转换

同样,为了确保一致性,传递给Utilities.computeHmacSignature的消息内容也应该是一个字节数组。Google Apps Script提供了Utilities.newBlob(string).getBytes()方法,可以将字符串按照UTF-8编码转换为字节数组。

var messageString = "https://www.ifirma.pl/iapi/abonent/miesiacksiegowy.json" + "user@example.com" + "abonent";var messageByteArray = Utilities.newBlob(messageString).getBytes();

3. 完整的Google Apps Script HMAC计算

结合上述转换,以下是Google Apps Script中正确计算HMAC的完整函数:

/** * 将字节数组转换为十六进制字符串,用于日志输出。 * @param {number[]} data 字节数组。 * @returns {string} 十六进制字符串。 */function bytesToHex(data) {    return data.map(function(e) {        // 将带符号字节转换为无符号字节(0-255),然后转为16进制        var v = (e  {        const byteValue = parseInt(e, 16);        return byteValue > 127 ? byteValue - 256 : byteValue;    });}/** * 在Google Apps Script中计算HMAC-SHA1签名。 */function callNumbers() {  // 1. 准备十六进制密钥并转换为字节数组  var hexKey = "C77C96EEF6F6995B";  var kluczByteArray = hexToSignedByteArray(hexKey);  // 2. 准备消息内容  var user = "user@example.com"; // 替换为实际的用户信息  var url = "https://www.ifirma.pl/iapi/abonent/miesiacksiegowy.json"; // 替换为实际的URL  var nazwaKlucza = "abonent"; // 替换为实际的键名  var messageString = url + user + nazwaKlucza;  // 3. 将消息字符串转换为字节数组  var messageByteArray = Utilities.newBlob(messageString).getBytes();  // 4. 使用Utilities.computeHmacSignature计算HMAC  // 注意:HMAC_SHA_1算法,消息和密钥都必须是字节数组  var hmacByteArray = Utilities.computeHmacSignature(      Utilities.MacAlgorithm.HMAC_SHA_1,      messageByteArray,      kluczByteArray  );  // 5. 将结果字节数组转换为十六进制字符串以便于显示和比较  var hmacHex = bytesToHex(hmacByteArray);  Logger.log(hmacHex); // 预期输出: 9b5f9bb41ac30b9c55b10f3cecdd6e12e852f274}

运行上述callNumbers函数,将得到与PHP脚本完全一致的HMAC哈希值:9b5f9bb41ac30b9c55b10f3cecdd6e12e852f274。

总结与注意事项

字节数组是关键: 在Google Apps Script中使用Utilities.computeHmacSignature时,务必将十六进制密钥和消息内容都转换为字节数组。直接使用字符串作为二进制密钥或消息可能会导致不一致的结果。十六进制密钥转换: 对于十六进制密钥,需要将其解析为每两个字符一组,并转换为对应的数值。考虑到Java底层对byte类型的处理,对于大于127的无符号字节值,需要转换为其对应的带符号表示(即减去256)。消息编码: Utilities.newBlob(string).getBytes()默认使用UTF-8编码将字符串转换为字节数组。请确保这与API期望的编码一致。bytesToHex函数: 此辅助函数用于将computeHmacSignature返回的字节数组转换为可读的十六进制字符串,便于验证和调试。

通过遵循这些指导原则,您可以在Google Apps Script中可靠地实现HMAC签名,确保与各种API和平台之间的兼容性。

参考资料

Google Apps Script Utilities.computeHmacSignature()

以上就是正确使用Google Apps Script计算带十六进制密钥的HMAC的详细内容,更多请关注php中文网其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1272913.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月10日 15:12:36
下一篇 2025年12月10日 15:12:47

相关推荐

  • PHP文件写入权限与逻辑处理深度解析

    本教程深入探讨PHP中文件写入操作的常见权限问题与逻辑陷阱。文章详细分析了is_writable函数在文件不存在时的行为、动态文件名生成及一致性使用的重要性,并提供了优化后的代码示例,旨在帮助开发者构建健壮、可靠的文件日志系统,避免因权限或逻辑错误导致的程序中断,确保数据写入的准确性和稳定性。 PH…

    2025年12月10日
    000
  • JavaScript与jQuery动态HTML拼接中的引号转义及最佳实践

    本文深入探讨了在使用jQuery动态拼接HTML字符串,特别是包含内联事件处理器时常见的SyntaxError问题。核心在于字符串内部引号与外部引号的冲突。文章提供了两种解决方案:通过切换引号类型或使用反斜杠进行转义,并进一步建议了避免内联事件处理器、采用事件委托等现代前端开发最佳实践,以提升代码的…

    2025年12月10日
    000
  • 正确计算Google Apps Script中带十六进制密钥的HMAC

    本文深入探讨了在Google Apps Script中使用十六进制密钥正确计算HMAC的常见问题。通过对比PHP和Google Apps Script的实现差异,重点阐述了将十六进制密钥和消息字符串精确转换为字节数组的重要性,并提供了详细的示例代码和注意事项,确保HMAC计算结果的一致性。 引言 h…

    2025年12月10日
    000
  • PHPMaker 2019:利用自定义视图处理复杂SQL联接与数据过滤

    本文探讨了在PHPMaker 2019中处理复杂SQL联接和数据过滤的挑战,特别是在Recordset_Selecting事件中的局限性。我们提出并详细阐述了创建自定义数据库视图作为解决方案,并指导如何在PHPMaker中配置这些视图以实现数据编辑功能,特别是通过设置UpdateTable属性,从而…

    2025年12月10日
    000
  • PHPMaker 2019中实现复杂数据过滤与联接:自定义视图的实践指南

    在PHPMaker 2019中处理涉及复杂联接和高级过滤逻辑的数据时,直接在Recordset_Selecting事件中实现往往受限。本文详细阐述了如何通过创建数据库自定义视图来解决此类问题,特别是针对需要结合多表信息进行去重和条件筛选的场景。教程涵盖了视图的创建、在PHPMaker中集成视图以及如…

    2025年12月10日
    000
  • CodeIgniter 4 重定向函数传递参数的技巧与扩展

    本文旨在解决在 CodeIgniter 4 中使用命名路由进行重定向时,如何传递参数的问题。通过分析 redirect() 函数的源码和 route() 方法的特性,提供了一种扩展 redirect() 函数,使其能够传递参数的解决方案,从而满足更灵活的路由需求。 在 CodeIgniter 4 中…

    2025年12月10日
    000
  • Yii2:在 ActiveRecord 中从连接的表获取额外字段

    本文档介绍了在使用 Yii2 框架进行数据库查询时,如何通过 JOIN 操作从关联表中获取额外的字段,并将其作为 ActiveRecord 对象的一部分返回。重点解决了在执行 JOIN 查询后,额外字段在 ActiveRecord 对象中丢失的问题,并提供了明确的解决方案。 在使用 Yii2 的 A…

    2025年12月10日
    000
  • CodeIgniter 4 命名路由重定向时传递参数的技巧

    本文旨在解决 CodeIgniter 4 中使用命名路由进行重定向时,如何优雅地传递参数的问题。虽然框架原生 redirect() 函数只接受一个路由参数,但通过自定义 redirect() 函数,可以实现向命名路由传递参数,从而简化代码并提高可维护性。 CodeIgniter 4 框架的 redi…

    2025年12月10日
    000
  • Yii2:在 JOIN 查询中获取 ActiveRecord 对象时包含额外字段

    本文档旨在解决在使用 Yii2 的 ActiveRecord 进行 JOIN 查询时,如何将关联表中的额外字段包含在结果对象中的问题。我们将通过一个具体的示例,详细介绍如何配置模型和查询,以便在获取 ActiveRecord 对象时,能够访问 JOIN 表中的字段数据。 问题描述 在使用 Yii2 …

    2025年12月10日
    000
  • Laravel共享服务器上无法显示Storage中的图片:解决方案与最佳实践

    在Laravel应用部署到共享服务器时,经常会遇到无法显示存储在storage/app/public目录下的图片的问题。这通常是由于软链接未正确创建、配置错误或文件权限问题导致的。本文将详细介绍如何解决这一问题,确保你的Laravel应用能够正确显示图片。 软链接的创建与配置 在Laravel中,s…

    2025年12月10日
    000
  • Laravel共享服务器上无法显示Storage中的图片:解决方案与排错指南

    本文旨在解决Laravel应用程序部署在共享服务器上时,无法从storage目录显示图片的问题。文章将涵盖文件系统配置、软链接创建、路径绑定以及权限设置等多个方面,提供详细的排错步骤和代码示例,帮助开发者快速定位问题并解决,确保图片资源能够正确加载和显示。 在将Laravel应用程序部署到共享服务器…

    2025年12月10日
    000
  • PHP 数组:查找数组中唯一的不同元素

    PHP 数组:查找数组中唯一的不同元素 本文将详细介绍如何利用 PHP 数组函数,高效地从一个包含重复元素的数组中找出那个唯一的不同元素。例如,给定数组 [2, 2, 5, 2, 2],目标是找出 5。 核心思路: 利用 array_count_values 函数统计数组中每个值的出现次数,然后对统…

    2025年12月10日
    000
  • 找出PHP数组中唯一的不同元素

    本文旨在提供一种高效的方法,用于从PHP数组中找出与其他元素不同的唯一元素。通过使用 array_count_values 函数统计数组中每个元素的出现次数,并结合 arsort 函数进行排序,我们可以轻松地定位到出现次数最少的元素,即数组中唯一的不同元素。本文将详细介绍该方法的使用,并提供示例代码…

    2025年12月10日
    000
  • 查找PHP数组中唯一不同的数字

    本文介绍了如何在PHP数组中查找与其他元素不同的唯一数字。通过使用array_count_values函数统计数组中每个值的出现次数,并结合arsort和array_keys函数,我们可以轻松地找到出现次数最少的元素,即数组中唯一不同的数字。文章提供了详细的代码示例和解释,帮助开发者理解和应用该方法…

    2025年12月10日
    000
  • 查找PHP数组中唯一不同的元素

    本文介绍了如何使用PHP内置函数 array_count_values 和 array_keys 快速有效地查找数组中与其他元素不同的唯一元素。 通过统计数组中每个值的出现次数,并结合数组键名提取,可以轻松定位并提取目标元素,并提供代码示例和注意事项,帮助开发者理解和应用该方法。 在PHP中,有时我…

    2025年12月10日
    000
  • 解决Symfony #[CurrentUser] 属性返回 null 的问题

    本文针对Symfony框架中使用#[CurrentUser]属性时可能遇到的null值问题,进行了深入分析和详细解答。通过剖析问题根源,即ParamConverter的自动转换机制,提供了禁用自动转换并手动定义路由参数的解决方案。同时,强调了阅读官方文档的重要性,避免类似问题的再次发生,助力开发者更…

    2025年12月10日
    000
  • 解决 Symfony #[CurrentUser] 属性返回 null 的问题

    文章摘要:本文旨在解决 Symfony 框架中使用 #[CurrentUser] 属性时,用户对象返回 null 的问题。该问题通常由于 sensio/framework-extra-bundle 引起的参数转换器自动转换导致。通过禁用自动转换并手动定义路由参数,可以有效解决此问题,并确保 #[Cu…

    2025年12月10日
    000
  • 树莓派Python向Laravel发送与展示JSON数据教程

    本教程详细指导如何利用Python在树莓派上读取数据、生成JSON,并通过HTTP POST请求将其安全地发送至Laravel后端。文章涵盖Laravel路由配置、控制器中JSON数据的接收、解析与处理,以及如何在Blade模板中优雅地展示这些数据,旨在提供一套完整的跨平台数据传输与展示解决方案。 …

    2025年12月10日
    000
  • 理解PHP Web应用中的静态变量、请求生命周期与数据持久化策略

    在PHP Web环境中,每次HTTP请求都会创建一个全新的、独立的执行环境,因此静态变量的值不会在不同请求之间保持。本文深入探讨了PHP中静态变量和方法的行为,解释了Web应用中数据持久化的必要性,并提供了通过数据库和会话管理实现数据持久化的策略,同时对比了Node.js等其他环境的差异。 1. P…

    2025年12月10日
    000
  • CodeIgniter中POST数据安全高效入库的实践指南

    本教程旨在解决CodeIgniter应用中POST数据无法正确插入数据库的问题。通过分析控制器和模型层常见的逻辑错误,本文将提供一套优化的解决方案,包括正确处理表单提交、有效获取POST数据以及使用CodeIgniter数据库类进行数据插入的最佳实践。读者将学习如何构建健壮的数据提交流程,确保用户输…

    2025年12月10日
    000

发表回复

登录后才能评论
关注微信