createSaltedVerificationKeyFromBytes static method
Creates a salted verification key from byte arrays.
Pass this key to server as part of user registration request.
WARNING: If safePrime
is not provided, the default safe prime provided
by dsrp is used. This should NOT be done in production. You are encouraged
to generate your own safe prime instead to reduce the chance of a
pre-computed attack on common safe primes impacting your users.
If kdf
is not provided, Argon2id is used since it is slow and
hence relatively secure. Alternatively, provide customKdf
to use a
custom KDF implementation (cannot provide both kdf
and customKdf
).
If salt
is not provided then a 32-byte random salt is generated.
Only provide userIdBytes
if you want derivation of the user private key
to include it, as is done in the RFC5054 standard. Not including the user
ID means if the ID changes, the user private key will need to be
regenerated and the user registration process repeated. When key
derivation excludes the user ID, re-registration is only needed if the
password changes.
Another option is to provide a unique, fixed userIdBytes
(e.g., a UUID,
user database index, etc.) that is different from the user-chosen ID. That
allows the user to change their login ID while their internal user ID
remains constant.
For improved security, use createSaltedVerificationKeyFromBytes to pass credentials as Uint8List instead of String.
This method is preferred over createSaltedVerificationKey for security reasons, as it avoids storing passwords as Strings in memory.
passwordBytes
and userIdBytes
should be UTF-8 encoded credentials.
Implementation
static Future<SaltedVerificationKey> createSaltedVerificationKeyFromBytes({
required Uint8List passwordBytes,
Uint8List? userIdBytes,
BigInt? generator, BigInt? safePrime,
KdfChoice? kdf,
Kdf? customKdf,
Uint8List? salt
}) async {
if (kdf != null && customKdf != null) {
throw InvalidParameterException(
'Cannot provide both kdf and customKdf. Please provide only one.'
);
}
if (safePrime == null) {
_log.warning('Using default safe prime. For production use, generate a custom safe prime using scripts/generate_safe_primes to reduce risk of pre-computed attacks.');
}
final generatorBigInt = generator ?? defaultGenerator;
final safePrimeBigInt = safePrime ?? defaultSafePrime;
final resolvedKdf = customKdf ?? getKdf(kdf ?? defaultKdfChoice);
salt ??= generateRandomBytes(defaultSaltByteLengthForSaltedVerificationKey);
final privateKey = await _derivePrivateKey(
userIdBytes: userIdBytes,
passwordBytes: passwordBytes,
salt: salt,
kdf: resolvedKdf
);
final verifierKey = _deriveVerificationKey(privateKey: privateKey,
generator: generatorBigInt, safePrime: safePrimeBigInt);
final verifierKeyBytes = verifierKey.toByteList();
return SaltedVerificationKey(
key: verifierKeyBytes,
salt: salt,
);
}