How can I get HMAC-SHA512(key, data) in the browser using Crypto Web API (window.crypto
)?
Currently I am using CryptoJS library and it is pretty simple:
CryptoJS.HmacSHA512("myawesomedata", "mysecretkey").toString();
Result is 91c14b8d3bcd48be0488bfb8d96d52db6e5f07e5fc677ced2c12916dc87580961f422f9543c786eebfb5797bc3febf796b929efac5c83b4ec69228927f21a03a
.
I want to get rid of extra dependencies and start using Crypto Web API instead. How can I get the same result with it?
Answering my own question. The code below returns the same result as CryptoJS.HmacSHA512("myawesomedata", "mysecretkey").toString();
There are promises everywhere as WebCrypto is asynchronous:
// encoder to convert string to Uint8Array
var enc = new TextEncoder("utf-8");
window.crypto.subtle.importKey(
"raw", // raw format of the key - should be Uint8Array
enc.encode("mysecretkey"),
{ // algorithm details
name: "HMAC",
hash: {name: "SHA-512"}
},
false, // export = false
["sign", "verify"] // what this key can do
).then( key => {
window.crypto.subtle.sign(
"HMAC",
key,
enc.encode("myawesomedata")
).then(signature => {
var b = new Uint8Array(signature);
var str = Array.prototype.map.call(b, x => x.toString(16).padStart(2, '0')).join("")
console.log(str);
});
});
The following is a copy of the ✅ answer. This time we are using async/await
for clean syntax. This approach also offers a base64 encoded digest.
secret
is the secret key that will be used to sign the body
.body
is the string-to-sign.enc
is a text encoder that converts the UTF-8 to JavaScript byte arrays.algorithm
is a JS object which is used to identify the signature methods.key
is a CryptoKey.signature
is the byte array hash.digest
is the base64 encoded signature.The JavaScript code follows:
(async ()=>{
'use strict';
let secret = "sec-demo"; // the secret key
let enc = new TextEncoder("utf-8");
let body = "GET\npub-demo\n/v2/auth/grant/sub-key/sub-demo\nauth=myAuthKey&g=1&target-uuid=user-1×tamp=1595619509&ttl=300";
let algorithm = { name: "HMAC", hash: "SHA-256" };
let key = await crypto.subtle.importKey("raw", enc.encode(secret), algorithm, false, ["sign", "verify"]);
let signature = await crypto.subtle.sign(algorithm.name, key, enc.encode(body));
let digest = btoa(String.fromCharCode(...new Uint8Array(signature)));
console.log(digest);
})();
The original answer on this page was helpful in a debugging effort earlier today. We're using it to help identify a bug in our documentation for creating signatures for granting access tokens to use APIs with read/write permissions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With