policy/setup.js

/**
 * @file MFKDF Policy Setup
 * @copyright Multifactor 2022 All Rights Reserved
 *
 * @description
 * Setup MFKDF key derivation policy
 *
 * @author Vivek Nair (https://nair.me) <[email protected]>
 */

const setupKey = require('../setup/key').key
const validate = require('./validate').validate

/**
 * Validate and setup a policy-based multi-factor derived key
 *
 * @example
 * // setup key that can be derived from passwordA AND (passwordB OR passwordC)
 * const setup = await mfkdf.policy.setup(
 *   await mfkdf.policy.and(
 *     await mfkdf.setup.factors.password('passwordA', { id: 'passwordA' }),
 *     await mfkdf.policy.or(
 *       await mfkdf.setup.factors.password('passwordB', { id: 'passwordB' }),
 *       await mfkdf.setup.factors.password('passwordC', { id: 'passwordC' })
 *     )
 *   ), { size: 8 }
 * )
 *
 * // derive key with passwordA and passwordC (or passwordA and passwordB)
 * const derive = await mfkdf.policy.derive(setup.policy, {
 *   passwordA: mfkdf.derive.factors.password('passwordA'),
 *   passwordC: mfkdf.derive.factors.password('passwordC'),
 * })
 *
 * setup.key.toString('hex') // -> e16a227944a65263
 * derive.key.toString('hex') // -> e16a227944a65263
 *
 * @param {MFKDFFactor} factor - Base factor used to derive this key
 * @param {Object} [options] - Configuration options
 * @param {string} [options.id] - Unique identifier for this key; random UUIDv4 generated by default
 * @param {number} [options.size=32] - Size of derived key, in bytes
 * @param {number} [options.threshold] - Number of factors required to derive key; factors.length by default (all required)
 * @param {Buffer} [options.salt] - Cryptographic salt; generated via secure PRG by default (recommended)
 * @param {string} [options.kdf='argon2id'] - KDF algorithm to use; pbkdf2, bcrypt, scrypt, argon2i, argon2d, or argon2id
 * @param {number} [options.pbkdf2rounds=310000] - Number of rounds to use if using pbkdf2
 * @param {string} [options.pbkdf2digest='sha256'] - Hash function to use if using pbkdf2; sha1, sha256, sha384, or sha512
 * @param {number} [options.bcryptrounds=10] - Number of rounds to use if using bcrypt
 * @param {number} [options.scryptcost=16384] - Iterations count (N) to use if using scrypt
 * @param {number} [options.scryptblocksize=8] - Block size (r) to use if using scrypt
 * @param {number} [options.scryptparallelism=1] - Parallelism factor (p) to use if using scrypt
 * @param {number} [options.argon2time=2] - Iterations to use if using argon2
 * @param {number} [options.argon2mem=24576] - Memory to use if using argon2
 * @param {number} [options.argon2parallelism=1] - Parallelism to use if using argon2
 * @returns {MFKDFDerivedKey} A multi-factor derived key object
 * @author Vivek Nair (https://nair.me) <[email protected]>
 * @since 0.16.0
 * @memberOf policy
 */
async function setup (factor, options) {
  const key = await setupKey([factor], options)
  if (!validate(key.policy)) throw new RangeError('policy contains duplicate ids')
  return key
}
module.exports.setup = setup