/*! * algorithms/hkdf.js - HMAC-based Extract-and-Expand Key Derivation * * Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file. */ "use strict"; var CONSTANTS = require("./constants.js"), hmac = require("./hmac.js"); function hkdfDeriveFn(name) { var hash = name.replace("HKDF-", ""), op = name.replace("HKDF-SHA-", "HS"); // NOTE: no nodejs/webcrypto/fallback model, since this HKDF is // implemented using the HMAC algorithms var fn = function(key, props) { var hashLen = CONSTANTS.HASHLENGTH[hash] / 8; if ("string" === typeof op) { op = hmac[op].sign; } // prepare options props = props || {}; var salt = props.salt; if (!salt || 0 === salt.length) { salt = Buffer.alloc(hashLen); } var info = props.info || Buffer.alloc(0); var keyLen = props.length || hashLen; var promise; // Setup Expansion var N = Math.ceil(keyLen / hashLen), okm = [], idx = 0; function expand(key, T) { if (N === idx++) { return Buffer.concat(okm).slice(0, keyLen); } if (!T) { T = Buffer.alloc(0); } T = Buffer.concat([T, info, Buffer.from([idx])]); T = op(key, T); T = T.then(function(result) { T = result.mac; okm.push(T); return expand(key, T); }); return T; } // Step 1: Extract promise = op(salt, key, { length: salt.length * 8 }); promise = promise.then(function(result) { // Step 2: Expand return expand(result.mac); }); return promise; }; return fn; } // Public API // * [name].derive var hkdf = {}; [ "HKDF-SHA-1", "HKDF-SHA-256", "HKDF-SHA-384", "HKDF-SHA-512" ].forEach(function(name) { hkdf[name] = { derive: hkdfDeriveFn(name) }; }); module.exports = hkdf;