HOTP and TOTP one-time passwords, with otpauth URI

README.md

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"
  • 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 #

Licence #

ISC. See LICENSE.md.