From ede06757a3f8bf344b015f95eb835277e971d2b7 Mon Sep 17 00:00:00 2001 From: Pascal Perrenoud Date: Thu, 6 Jun 2024 01:50:10 +0200 Subject: [PATCH] Implement kdf --- src/kdf.ts | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/kdf.ts diff --git a/src/kdf.ts b/src/kdf.ts new file mode 100644 index 0000000..7d6a2c2 --- /dev/null +++ b/src/kdf.ts @@ -0,0 +1,90 @@ +import logger from 'log' +const log = logger('crypto:kdf') + +export enum Usage { + sign, + wrap, +} +export async function hkdf(key: Uint8Array, usage: Usage) : Promise { + log.trace("HKDF") + log.trace(`usage : ${usage === Usage.sign ? 'sign' : 'wrap'}`) + + const material = await crypto.subtle.importKey( + "raw", + key, + "HKDF", + false, + ["deriveKey", "deriveBits"], + ) + + if (usage === Usage.wrap) { + return crypto.subtle.deriveKey( + { + name: "HKDF", + hash: "SHA-512", + salt: new Uint8Array(32), + info: new TextEncoder().encode("wrap"), + }, + material, + {name: "AES-GCM", length: 256}, + false, + ["wrapKey", "unwrapKey"], + ) + } else if (usage === Usage.sign) { + const buffer = await crypto.subtle.deriveBits( + { + name: "HKDF", + hash: "SHA-512", + salt: new Uint8Array(32), + info: new TextEncoder().encode("sign"), + }, + material, + 256 + ) + return new Uint8Array(buffer) + } else { + log.warn(`Called HKDF with unknown enum value : ${usage}`) + throw "I don't even know what to say." + } +} + +export async function pbkdf(salt: Uint8Array, password: string) : Promise { + log.trace("PBKDF") + const material = await crypto.subtle.importKey( + "raw", + new TextEncoder().encode(password), + "PBKDF2", + false, + ["deriveBits"], + ) + + const buffer = await crypto.subtle.deriveBits( + { + name: "PBKDF2", + salt, + iterations: 250_000, + hash: "SHA-512", + }, + material, + 256, + ) + + return new Uint8Array(buffer) +} + +export function ecdh(privkey: CryptoKey, pubkey: CryptoKey) : Promise { + log.trace("ECDH") + return crypto.subtle.deriveKey( + { + name: "ECDH", + public: pubkey, + }, + privkey, + { + name: "AES-GCM", + length: 256, + }, + false, + ["wrapKey", "unwrapKey"], + ) +}