Skip to content

Instantly share code, notes, and snippets.

@cendyne
Last active January 30, 2023 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cendyne/e56a53ec0b2c65c42822162d537020c3 to your computer and use it in GitHub Desktop.
Save cendyne/e56a53ec0b2c65c42822162d537020c3 to your computer and use it in GitHub Desktop.
HKDF derive key web crypto subtle
// We generated this above as an example IND key derivation key
let openSSLSecretKey = '0de81e851cd7995626ad4c3e160ae1c449af4e15c8ceabd44fb75be581adfbaa';
// Parse the hex string into a Uint8Array
let ikm = Uint8Array.from(openSSLSecretKey
.match(/.{1,2}/g)
.map((byte) => parseInt(byte, 16)));
// Import the raw key data
let kdk = await crypto.subtle.importKey(
'raw',
ikm,
'HKDF',
false, // KDF keys cannot be exported
['deriveKey', 'deriveBits']);
// We are going to create a signing key from the secret
// If we create other keys too, they should not have the
// same label!
let label = 'signing key';
// This function works with bytes.
// Therefore we must encode our label which is text to bytes.
let encoder = new TextEncoder();
let info = encoder.encode(label);
// A salt is a required property, even though it is empty.
let salt = new Uint8Array(); // Nothing inside!
// Derive a signing key from the key derivation key
let signingKey = await crypto.subtle.deriveKey(
// Again, the salt is empty
// The info will uniquely describe this key
{name: 'HKDF', salt, info, hash: 'SHA-256'},
// The input key material we decoded from hex above
// and then wrapped in a CryptoKey
kdk,
// We're creating an HMAC-SHA-256 key
{name: 'HMAC', hash: 'SHA-256'},
// We do not need to export it,
// since we can create it deterministically.
false,
// it needs to sign and verify
['sign', 'verify']);
// Prove that it works
// Let's sign "Hello world"
let message = 'Hello world';
let encodedMessage = encoder.encode(message);
let tag = await crypto.subtle.sign(
{name: 'HMAC'},
signingKey,
encodedMessage);
console.log(`Message ${message} - tag: ${btoa(tag)}`);
// Message Hello world - tag: W29iamVjdCBBcnJheUJ1ZmZlcl0=
// And prove that it can match its own mac too.
let verified = await crypto.subtle.verify(
{name: 'HMAC'},
signingKey,
tag,
encodedMessage);
console.log(`Verify?: ${verified}`);
// Verify?: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment