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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 1x 1x 13x 2x 11x 3x 8x 8x 1x 7x 7x 7x 7x 7x 224x 224x 7x 1x 2x 2x 2x 1x | /** * @file Multi-Factor Derived Key Threshold Hints * @copyright Multifactor, Inc. 2022–2025 * * @description * Add factor hints to a multi-factor derived key * * @author Vivek Nair (https://nair.me) <[email protected]> */ const { hkdfSync } = require('crypto') const { decrypt } = require('../../crypt') /** * Get a (probabilistic) hint for a factor to (usually) help verify which factor is wrong. * Makes the key slightly easier to brute-force (about 2^bits times easier), so be careful. * * @example * const setup = await mfkdf.setup.key([ * await mfkdf.setup.factors.password("password1", { * id: "password1", * }), * ]); * * const hint = setup.getHint("password1", 7); // -> 1011000 * * const derived = await mfkdf.derive.key(setup.policy, { * password1: mfkdf.derive.factors.password("password1"), * }); * * const hint2 = derived.getHint("password1", 7); // -> 1011000 * hint2.should.equal(hint); * * @param {string} factor - Factor ID to add hint for * @param {string} [bits=7] - Bits of entropy to reveal (default: 7 bits; more is risky) * @returns {Buffer} Derived sub-key * @author Vivek Nair (https://nair.me) <[email protected]> * @since 2.0.0 * @memberOf MFKDFDerivedKey * @async */ function getHint (factor, bits = 7) { if (typeof factor !== 'string' || factor.length === 0) { throw new TypeError('factor id must be a non-empty string') } if (typeof bits !== 'number' || bits < 1 || bits > 256) { throw new TypeError('bits must be a number between 1 and 256') } // get factor data const factorData = this.policy.factors.find((f) => f.id === factor) if (!factorData) { throw new RangeError('factor id not found in policy') } const pad = Buffer.from(factorData.secret, 'base64') const secretKey = Buffer.from( hkdfSync( 'sha256', this.key, Buffer.from(factorData.salt, 'base64'), 'mfkdf2:factor:secret:' + factorData.id, 32 ) ) const factorMaterial = decrypt(pad, secretKey) const buffer = Buffer.from( hkdfSync( 'sha256', factorMaterial, Buffer.from(factorData.salt, 'base64'), 'mfkdf2:factor:hint:' + factorData.id, 32 ) ) const binaryString = [...buffer] .map((byte) => byte.toString(2).padStart(8, '0')) .reduce((acc, bits) => acc + bits, '') return binaryString.slice(-1 * bits) } module.exports.getHint = getHint /** * Add a (probabilistic) hint for a factor to (usually) help verify which factor is wrong. * Permanently adds the hint to the key policy, and throws an error when the factor is wrong. * Makes the key slightly easier to brute-force (about 2^bits times easier), so be careful. * Overrides the existing hint if one already exists. * * @example * const setup = await mfkdf.setup.key( * [ * await mfkdf.setup.factors.password('password1', { * id: 'password1' * }) * ], * { * integrity: false * } * ) * * setup.addHint('password1') * * await mfkdf.derive * .key( * setup.policy, * { * password1: mfkdf.derive.factors.password('password2') * }, * false * ) * .should.be.rejectedWith(RangeError) * * @param {string} factor - Factor ID to add hint for * @param {string} [bits=7] - Bits of entropy to reveal (default: 7 bits; more is risky) * @returns {Buffer} Derived sub-key * @author Vivek Nair (https://nair.me) <[email protected]> * @since 2.0.0 * @memberOf MFKDFDerivedKey * @async */ function addHint (factor, bits = 7) { const hint = this.getHint(factor, bits) const factorData = this.policy.factors.find((f) => f.id === factor) factorData.hint = hint } module.exports.addHint = addHint |