/**
 * Package hkdf implements HKDF key derivation function.
 */ import { Hash } from "@stablelib/hash" ; import { HMAC , hmac } from "@stablelib/hmac" ; import { wipe } from "@stablelib/wipe" ; /**
 * HMAC-based Extract-and-Expand Key Derivation Function.
 *
 * Implements HKDF from RFC5869.
 *
 * Expands the given master key with salt and info into
 * a limited stream of key material.
 */ export class HKDF { private _hmac : HMAC ; private _buffer : Uint8Array ; private _bufpos : number ; private _counter = new Uint8Array ( 1 ) ; private _hash : new ( ) => Hash ; private _info ? : Uint8Array ; /**
     * Create a new HKDF instance for the given hash function
     * with the master key, optional salt, and info.
     *
     * - Master key is a high-entropy secret key (not a password).
     * - Salt is a non-secret random value.
     * - Info is application- and/or context-specific information.
     */ constructor ( hash , key , salt = new Uint8Array ( 0 ) , info ? ) { this . _hash = hash ; this . _info = info ; const okm = hmac ( this . _hash , salt , key ) ; this . _hmac = new HMAC ( hash , okm ) ; this . _buffer = new Uint8Array ( this . _hmac . digestLength ) ; this . _bufpos = this . _buffer . length ; } private _fillBuffer ( ) { this . _counter [ 0 ] ++ ; const ctr = this . _counter [ 0 ] ; if ( ctr === 0 ) { throw new Error ( "hkdf: cannot expand more" ) ; } this . _hmac . reset ( ) ; if ( ctr > 1 ) { this . _hmac . update ( this . _buffer ) ; } if ( this . _info ) { this . _hmac . update ( this . _info ) ; } this . _hmac . update ( this . _counter ) ; this . _hmac . finish ( this . _buffer ) ; this . _bufpos = 0 ; } /**
     * Expand returns next key material of the given length.
     *
     * It throws if expansion limit is reached (which is
     * 254 digests of the underlying HMAC function).
     */ expand ( length ) { const out = new Uint8Array ( length ) ; for ( let i = 0 ; i < out . length ; i ++ ) { if ( this . _bufpos === this . _buffer . length ) { this . _fillBuffer ( ) ; } out [ i ] = this . _buffer [ this . _bufpos ++ ] ; } return out ; } clean ( ) { this . _hmac . clean ( ) ; wipe ( this . _buffer ) ; wipe ( this . _counter ) ; this . _bufpos = 0 ; } }