Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1x 1x 1x 1x 1x 1x 462x 462x 462x 116x 116x 116x 116x 346x 13x 13x 13x 13x 13x 13x 13x 13x 333x 6x 6x 6x 327x 319x 319x 319x 318x 319x 319x 8x 7x 7x 7x 1x 1x | /** * @file Key Derivation Function (KDF) * @copyright Multifactor 2021 All Rights Reserved * * @description * Implements several key derivation functions (KDFs) that can underly the MFKDF * * @author Vivek Nair (https://nair.me) <[email protected]> */ // const argon2 = require('argon2-browser') const crypto = require('crypto') const pbkdf2 = require('pbkdf2') const bcrypt = require('bcryptjs') const scrypt = require('scrypt-js') const { hkdf } = require('@panva/hkdf') const hash = require('hash-wasm') /** * Single-factor (traditional) key derivation function; produces a derived a key from a single input. * Supports a number of underlying KDFs: pbkdf2, scrypt, bcrypt, and argon2 (recommended). * * @example * // setup kdf configuration * const config = await mfkdf.setup.kdf({ * kdf: 'pbkdf2', * pbkdf2rounds: 100000, * pbkdf2digest: 'sha256' * }); // -> { type: 'pbkdf2', params: { rounds: 100000, digest: 'sha256' } } * * // derive key * const key = await mfkdf.kdf('password', 'salt', 8, config); * key.toString('hex') // -> 0394a2ede332c9a1 * * @param {Buffer|string} input - KDF input string * @param {Buffer|string} salt - KDF salt string * @param {number} size - Size of derived key to return, in bytes * @param {Object} options - KDF configuration options * @param {string} options.type - KDF algorithm to use; hkdf, pbkdf2, bcrypt, scrypt, argon2i, argon2d, or argon2id * @param {Object} options.params - Specify parameters of chosen kdf * @param {number} options.params.rounds - Number of rounds to use * @param {number} [options.params.digest] - Hash function to use (if using pbkdf2 or hdkf) * @param {number} [options.params.blocksize] - Block size to use (if using scrypt) * @param {number} [options.params.parallelism] - Parallelism to use (if using scrypt or argon2) * @param {number} [options.params.memory] - Memory to use (if using argon2) * @returns A derived key as a Buffer * @author Vivek Nair (https://nair.me) <[email protected]> * @since 0.0.3 * @async * @memberOf kdfs */ async function kdf (input, salt, size, options) { if (typeof input === 'string') input = Buffer.from(input) if (typeof salt === 'string') salt = Buffer.from(salt) if (options.type === 'pbkdf2') { // PBKDF2 return new Promise((resolve, reject) => { pbkdf2.pbkdf2(input, salt, options.params.rounds, size, options.params.digest, (err, derivedKey) => { /* istanbul ignore if */ if (err) reject(err) else resolve(derivedKey) }) }) } else if (options.type === 'bcrypt') { // bcrypt return new Promise((resolve, reject) => { // pre-hash to maximize entropy; safe when using base64 encoding const inputhash = crypto.createHash('sha256').update(input).digest('base64') const salthash = crypto.createHash('sha256').update(salt).digest('base64').replace(/\+/g, '.') // bcrypt with fixed salt bcrypt.hash(inputhash, '$2a$' + options.params.rounds + '$' + salthash, function (err, hash) { /* istanbul ignore if */ if (err) { reject(err) } else { // use pbkdf2/sha256 for stretching pbkdf2.pbkdf2(hash, salthash, 1, size, 'sha256', (err, derivedKey) => { /* istanbul ignore if */ if (err) reject(err) else resolve(derivedKey) }) } }) }) } else if (options.type === 'scrypt') { return new Promise((resolve, reject) => { scrypt.scrypt(input, salt, options.params.rounds, options.params.blocksize, options.params.parallelism, size).then((result) => { resolve(Buffer.from(result)) }) }) } else if (options.type === 'argon2i' || options.type === 'argon2d' || options.type === 'argon2id') { return new Promise((resolve, reject) => { let argon2 = hash.argon2id if (options.type === 'argon2i') argon2 = hash.argon2i else if (options.type === 'argon2d') argon2 = hash.argon2d argon2({ password: input.toString(), salt: salt.toString(), iterations: options.params.rounds, memorySize: options.params.memory, hashLength: size, parallelism: options.params.parallelism, outputType: 'hex' }).then((result) => { resolve(Buffer.from(result, 'hex')) }) }) } if (options.type === 'hkdf') { return new Promise((resolve, reject) => { hkdf(options.params.digest, input, salt, '', size).then((result) => { resolve(Buffer.from(result)) }) }) } else { throw new RangeError('kdf should be one of pbkdf2, bcrypt, scrypt, argon2i, argon2d, or argon2id (default)') } } module.exports.kdf = kdf |