HMAC 生成器用一条消息和一个密钥算出带密钥的摘要. 整个计算是一次浏览器内的 WebCrypto 调用: 消息和密钥都留在页面上, 不发给任何服务器, 结果是确定性的字符串, 可以粘进请求头, 查询参数或测试向量. 从HMAC 生成器开始, 消息输入 The quick brown fox jumps over the lazy dog, 密钥输入 key, 保持 SHA-256 和 Hex 选中, 按生成: 摘要打印 f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8.
四个控件
四个输入决定摘要: 消息框, 带 Text/Hex 切换的密钥框, 算法选择和输出格式选择. 消息是多行文本域: 换行符是消息的一部分, 参与签名, 所以同样的词分两行签和用空格连成一行签出的值不同, 你好 的 UTF-8 字节在密钥 key 下签出 309b75c0cbbfb27bb35b8d7b8f4adb4b9399cd54339ab5faeb8798e1b9f7f00c. 密钥是单行框, 切换按钮决定这个字符串如何被读. 算法选择提供 SHA-256, SHA-384 和 SHA-512, 格式选择提供 Hex 和 Base64. 生成是一个显式按钮: 按之前不计算任何东西, 摘要出现在一个只读框里, 旁边是复制按钮.
文本密钥和十六进制密钥
Text 模式下密钥按所敲的 UTF-8 字节读取: 每个字符都是密钥的一部分, 包括尾随空格, 所以密钥 key 把 abc 签成 9c196e32dc0175f86f4b1cb89289d6619de6bee699e4c378e68309ed97a1a6ab, 而带一个尾随空格的 key 把同样的 abc 签成 0324ef70f9e605e123731b458dcdce99cf5f8d23572f604fbdabf371aedb0f68. Hex 模式下字符串先去掉所有空白, 再按原始字节对读取, 所以 616263 是三个字节 0x61, 0x62, 0x63, 不是文本 616263 的六个字符: 消息 msg 下, 十六进制密钥 616263 签出 eb14f17c9f056479f147adcf8020d27914f1e5971f049e75bf21a669cbd747e2, 而文本密钥 616263 签出 49962d2f0cde29c6a4848f8ea64575424ad42d3d108452127c0512cb88444a41. 十六进制字符串必须至少两个字符, 偶数长度, 且全是十六进制数字; 6162635 在任何加密运行之前就过不了检查, 奇数长度和 a 到 f 之外的字母也一样.
三个算法
摘要长度由算法固定: SHA-256 打印 32 字节, 即 64 个十六进制字符, 或 44 个 Base64 字符带一个 = 填充; SHA-384 打印 48 字节, 96 个十六进制字符, 或 64 个 Base64 字符无填充; SHA-512 打印 64 字节, 128 个十六进制字符, 或 88 个 Base64 字符带双填充. 三者是同一个带密钥构造套在三个哈希函数上, 所以切换选择改变的是长度和值, 不是输入的形状. 本工具能复现 RFC 4231 测试向量: 十六进制密钥 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 配消息 Hi There, SHA-256 打印 b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7, SHA-512 打印 87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854; 文本密钥 Jefe 配消息 what do ya want for breakfast?, SHA-256 打印 47f69d8f80f0a6326746beec23a9040fd533642b5ba38a99287670639d8b862a.
Hex 和 Base64
Hex 按字节小写打印摘要, 每字节两个字符; Base64 打印同样的字节, 带标准填充. 两种写法携带的是同样的 32 字节: 密钥 key 下的 fox 消息, Hex 是 f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8, Base64 是 97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg=, 结尾的 = 是填充, 不是被签的字符. Jefe 消息在 SHA-256 下打印 R/adj4DwpjJnRr7sI6kED9UzZCtbo4qZKHZwY52Lhio=, 在 SHA-384 下打印 MxTAcsyrQOuSUFsKlh1Gv2UuDowpCJfZzsFDvCo65FGJ15G5QCeCSey3RFF3dIlG, 48 字节正好填满 Base64 分组, 没有填充; 在 SHA-512 下打印 af7nmi5sP0zyOeCqttVBl2h4BIXw5B/8dZckor99FGR+CncEsWts5Zi2pWU1HIhhnQ3+0nKMj8+Ja0GvkB1UCA==, 64 字节在最后一组剩一个字节, 用双 = 填充. 复制按钮把打印的字符串放进剪贴板, 并显示 已复制 两秒.
确定性和输入检查
同样的消息, 密钥和算法永远打印同样的摘要: 没有盐, 没有时间戳, 没有随机性, 这正是 HMAC 能被用作测试向量, 以及被两个系统用作共享校验的原因. 两个输入在任何加密运行之前被拒: 空消息或纯空白消息触发 请输入消息 错误, 空密钥或纯空白密钥触发 请输入密钥 错误; 过不了十六进制检查的密钥触发 无效十六进制 错误, 三种情况框里都保留内容以便修正. 密钥长度除此之外不受限: 单字节密钥把 abc 签成 df55998f9fc33d78ac99d1d8ebc2b6e16aa076c4189946942a82b55d5dee8dc7, 100 字节密钥把同样的 abc 签成 30f0f7f4a3d31b9750666b038c048550020795dd2743759bf83bcf5e0f125b36, 因为 HMAC 构造先把过长的密钥哈希到哈希尺寸. 还剩一个平台角: WebCrypto subtle API 只存在于安全上下文, 所以在纯 http 页面上, 按钮会显示失败错误而不是计算.
它不是什么
HMAC 生成器不是普通哈希工具: 要对消息本身不带任何密钥的摘要, 哈希生成器对文本跑 MD5, SHA-1 和 SHA-2 族. 它也不是 JWT 工具: 要读取, 拆分并 Base64 解码一个令牌而不是签一个, JWT 解码器做那件事. 它也不加密: 摘要是签名, 不是秘密容器, 加密方向见AES 指南. 它也不在四个输入之外保存任何状态: 没有历史, 没有存储的密钥, 没有上一个摘要的记忆, 关掉页面就丢掉消息和密钥.