Secure

based on argon2id

Fast

≤ 20ms overhead

Transparent

fully open-source

Flexible

modular design

Knowledge
Soft Tokens
USB
Out-of-Band
Intrinsic
Knowledge
Soft Tokens
USB
Out-of-Band
Intrinsic

Go beyond passwords

Most users have notoriously insecure passwords, with up to 81% of them re-using passwords across multiple accounts. MFKDF2 improves upon password-based key derivation by using all of a user's authentication factors (not just their password) to derive a key. MFKDF2 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
14 bits
14 bits
20 bits
160 bits
14 bits
≈ 16s
194 bits
≈ 1047 yrs
14 bits
14 bits
20 bits
160 bits
14 bits
≈ 16s
194 bits
≈ 1047 yrs

Increased key entropy

All factors must be simultaneously correctly guessed to derive a key using MFKDF, meaning that they can't be individually brute-force attacked. MFKDF2 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
AND
OR
AND
AND
OR
AND

Enforce advanced policies

MFKDF2 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()
    )
  )
)

Self-service factor recovery

Password-derived keys can't be recovered after a password is forgotten without creating a centralized point of failure (e.g., 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

Built by the Multifactor research team, for the community

Multifactor is a public benefit company on a mission to redefine zero-trust for the modern web. Learn more about our other research projects, or reach out to explore working together.

We appreciate the support of:
Zcash Foundation Community Grants
Berkeley Center for Responsible Decentralized Intelligence
National Science Foundation
National Physical Science Consortium
Fannie and John Hertz Foundation
Evaluated by USENIX: