⏱️ Kryptografi & RFC-protokoller ✓ Analyse af IETF-standarder

Forskellen på TOTP og HOTP forklaret: Sikkerhed, mekanik og virkemåde

Millioner af udviklere og sikkerhedsingeniører kigger dagligt på rullende 6-cifrede bekræftelseskoder, men de færreste kender det elegante matematiske maskineri bag skærmen. Fra de hændelsesdrevne tællere i RFC 4226 (HOTP) fra 2005 til de diskrete tidstrin i RFC 6238 (TOTP) fra 2011 undersøger denne vejledning den dynamiske trunkeringsalgoritme på byteniveau, sårbarheder ved desynkronisering, tolerancer for ur-drift, og hvorfor TOTP erobrede det moderne internet.

2FA
2FA-Tool sikkerhedsteam
Opdateret oktober 2026
Estimeret læsetid: 14 min (2.600+ ord)
RFC 6238 RFC 4226 Dynamisk trunkering
💡 Vigtigste kryptografiske pointer (TL;DR)
  • Den grundlæggende inputforskel: HOTP beregner hashværdier ud fra en monotont voksende tæller C, hvorimod TOTP erstatter C med et tidstrin T afledt af Unix-tid (NuværendeUnixTid / 30).
  • Direkte nedarvning: TOTP er matematisk set en specialisering af HOTP: TOTP(K, Tid) = HOTP(K, T). Begge algoritmer anvender præcis den samme funktion til dynamisk trunkering.
  • Den afgørende arkitekturforskel: HOTP er tilstandsbaseret (serveren skal låse og lagre tælleren i databasen ved hvert login). TOTP er tilstandsløs, hvilket gør det muligt for moderne cloud-mikrotjenester at validere koder på tværs af distribuerede klynger uden centraliserede databaserettigheder.
01

Historiske rødder: Fra proprietære hardwaretokens til åbne webstandarder

I de tidlige 2000'ere var totrinsgodkendelse i virksomheder domineret af proprietære hardware-nøgleringe som RSA SecurID. Disse lukkede og dyre enheder indeholdt interne kvartskrystaller synkroniseret med proprietære virksomhedsservere. Hvis en organisation ønskede at udrulle totrinsgodkendelse til tusindvis af medarbejdere, var udgifterne til hardwareindkøb og softwarelicenser astronomiske.

For at frigøre godkendelse fra leverandørlåsning blev OATH (Initiative for Open Authentication) dannet af førende brancheaktører med det formål at levere åbne, royaltyfrie IETF-standarder, som enhver softwareingeniør frit kunne gennemse, implementere og revidere:

📜 2005: RFC 4226 (HOTP)

HMAC-Based One-Time Password Algorithm. Designet til strømsvage mikrokontrollere med fysiske trykknapper. Et tryk på knappen tæller den interne tæller op og viser en 6-cifret kode på en LCD-skærm.

📜 2011: RFC 6238 (TOTP)

Time-Based One-Time Password Algorithm. Designet i takt med smartphones udbredelse. Ved at udnytte netværkssynkroniseret tid (NTP) via mobilnetværket fjernede TOTP alle problemer med uoverensstemmelse i knaptilstand.

02

HOTP (RFC 4226) & mekanikken i dynamisk trunkering

Den grundlæggende matematiske definition af HOTP er overraskende enkel:

HOTP(K, C) = Truncate(HMAC-SHA-1(K, C)) mod 10CifferAntal

Parameterforklaring:

  • K: Delt symmetrisk hemmelig nøgle (typisk en Base32-afkodet 160-bit / 20-byte binær sekvens).
  • C: 8-byte (64-bit) big-endian heltalstæller.
  • HMAC-SHA-1: Nøglebaseret hash-godkendelseskode, der danner et 20-byte (160-bit) kryptografisk digest.

🔍 Hvordan dynamisk trunkering (DT) konverterer 20 bytes til 6 cifre:

Et HMAC-SHA1-digest indeholder 160 bits (20 bytes). Udtræk af 6 ensartede decimale cifre kræver en deterministisk og kollisionsresistent udvælgelsesmekanisme, som defineret i afsnit 5.3 i RFC 4226:

// Trin 1: Beregn dynamisk offset
Offset = HS[19] & 0x0F
Tag den sidste byte (indeks 19) af det 20-byte digest. Maskering med 0x0F isolerer de laveste 4 bits, hvilket giver et heltal mellem 0 og 15 (0x0 til 0xF). Dette sikrer, at det efterfølgende 4-byte udtræk aldrig overskrider den 20-byte buffer (da 15 + 4 = 19).
// Trin 2: Udtræk 4 på hinanden følgende bytes med maskering
P = ( (HS[Offset] & 0x7F) << 24 ) | ( (HS[Offset+1] & 0xFF) << 16 ) | ( (HS[Offset+2] & 0xFF) << 8 ) | ( HS[Offset+3] & 0xFF )
Udtræk 4 bytes startende fra Offset. Masken 0x7F nulstiller den mest betydende bit (MSB) for at undgå problemer med fortegnede heltal på tværs af CPU-arkitekturer (hvilket sikrer et rent positivt 31-bit heltal).
// Trin 3: Modulo-aritmetik for de endelige cifre
OTP = P mod 106 = P mod 1000000
Modulo 1.000.000 isolerer de sidste 6 decimale cifre, udfyldt med foranstillede nuller hvis nødvendigt (f.eks. bliver 748 til "000748").
🧪 Konkret testvektor fra RFC 4226 bilag D:

Antag, at den hemmelige nøgle er ASCII "12345678901234567890" og tælleren C = 0. Det resulterende HMAC-SHA1-digest i hexadecimal form er:

cc 93 cf 18 50 8d 94 93 4c 64 b6 6d 8b fb 87 fb 23 cb 4b 71

1. Den sidste byte er 0x71. 0x71 & 0x0F = 0x01, så Offset = 1.
2. Bytes 1 til 4 er: 93 cf 18 50. Nulstilling af MSB giver 0x13cf1850, hvilket i decimaltal er 332.339.280.
3. 332339280 mod 1000000 = 339280. Den resulterende 6-cifrede OTP-kode er 339280!

03

Udviklingen til TOTP (RFC 6238): Magi ved tidstrin

HOTP krævede, at tælleren på klienten forblev synkroniseret med serveren. På softwareenheder medførte tælling af tastetryk eller knapaktiveringer uundgåelige menneskelige fejl.

RFC 6238 erstattede tælleren C med et diskret tidstrin T afledt direkte fra Unix epoch-uret:

T = ⌊ (NuværendeUnixTid - T0) / X ⌋
  • NuværendeUnixTid: Sekunder forløbet siden 1970-01-01 00:00:00 UTC.
  • T0: Epoch-referencepunkt (sat til 0 i alle moderne systemer).
  • X (Tidsvindue): Standardmæssigt anbefalet varighed på 30 sekunder.
  • Gulvfunktion ⌊ ⌋: For ethvert tidsstempel inden for et 30-sekunders vindue forbliver T konstant. For eksempel resulterer alle sekunder mellem 1728211200 og 1728211229 i præcis det samme 64-bit heltal.

Binær serialisering: Når T er beregnet, pakkes det i en 8-byte big-endian binær bytebuffer (identisk i hukommelsesstruktur med tælleren C i HOTP). Som følge heraf forenkles den samlede formel til:
TOTP(K, Tid) = HOTP(K, T) Denne matematiske elegance forklarer, hvorfor godkendelsesapps skifter koder synkront hvert 30. sekund uden behov for vedvarende tilstandssynkronisering.

RFC 6238-understøttelse af SHA-256 og SHA-512: Hvor RFC 4226 udelukkende specificerede HMAC-SHA-1, udvidede RFC 6238 understøttelsen til også at omfatte HMAC-SHA-256 og HMAC-SHA-512. I SHA-256 (32-byte digest) tages offset fra byte 31 (HS[31] & 0x0F); i SHA-512 (64-byte digest) tages offset fra byte 63 (HS[63] & 0x0F). På 99,9 % af kommercielle websteder (Google, Microsoft, GitHub, AWS) forbliver SHA-1 dog den universelle standard af hensyn til kompatibilitet med ældre mobilklienter.
04

Sammenligningsmatrix: HOTP over for TOTP

