Password-derived keys are only as strong as the passwords they're based on. Securely leverage all of your users' authentication factors with MFKDF.
Secure
based on argon2id
Fast
≤ 20ms overhead
Transparent
fully open-source
Flexible
modular design
Most users have notoriously insecure passwords, with up to 81% of them re-using passwords across multiple accounts. MFKDF improves upon password-based key derivation by using all of a user's authentication factors (not just their password) to derive a key. MFKDF supports deriving key material from a variety of common factors, including HOTP, TOTP, and hardware tokens like YubiKey.
const derivedKey = await mfkdf.derive.key(JSON.parse(keyPolicy), {
password: mfkdf.derive.factors.password('Tr0ub4dour'),
hotp: mfkdf.derive.factors.hotp(365287),
recovery: mfkdf.derive.factors.uuid('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')
})
console.log(derivedKey.key.toString('hex')) // -> 34d20ced439ec2f871c96ca377f25771
All factors must be simultaneously correctly guessed to derive a key using MFKDF, meaning that they can't be individually brute-force attacked. MFKDF keys are thus exponentially harder to crack while remaining just as fast to derive on the fly as password-derived keys for users with the correct credentials.
(await mfkdf.setup.key([
await mfkdf.setup.factors.password('Tr0ub4dour')
])).entropyBits.real // -> 16.53929514807314
(await mfkdf.setup.key([
await mfkdf.setup.factors.password('Tr0ub4dour'),
await mfkdf.setup.factors.hotp(),
await mfkdf.setup.factors.hmacsha1()
])).entropyBits.real // -> 196.470863717397314
MFKDF is not all or nothing: factor requirements can be combined based on simple logical operators like "AND" and "OR." In fact, multi-factor derived keys can enforce arbitrarily complex authentication policies purely cryptographically, without requiring a software reference monitor or trusted hardware.
const policyBasedKey = await mfkdf.policy.setup(
await mfkdf.policy.or(
await mfkdf.setup.factors.uuid({ id: 'recoveryCode' }),
await mfkdf.policy.and(
await mfkdf.setup.factors.password('Tr0ub4dour'),
await mfkdf.setup.factors.totp()
)
)
)
Password-derived keys can't be recoverred after a password is forgotten without creating a centralized point of failure (eg. a master key). Threshold-based multi-factor derived keys can be used to trustlessly recover lost factors on the client side without storing any server-side secrets.
const key = await mfkdf.derive.key(JSON.parse(keyPolicy), {
hotp: mfkdf.derive.factors.hotp(365287),
recoveryCode: mfkdf.derive.factors.uuid('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d')
})
await key.recoverFactor(
await mfkdf.setup.factors.password('myNewPassword', { id: 'password' })
) // modify key to use new password factor