totp #
HOTP and TOTP one-time passwords for OCaml, with otpauth provisioning
URIs.
An authenticator application and a server share a secret key. HOTP (RFC 4226) derives a short decimal value from the HMAC of a counter under that key; TOTP (RFC 6238) takes as counter the number of 30-second steps since the epoch, so the two sides agree through their clocks. HMAC-SHA-1, HMAC-SHA-256 and HMAC-SHA-512 are supported.
The key is a Secret.t of the secret package: it
lives in a buffer the runtime does not copy and that is erased when it is
destroyed. A verifier tries a window of steps around the current one,
compares each candidate in constant time, and refuses a counter at or below
the last one it accepted, so a value is good once. Totp.Uri reads and
writes the otpauth://totp/... and otpauth://hotp/... URIs of the Key
Uri Format that authenticators scan as QR codes.
Installation #
$ opam install totp
Usage #
The RFC 6238 key at 59 seconds past the epoch:
# let key = Secret.of_bytes (Bytes.of_string "12345678901234567890");;
val key : Secret.t = <abstr>
# Totp.generate ~digits:8 ~time:59L key;;
- : string = "94287082"
# Totp.verify ~digits:8 ~time:89L key "94287082";;
- : (int64, Totp.refusal) result = Ok 1L
# Totp.verify ~digits:8 ~last:1L ~time:89L key "94287082";;
- : (int64, Totp.refusal) result = Error `Replay
A provisioning URI:
# let uri =
Totp.Uri.of_string
"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example"
|> Result.get_ok;;
val uri : Totp.Uri.t = <abstr>
# Totp.Uri.to_string uri;;
- : string =
"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=SHA1&digits=6&period=30"
Related work #
- twostep implements HOTP and TOTP over mirage-crypto before 1.0.
- otp is GPL-3.0 over cryptokit.
- pquerna/otp (Go) and totp-rs (Rust) shape the verification options and the URI.
Recovery codes are not here: they are an account's credential, not a one-time password algorithm.
References #
- RFC 4226, HOTP, sections 5 and 7.4 and appendix D
- RFC 6238, TOTP, sections 4 and 5.2 and appendix B
- Key Uri Format
Licence #
ISC. See LICENSE.md.