pub fn hash_generated_secret(secret: &str) -> StringExpand description
Hashes a high-entropy generated secret, at a cost matched to the fact that it is one.
[ITERATIONS] exists to slow a dictionary down. A recovery code
(crate::admin::recovery) has no dictionary: it is CSPRNG output from a
32-symbol alphabet, so the cheapest attack on the stored form is a
brute-force over its own keyspace, which RECOVERY_ITERATIONS widens by
another ~13 bits on top.
The reason not to spend more is specific, and worth stating so it is not
“hardened” later by reflex: the attacker this would defend against already
has a better route. Recovery codes only matter to somebody holding the
database file, and that same file holds admin_users.totp_secret in the
clear – it must, since verifying a code means recomputing the HMAC. Paying
600 000 iterations ten times per enrolment buys nothing against a reader who
can simply take the factor itself.
The stored form is self-describing, so the two costs coexist with no
migration and no second format: verify_password reads the count back out
of the string. Do not run needs_rehash against one of these – it
compares against [ITERATIONS] and would report every recovery code as
stale forever.