WebCrypto JS SHA256 HMAC 不匹配
WebCrypto JS SHA256 HMAC Mismatch
我有两个生成 SHA256 HMAC 的脚本,其中包含明文消息和 Base64 编码密钥。一个写在PHP,另一个写在JavaScript。 PHP 脚本 returns 正确的 HMAC,但由于某种原因 JS 版本没有。这是什么原因造成的?
这里是代码示例,带有经过编辑(本质上仍然相似)的密钥。
PHP
<?php
header("content-type: text/plain");
$key = "YdkQZp9Pq0OsKT5TlFzrgry7j1nw0XEmbNFm86zNU3+XFEmM/I+WxrAZE7yjFAD3iWJTQ10VN2+JK3fz4b3Viw==";
$message = "1614117737467myJSON.json" . '{"json_data": "to-be-encoded"}';
$hmac = base64_encode(hash_hmac('sha256', $message, base64_decode($key), true));
// to base64
echo base64_encode("1614117737467;" . $hmac);
这个脚本,returnsMTYxNDExNzczNzQ2NztFdXcwQ1l0bTBTMkdIdnZ2ZnN2ZGFkTEFDMGVPbVlJeHFzZk9PQWExS1BzPQ==
JS
async function hash_hmac(type, message, key, base64) {
const getUtf8Bytes = str =>
new Uint8Array(
[...unescape(encodeURIComponent(str))].map(c => c.charCodeAt(0))
);
const keyBytes = getUtf8Bytes(key);
const messageBytes = getUtf8Bytes(message);
const cryptoKey = await crypto.subtle.importKey(
"raw", keyBytes, { name: "HMAC", hash: type },
true, ["sign"]
);
const sig = await crypto.subtle.sign("HMAC", cryptoKey, messageBytes);
const data = String.fromCharCode(...new Uint8Array(sig));
return base64 ? btoa(data) : data;
}
(async function() {
let key = "YdkQZp9Pq0OsKT5TlFzrgry7j1nw0XEmbNFm86zNU3+XFEmM/I+WxrAZE7yjFAD3iWJTQ10VN2+JK3fz4b3Viw==";
let message = "1614117737467myJSON.json" + '{"json_data": "to-be-encoded"}';
let hmac = await hash_hmac("SHA-256", message, atob(key), true);
console.log(
btoa("1614117737467;" + hmac)
);
})();
哪个returnsMTYxNDExNzczNzQ2NztBeGxFRVJCTzVYWm5KN2ZHNCtoeWlxalJ0VmxZQmJpekNUSEwzcldMQVhzPQ==
为什么这些看似相同的脚本返回不同的结果?
这与 php/javascript 中处理二进制数组或字符串的差异有关。如果您将 base64_decode($key)
更改为 $key
(php) 并将 atob(key)
更改为 key
(javascript) 它工作正常。
编辑:
错误在 unescape(encodeURIComponent(str))
,只需删除函数并更改为 str
即可。
我有两个生成 SHA256 HMAC 的脚本,其中包含明文消息和 Base64 编码密钥。一个写在PHP,另一个写在JavaScript。 PHP 脚本 returns 正确的 HMAC,但由于某种原因 JS 版本没有。这是什么原因造成的?
这里是代码示例,带有经过编辑(本质上仍然相似)的密钥。
PHP
<?php
header("content-type: text/plain");
$key = "YdkQZp9Pq0OsKT5TlFzrgry7j1nw0XEmbNFm86zNU3+XFEmM/I+WxrAZE7yjFAD3iWJTQ10VN2+JK3fz4b3Viw==";
$message = "1614117737467myJSON.json" . '{"json_data": "to-be-encoded"}';
$hmac = base64_encode(hash_hmac('sha256', $message, base64_decode($key), true));
// to base64
echo base64_encode("1614117737467;" . $hmac);
这个脚本,returnsMTYxNDExNzczNzQ2NztFdXcwQ1l0bTBTMkdIdnZ2ZnN2ZGFkTEFDMGVPbVlJeHFzZk9PQWExS1BzPQ==
JS
async function hash_hmac(type, message, key, base64) {
const getUtf8Bytes = str =>
new Uint8Array(
[...unescape(encodeURIComponent(str))].map(c => c.charCodeAt(0))
);
const keyBytes = getUtf8Bytes(key);
const messageBytes = getUtf8Bytes(message);
const cryptoKey = await crypto.subtle.importKey(
"raw", keyBytes, { name: "HMAC", hash: type },
true, ["sign"]
);
const sig = await crypto.subtle.sign("HMAC", cryptoKey, messageBytes);
const data = String.fromCharCode(...new Uint8Array(sig));
return base64 ? btoa(data) : data;
}
(async function() {
let key = "YdkQZp9Pq0OsKT5TlFzrgry7j1nw0XEmbNFm86zNU3+XFEmM/I+WxrAZE7yjFAD3iWJTQ10VN2+JK3fz4b3Viw==";
let message = "1614117737467myJSON.json" + '{"json_data": "to-be-encoded"}';
let hmac = await hash_hmac("SHA-256", message, atob(key), true);
console.log(
btoa("1614117737467;" + hmac)
);
})();
哪个returnsMTYxNDExNzczNzQ2NztBeGxFRVJCTzVYWm5KN2ZHNCtoeWlxalJ0VmxZQmJpekNUSEwzcldMQVhzPQ==
为什么这些看似相同的脚本返回不同的结果?
这与 php/javascript 中处理二进制数组或字符串的差异有关。如果您将 base64_decode($key)
更改为 $key
(php) 并将 atob(key)
更改为 key
(javascript) 它工作正常。
编辑:
错误在 unescape(encodeURIComponent(str))
,只需删除函数并更改为 str
即可。