feat(crypto): recovery codes kept under the instance's key
A code holds 40 bits, which plain SHA-256 hashes in a leaked database would give up to guessing; HMAC-SHA256 under a key of the instance kept outside the database (recoveryCodeKey, at least 32 characters) gives nothing to guess against without it. Decided 20 Oct 2026. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
3bc0bae6e3
commit
7ad0f92f23
1 changed files with 91 additions and 28 deletions
|
|
@ -140,9 +140,11 @@ The second factor, in `package:halkyon_base_server/base.dart`:
|
|||
so no code is accepted twice; `TotpAccepted.step` is the step to keep before answering.
|
||||
Refusals: `malformed`, `wrong`, `reused`. `totpCode` makes a code (SHA-256 and SHA-512
|
||||
for RFC 6238's vectors).
|
||||
- `RecoveryCodes.generate()`: ten codes of eight Crockford characters (`K7QX-M2PD`, as
|
||||
email sign-in's codes), shown once, kept as SHA-256 hashes; `useRecoveryCode(typed,
|
||||
hashes)` compares every hash in constant time and gives the hashes left
|
||||
- `RecoveryCodes.generate(key)`: ten codes of eight Crockford characters (`K7QX-M2PD`, as
|
||||
email sign-in's codes), shown once, kept as HMAC-SHA256 under the instance's key
|
||||
(`recoveryCodeKey`, at least 32 characters, kept outside the database: a code's 40 bits
|
||||
in a leaked database give nothing to guess against without it); `useRecoveryCode(typed,
|
||||
hashes, key)` compares every hash in constant time and gives the hashes left
|
||||
(`RecoveryCodeAccepted.remaining`), so each code works once.
|
||||
|
||||
## Taking it into a host
|
||||
|
|
|
|||
Loading…
Reference in a new issue