最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to specify desired HKDF output length with `crypto.subtle.deriveKey` - Stack Overflow

programmeradmin7浏览0评论

The web crypto API defines two different KDF utilities, namely deriveBits and deriveKey. While the former allows you to specify the desired output length (RFC 5869 calls this parameter L), the latter doesn't seem to do so.

I need to use HKDF with SHA-512 (as the spec I'm implementing requires this) in order to derive an HMAC-SHA256 key. In other words, 256 output bits are sufficient; but only deriveBits seems to have a corresponding parameter:

const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(32), { name: 'HKDF' }, false, ['deriveKey', 'deriveBits'])
const salt = new Uint8Array(16)
const info = new Uint8Array(8)

// deriveBits → derives 256 bit:
const rawHmacKey1 = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, 256);
const hmacKey1 = await crypto.subtle.importKey('raw', rawHmacKey1, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported1 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey1));
console.log(btoa(exported1)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAz

// deriveKey → derives 512 bit:
const hmacKey2 = await crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported2 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey2));
console.log(btoa(exported2)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAzLDUwLDE4Myw3Miw4OSwyMDQsMTcsMzksMTY5LDE4OCw5Niw3NSw5NSwxMTMsMjQ3LDExNywxOTQsNDYsMTY0LDIyOSwyMTMsNzUsMjE5LDI0NCwyMjYsMjAwLDE2MCw5NCwxNCw3MiwxNjMsMTcwLDEwMg==

Note that when using deriveKey I explicitly specified { name: 'HMAC', hash: 'SHA-256' } as key usage parameter. Regardless the derived key length seems to solely depend on the specified hash algorithm (SHA-512 → 64 bytes).

As I would prefer to use deriveKey, my question is: How do I specify the desired output key size?

The web crypto API defines two different KDF utilities, namely deriveBits and deriveKey. While the former allows you to specify the desired output length (RFC 5869 calls this parameter L), the latter doesn't seem to do so.

I need to use HKDF with SHA-512 (as the spec I'm implementing requires this) in order to derive an HMAC-SHA256 key. In other words, 256 output bits are sufficient; but only deriveBits seems to have a corresponding parameter:

const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(32), { name: 'HKDF' }, false, ['deriveKey', 'deriveBits'])
const salt = new Uint8Array(16)
const info = new Uint8Array(8)

// deriveBits → derives 256 bit:
const rawHmacKey1 = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, 256);
const hmacKey1 = await crypto.subtle.importKey('raw', rawHmacKey1, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported1 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey1));
console.log(btoa(exported1)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAz

// deriveKey → derives 512 bit:
const hmacKey2 = await crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported2 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey2));
console.log(btoa(exported2)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAzLDUwLDE4Myw3Miw4OSwyMDQsMTcsMzksMTY5LDE4OCw5Niw3NSw5NSwxMTMsMjQ3LDExNywxOTQsNDYsMTY0LDIyOSwyMTMsNzUsMjE5LDI0NCwyMjYsMjAwLDE2MCw5NCwxNCw3MiwxNjMsMTcwLDEwMg==

Note that when using deriveKey I explicitly specified { name: 'HMAC', hash: 'SHA-256' } as key usage parameter. Regardless the derived key length seems to solely depend on the specified hash algorithm (SHA-512 → 64 bytes).

As I would prefer to use deriveKey, my question is: How do I specify the desired output key size?

Share Improve this question edited Jan 17 at 20:29 Sebastian S asked Jan 17 at 19:33 Sebastian SSebastian S 4,7124 gold badges40 silver badges67 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

The length is specified by the third parameter derivedKeyAlgorithm of deriveKey().

In the case of an HMAC, a HmacKeyGenParams is passed, which encapsulates the three parameters name, hash and length. If length is missing, as in your example, the block size of the hash function is used by default, which is 512 bits for SHA-256 (s. here) and thus explains the result of your test.

If you want a 256 bits key, simply specify length:

(async () => {

const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(32), { name: 'HKDF' }, false, ['deriveKey', 'deriveBits'])
const salt = new Uint8Array(16)
const info = new Uint8Array(8)

// deriveBits → derives 256 bit:
const rawHmacKey1 = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, 256);
const hmacKey1 = await crypto.subtle.importKey('raw', rawHmacKey1, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported1 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey1));
console.log(btoa(exported1)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAz

// deriveKey → derives 256 bit:
const hmacKey2 = await crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, { name: 'HMAC', hash: 'SHA-256', length: 256 }, true, ['sign']);
const exported2 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey2));
console.log(btoa(exported2)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAz

})();


Note that your Base64 encoding is incorrect. The code below shows a working implementation.

(async () => {

const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(32), { name: 'HKDF' }, false, ['deriveKey', 'deriveBits'])
const salt = new Uint8Array(16)
const info = new Uint8Array(8)

// deriveBits → derives 256 bit:
const rawHmacKey1 = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, 256);
const hmacKey1 = await crypto.subtle.importKey('raw', rawHmacKey1, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported1 = await crypto.subtle.exportKey('raw', hmacKey1);
console.log(ab2b64(exported1)) // tQwIbxv4VU4rCl3yE72/rYhkFeMnfrPEMlY9G4/Ux8s=

// deriveKey → derives 256 bit:
const hmacKey2 = await crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, { name: 'HMAC', hash: 'SHA-256', length: 256 }, true, ['sign']);
const exported2 = await crypto.subtle.exportKey('raw', hmacKey2);
console.log(ab2b64(exported2)) //tQwIbxv4VU4rCl3yE72/rYhkFeMnfrPEMlY9G4/Ux8s=

function ab2b64(arrayBuffer) {
    return window.btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)))
}

})();

发布评论

评论列表(0)

  1. 暂无评论