Skip to main content

Module totp

Module totp 

Source
Expand description

RFC 6238 time-based one-time passwords.

§Two callers, one generator

Phase 19 added this module for sub-user login: UnENVerse checking a code its own user typed. Phase 22 added the mirror image — a TOTP seed the vault stores on behalf of a third party, the way Bitwarden and 1Password hold an authenticator entry, where UnENVerse produces the code and a website checks it.

They share every line of arithmetic and deliberately nothing else. The login path is fixed at SHA-1/6 digits/30 seconds because that is what this product mints and there is no interoperability question; the stored-seed path is parameterised (Params) because the issuer chose those numbers years ago and a generator that cannot follow is a generator that produces confidently wrong codes. Only the login path has an anti-replay mark — see verify — because only the login path is a verifier.

§Why this exists twice

Phase 5.1 shipped a TOTP implementation and Phase 7 removed it, because nothing in the product ever reached it: there was no enrollment surface, no CLI verb and no UI, so the only thing the code did was carry a schema column. It comes back here with all three, and with the anti-replay rule that the original had — see verify.

§Sub-users only, deliberately

The vault owner authenticates by deriving the SQLCipher key from the master password. There is no stored hash to check and therefore nothing for a second factor to gate: an attacker who can derive the key does not go through a login form, they open the file. Offering the owner a TOTP toggle would be a control that protects nothing while looking as though it protects everything.

§No new crates

hmac is already a dependency (entropy.rs builds HKDF on it), sha1 is added for the one algorithm RFC 6238 pins for interoperability, and sha2 was already here for the KDF — which is the whole cost of supporting the SHA-256 and SHA-512 variants a stored third-party seed may name. Base32 is forty lines and lives here rather than behind a crate, for the same reason HKDF does: the encoding is part of what a reader has to check.

Structs§

Accepted
The outcome of checking a code, carrying the step that was accepted.
LiveCode
A code and how long it has left — the shape the desktop app and the CLI both render.
Params
The three numbers a stored seed is generated under.
Stored
A parsed seed: the base32 secret plus everything the URI said about it.

Enums§

Algorithm
The HMAC a stored seed names.
Kind
What a stored seed is, which decides what “the current code” means for it.

Constants§

DIGITS
Digits in a generated code. Six is what every authenticator app assumes when the otpauth:// URI omits the parameter, and omitting it is what keeps the QR-less manual-entry path working.
MAX_DIGITS
Most digits a code may carry.
MAX_PERIOD_SECS
Longest step a stored seed may name, in seconds.
MIN_DIGITS
Fewest digits a code may carry. RFC 4226 sets six as the floor.
SECRET_BYTES
Bytes of secret material. RFC 4226 requires at least 128 bits and recommends 160 — which is also the SHA-1 block output, so nothing is truncated.
SKEW_STEPS
How many steps either side of the current one are accepted.
STEAM_ALPHABET
The alphabet Steam Guard draws its five characters from.
STEAM_DIGITS
How many characters a Steam code carries. Not configurable; Steam fixes it.
STEP_SECS
Seconds per counter step. RFC 6238’s recommended default.

Functions§

base32_decode
Decodes unpadded (or padded) RFC 4648 base32, case-insensitively.
base32_encode
Encodes bytes as unpadded RFC 4648 base32.
code_at
The code a stored seed produces at a given time.
code_for_counter
The code for one explicit counter value.
generate_secret
Generates a fresh base32 secret from the OS CSPRNG.
grouped
Splits a secret into space-separated groups of four for manual entry.
hotp
HOTP (RFC 4226) for one counter value, SHA-1 and six digits.
hotp_with
HOTP (RFC 4226) for one counter value, with the algorithm and digit count the issuer chose.
live_code
The code a stored seed produces right now, with its countdown.
live_code_with
The same, optionally carrying the code that comes next.
next_code_at
The code that replaces the current one.
normalize_b32
Normalises a base32 secret: uppercase, no spaces, dashes or padding.
now_unix
Current Unix time in seconds.
otpauth_uri
Builds the otpauth:// URI an authenticator scans or imports.
parse_otpauth
Parses an otpauth://totp/... URI.
parse_seed
Reads either a bare base32 seed or a full otpauth:// URI.
remaining_secs
Seconds until the current code is replaced.
step_at
The counter step for a Unix timestamp.
totp_at
TOTP for a base32 secret at a given time. Exposed so a caller can show the user the code their authenticator should be showing — used by nothing that authenticates, only by diagnostics.
verify
Verifies a code against a secret, refusing anything at or before last_step.