1 const HASH_ALGORITHM = 'SHA-256';
2 const KEY_LENGTH_BYTES = 32;
3 export type HmacCryptoKey = CryptoKey;
5 type HmacKeyUsage = 'sign' | 'verify';
8 * Import an HMAC-SHA256 key in order to use it with `signData` and `verifyData`.
10 export const importKey = async (
12 keyUsage: HmacKeyUsage[] = ['sign', 'verify']
13 ): Promise<HmacCryptoKey> => {
14 // From https://datatracker.ietf.org/doc/html/rfc2104:
15 // The key for HMAC can be of any length (keys longer than B bytes are first hashed using H).
16 // However, less than L bytes (L = 32 bytes for SHA-256) is strongly discouraged as it would
17 // decrease the security strength of the function. Keys longer than L bytes are acceptable
18 // but the extra length would not significantly increase the function strength.
19 // (A longer key may be advisable if the randomness of the key is considered weak.)
20 if (key.length < KEY_LENGTH_BYTES) {
21 throw new Error('Unexpected HMAC key size: key is too short');
23 return crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: HASH_ALGORITHM }, false, keyUsage);
27 * Sign data using HMAC-SHA256
28 * @param key - WebCrypto secret key for signing
29 * @param data - data to sign
30 * @param additionalData - additional data to authenticate
32 export const signData = async (key: HmacCryptoKey, data: Uint8Array) => {
33 const signatureBuffer = await crypto.subtle.sign({ name: 'HMAC', hash: HASH_ALGORITHM }, key, data);
34 return new Uint8Array(signatureBuffer);
38 * Verify data using HMAC-SHA256
39 * @param key - WebCrypto secret key for verification
40 * @param signature - signature over data
41 * @param data - data to verify
42 * @param additionalData - additional data to authenticate
44 export const verifyData = async (key: HmacCryptoKey, signature: Uint8Array, data: Uint8Array) => {
45 return crypto.subtle.verify({ name: 'HMAC', hash: HASH_ALGORITHM }, key, signature, data);