Dimension HOTP (RFC 4226) TOTP (RFC 6238)
Inputvariabel Hændelsestæller C (monotont stigende) Tidstrin T (30-sekunders Unix epoch-vindue)
Kodens levetid Ubegrænset (gyldig indtil den forbruges ved login) Strengt 30 sekunder (udløber automatisk)
Serverarkitektur Tilstandsbaseret (kræver atomiske databaseskrivninger pr. login) Tilstandsløs (uafhængig NTP-verifikation)
Sårbarhed for replay-angreb Moderat (opsnappet kode forbliver gyldig indtil brug) Minimal (begrænset til resterende sekunder i aktuelt vindue)
Primær fejlkilde Desynkronisering af tæller (utilsigtede tastetryk) Ur-drift (telefonens interne ur er ude af sync)
Understøttede hashfunktioner Udelukkende HMAC-SHA-1 HMAC-SHA-1, HMAC-SHA-256, HMAC-SHA-512
Udbredelse i branchen Ældre bank-dongler, specialiserede adgangssluser 99,9 % af moderne godkendelsesapps på nettet
05

Tekniske løsninger: Desynkronisering og tidsdrift

I distribuerede produktionsmiljøer vil klienter og servere uundgåeligt opleve tids- eller tællerafvigelser. Kryptografer designede derfor eksplicitte kompensationsvinduer for at opretholde pålidelighed:

⚙️ HOTP-kompensation: Fremadskuende verifikationsvindue (s)

Hvis en bruger klikker 5 gange på sin hardwaretoken uden at logge ind, når klienttælleren C+5, mens serveren forbliver på C.
RFC 4226 fastslår, at serveren ved godkendelse beregner et fremadskuende vindue [C+1, C+s] (typisk s=20). Hvis der findes et match, springer serveren frem og synkroniserer tælleren C med det samme.

⏱️ TOTP-kompensation: Tolerance for tidsforskydning (±1 vindue)

På grund af netværkslatens eller mindre tidsunøjagtigheder på klientenheder (f.eks. en mobil, der går 10 sekunder bagud) kan koder ankomme i tilstødende tidstrin.
Produktionsservere evaluerer derfor et array af 3 vinduer: [T-1, T, T+1], hvilket i praksis udvider acceptvinduet til 90 sekunder.

Obligatorisk anti-replay-regel: For at forhindre replay-angreb inden for dette 90-sekunders tolerancevindue skal servere cache og låse anvendte koder i hukommelsen (f.eks. Redis) i 90 sekunder og afvise eventuelle gentagne indsendelser.
🛡️ Strenge-sammenligning i konstant tid (beskyttelse mod timing-angreb):

Når serveren kontrollerer, om den indtastede kode matcher den beregnede kode, vil standard sammenligninger (som userOtp === serverOtp) afbryde ved det første forkerte tegn. En angriber, der måler mikroskopiske forskelle i netværkets svartider, kan derved gætte cifrene et ad gangen. Enterprise-systemer håndhæver sammenligning i konstant tid (f.eks. crypto.timingSafeEqual i Node.js) for at forhindre sådanne sidekanalsangreb.

06

Hvorfor TOTP vandt på det moderne internet

TOTP's ubestridte succes i forhold til HOTP skyldes primært tre arkitektoniske fordele:

☁️ Tilstandsløs cloud-skalérbarhed

I distribuerede multiregionale mikrotjenester kan enhver server med et NTP-synkroniseret ur validere TOTP-koder uden at læse eller låse en central databasepost.

📱 Synergi med smartphones

Smartphones kalibrerer løbende deres systemure via mobilmaster og GPS, hvilket eliminerer ur-drift helt uden behov for manuel vedligeholdelse af hardware.

🛡️ Kort 30-sekunders angrebsvindue

HOTP-koder forbliver gyldige på ubestemt tid indtil brug. TOTP-koder udløber efter 30 sekunder, hvilket automatisk uskadeliggør lækkede serverlogs og opsnappede datapakker.

🧮 Ren klientbaseret RFC 6238-motor

Oplev TOTP-beregninger i realtid med 2FA-Tool

Se hvordan din hemmelige Base32-streng transformeres til dynamiske 6-cifrede koder via HMAC-SHA1 dynamisk trunkering. 100 % offline i din browser.

Åbn online generator