HOTP & TOTP Calculator
Generate and verify HMAC-based (HOTP) and Time-based (TOTP) one-time passwords. Supports SHA-1, SHA-256, SHA-512, 6–8 digit codes. All computation runs in your browser — your secret is never sent anywhere.
How HOTP & TOTP Work
HMAC-SHA1(K, C) where K is the shared secret and C is the counter (HOTP) or time-derived counter (TOTP). The HMAC output is then dynamically truncated to produce a 6–8 digit code.
HOTP (RFC 4226) — Counter-Based
HOTP uses an incrementing counter shared between the client and server. Each generation increments the counter by 1:
HOTP(K, C) = Truncate(HMAC-SHA1(K, C)) mod 10^d
// C = counter (8-byte big-endian)
// d = digit count (6, 7, or 8)
Use case: Event-based OTP tokens, OATH HOTP tokens, smart card challenge-response (some PIV cards).
TOTP (RFC 6238) — Time-Based
TOTP replaces the counter with a time-derived value:
T = floor((CurrentTime - T0) / X)
TOTP(K, T) = Truncate(HMAC-SHA1(K, T)) mod 10^d
// T0 = epoch start (usually 0)
// X = time step (typically 30 or 60 seconds)
Use case: Google Authenticator, Authy, Microsoft Authenticator, 2FA apps, FIDO2/U2F time-based challenges.
Dynamic Truncation
The HMAC output (20 bytes for SHA-1, 32 for SHA-256, 64 for SHA-512) is truncated to produce a numeric code:
1. offset = hmac[hamc_length-1] & 0x0F
2. code = ((hmac[offset] & 0x7F) << 24) |
((hmac[offset+1] & 0xFF) << 16) |
((hmac[offset+2] & 0xFF) << 8) |
(hmac[offset+3] & 0xFF)
3. otp = code % 10^d (d = digit count)
Smart Card & Security Key Applications
| Application | OTP Type | Algorithm | Details |
|---|---|---|---|
| PIV Card (NIST SP 800-73) | HOTP | SHA-1 / SHA-256 | Card internal counter, challenge-response mode |
| OATH Token (YubiKey) | HOTP + TOTP | SHA-1 / SHA-256 | YubiKey stores multiple OATH credentials |
| Google Authenticator | TOTP | SHA-1 | 30s step, 6 digits, Base32 secret |
| RFC 6238 Test Vectors | TOTP | SHA-1/256/512 | 8 digits, 30s step, test times from RFC |
| EMV CAP (Chip Authentication) | HOTP-like | SHA-1 | Banking card generates transaction codes |
RFC 6238 Test Vectors
You can verify your implementation against these known test vectors (secret = 12345678901234567890 in ASCII, 8-digit TOTP):
| Time (Unix) | T | SHA-1 | SHA-256 | SHA-512 |
|---|---|---|---|---|
| 59 | 1 | 94287082 | 46119246 | 90693936 |
| 1111111109 | 37037036 | 07081804 | 68064774 | 25091201 |
| 1234567890 | 41152263 | 89012594 | 68064774 | 25091201 |
| 2000000000 | 66666666 | 69279037 | 91819424 | 77737706 |
Code Example (Python)
import hmac, hashlib, struct, time
def hotp(secret: bytes, counter: int, digits: int = 6, algo: str = 'sha1') -> str:
msg = struct.pack('>Q', counter)
h = hmac.new(secret, msg, algo).digest()
offset = h[-1] & 0x0F
code = ((h[offset] & 0x7F) << 24 |
(h[offset+1] & 0xFF) << 16 |
(h[offset+2] & 0xFF) << 8 |
(h[offset+3] & 0xFF))
return str(code % 10**digits).zfill(digits)
def totp(secret: bytes, digits: int = 6, period: int = 30, algo: str = 'sha1') -> str:
t = int(time.time()) // period
return hotp(secret, t, digits, algo)
# Usage
secret = b'12345678901234567890'
print(f"HOTP(counter=0): {hotp(secret, 0)}") # 755224
print(f"TOTP(now): {totp(secret)}")