[![NPM Version](https://img.shields.io/npm/v/futoin-hkdf.svg?style=flat)](https://www.npmjs.com/package/futoin-hkdf) [![NPM Downloads](https://img.shields.io/npm/dm/futoin-hkdf.svg?style=flat)](https://www.npmjs.com/package/futoin-hkdf) [![stable](https://img.shields.io/badge/stability-stable-green.svg?style=flat)](https://www.npmjs.com/package/futoin-hkdf) [![NPM](https://nodei.co/npm/futoin-hkdf.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/futoin-hkdf/) # About Node.js implementation of [RFC5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF)](https://tools.ietf.org/html/rfc5869). Additionally, it supports a `HKDF-Expand-Label` variation based on [RFC8446: The Transport Layer Security (TLS) Protocol Version 1.3, section 7.1. Key Schedule](https://datatracker.ietf.org/doc/html/rfc8446#section-7.1). The implementation is fully compliant with test vectors provided in the RFC. There are alternative modules, but they are: * much less performing and/or * have quite poor code quality at the moment and/or * are not compliant with RFC (e.g. work only with string parameters) and/or * not working with current Node.js versions and/or * do not support arbitrary hash functions and/or * not reliable dependency for FutoIn™ Security concept in general. Standalone HKDF `extract()` and `expand()` actions are also available for advanced usage. **Documentation** --> [FutoIn™ Guide](https://futoin.org/docs/miscjs/hkdf/) Author: [Andrey Galkin](mailto:andrey@futoin.org) # Performance comparison The figures in "derived keys per second". * **futoin-hkdf** - **74 642** - fully compliant * `node-hdkf`/`hdkf` modules - *57 707* (~22% slower) - seems to be broken by design - **produces wrong results with RFC test vectors** * `ctrlpanel-hdkf` - *52 181* (~30% slower) - seems to be compliant * `@stablelib/hkdf` - *39 808* (~46% slower) - seems to be compliant # Installation for Node.js Command line: ```sh $ npm install futoin-hkdf --save ``` or: ```sh $ yarn add futoin-hkdf --save ``` # Examples ```javascript const hkdf = require('futoin-hkdf'); // Parameter overview //------------------- // initial keying material const ikm = 'string-or-buffer'; // required output length in bytes const length = 16; // can be empty string or false equivalent const salt = 'strongly-encouraged'; // optional parameter const info = 'optional-context'; // HMAC hashing algorithm to use const hash = 'SHA-256'; // Generic derivation //------------------- hkdf(ikm, length, {salt, info, hash}); // Buffer(length) - derived key hkdf(ikm, length, {salt, info, hash}).toString('hex'); // String(2*length) // NOTE: all optional paramaters are passed in object // With some parameters omitted //------------------- hkdf(ikm, length, {salt}); hkdf(ikm, length, {info}); hkdf(ikm, length, {hash}); hkdf(ikm, length); // Advanced usage (only if you know what you are doing) //------------------- // As in underlying Node.js crypto library const lhash = hash.toLowerCase().replace( '-', '' ); // 'sha256' hkdf.hash_length(lhash); // get hash_len hkdf.extract(lhash, hash_len, ikm, salt); // run only step #1 hkdf.expand(lhash, hash_len, prk, length, info); // run only step #2 // TLS v1.3+ //------------------- const hkdf_tls = require('futoin-hkdf/tls'); const label = 'tls13 ...'; const context = Buffer.from( /* E.g some binary hash generation */ '' ); hkdf_tls(ikm, length, {salt, label, context, hash}); // Buffer(length) - derived key // Advanced usage hkdf_tls.expand_label(lhash, hash_len, prk, length, label, context); // Same as: hkdf.expand(lhash, hash_len, prk, length, hkdf_tls.info(length, label, context)); ``` # API documentation ## Functions
hkdf(ikm, length, salt, info, hash)Buffer

HMAC-based Extract-and-Expand Key Derivation Function (HKDF)

tls(ikm, length, salt, label, info, hash)Buffer

TLS v1.3 HKDF-extract + HKFD-Expand-Label action

## hkdf(ikm, length, salt, info, hash) ⇒ Buffer HMAC-based Extract-and-Expand Key Derivation Function (HKDF) **Kind**: global function **Returns**: Buffer - Raw buffer with derived key of @p length bytes | Param | Type | Default | Description | | --- | --- | --- | --- | | ikm | Buffer \| string | | Initial Keying Material | | length | integer | | Required byte length of output | | salt | Buffer \| string | '' | Optional salt (recommended) | | info | Buffer \| string | '' | Optional context (safe to skip) | | hash | string | "'SHA-256'" | HMAC hash function to use | * [hkdf(ikm, length, salt, info, hash)](#hkdf) ⇒ Buffer * [.hash_length(hash)](#hkdf.hash_length) ⇒ integer * [.extract(hash, hash_len, ikm, salt)](#hkdf.extract) ⇒ Buffer * [.expand(hash, hash_len, prk, length, info)](#hkdf.expand) ⇒ Buffer ### hkdf.hash\_length(hash) ⇒ integer Get expected hash length. **Kind**: static method of [hkdf](#hkdf) **Returns**: integer - hash digest byte length **Note**: Values are hardcoded with fallback for unknown algorithms. | Param | Type | Description | | --- | --- | --- | | hash | string | Hash algorithm (as in underlying Node.js crypto library) | ### hkdf.extract(hash, hash_len, ikm, salt) ⇒ Buffer HKDF extract action. **Kind**: static method of [hkdf](#hkdf) **Returns**: Buffer - A buffer with pseudorandom key **Note**: Values are hardcoded with fallback for unknown algorithms. | Param | Type | Description | | --- | --- | --- | | hash | string | Hash algorithm (as in underlying Node.js crypto library) | | hash_len | integer | Hash digest length | | ikm | Buffer \| string | Initial Keying Material | | salt | Buffer \| string | Optional salt (recommended) | ### hkdf.expand(hash, hash_len, prk, length, info) ⇒ Buffer HKDF expand action. **Kind**: static method of [hkdf](#hkdf) **Returns**: Buffer - A buffer with output keying material **Note**: Values are hardcoded with fallback for unknown algorithms. | Param | Type | Description | | --- | --- | --- | | hash | string | Hash algorithm (as in underlying Node.js crypto library) | | hash_len | integer | Hash digest length | | prk | Buffer \| string | A buffer with pseudorandom key | | length | integer | length of output keying material in octets | | info | Buffer \| string | Optional context (safe to skip) | ## tls(ikm, length, salt, label, info, hash) ⇒ Buffer TLS v1.3 HKDF-extract + HKFD-Expand-Label action **Kind**: global function **Returns**: Buffer - Raw buffer with derived key of @p length bytes **Note**: label and context are limited to 255 bytes! | Param | Type | Default | Description | | --- | --- | --- | --- | | ikm | Buffer \| string | | Initial Keying Material | | length | integer | | Required byte length of output | | salt | Buffer \| string | '' | Optional salt (required by fact) | | label | Buffer \| string | '' | Optional label (required by fact) | | info | Buffer \| string | '' | Optional context (safe to skip) | | hash | string | "'SHA-256'" | HMAC hash function to use | * [tls(ikm, length, salt, label, info, hash)](#tls) ⇒ Buffer * [.info(length, label, context)](#tls.info) ⇒ Buffer * [.expand_label(hash, hash_len, prk, length, label, context)](#tls.expand_label) ⇒ Buffer ### tls.info(length, label, context) ⇒ Buffer Encode HKDF context parameter in TLS v1.3 style based on RFC8446 TLS v1.3. **Kind**: static method of [tls](#tls) **Returns**: Buffer - A buffer with encoded HKDF context **Note**: label and context are limited to 255 bytes! | Param | Type | Description | | --- | --- | --- | | length | integer | length of output keying material in octets | | label | string | ASCII label | | context | Buffer \| string | Binary context or empty string | ### tls.expand\_label(hash, hash_len, prk, length, label, context) ⇒ Buffer TLS-HKDF expand label action - a HKDF-Expand-Label variation based on RFC8446 TLS v1.3. **Kind**: static method of [tls](#tls) **Returns**: Buffer - A buffer with output keying material **Note**: label and context are limited to 255 bytes! | Param | Type | Description | | --- | --- | --- | | hash | string | Hash algorithm (as in underlying Node.js crypto library) | | hash_len | integer | Hash digest length | | prk | Buffer \| string | A buffer with pseudorandom key | | length | integer | length of output keying material in octets | | label | string | ASCII label | | context | Buffer \| string | Binary context or empty string |