TOTP : comment fonctionne le 2FA par code
Les codes à six chiffres qui changent toutes les 30 secondes n’ont rien de magique : ils viennent d’un secret partagé et de l’heure, selon un algorithme public (RFC 6238).
Les ingrédients
Lors de l’inscription, le serveur génère un secret aléatoire et le transmet à l’application d’authentification, le plus souvent sous forme de QR code contenant une adresse otpauth:// avec le secret encodé en Base32. Ensuite, les deux côtés calculent le même code à partir de ce secret et de l’heure, sans rien échanger.
L’algorithme
- On calcule un compteur : le timestamp Unix divisé par 30 (le time step), arrondi à l’entier inférieur.
- On applique HMAC-SHA1 au compteur, écrit sur 8 octets, avec le secret comme clé.
- Dynamic truncation : les quatre derniers bits du résultat donnent un offset, on lit 4 octets à partir de là et on masque le bit de poids fort.
- On garde les six derniers chiffres (modulo 106), complétés de zéros à gauche.
import hmac, hashlib, struct, time
def totp(secret: bytes, period=30, digits=6, t=None):
counter = int((time.time() if t is None else t) // period)
h = hmac.new(secret, struct.pack(">Q", counter), hashlib.sha1).digest()
offset = h[-1] & 0x0F
number = struct.unpack(">I", h[offset:offset + 4])[0] & 0x7FFFFFFF
return str(number % 10 ** digits).zfill(digits)
Vérification avec les vecteurs de test de la RFC 6238 (secret ASCII 12345678901234567890, SHA-1, 8 chiffres) :
secret = b"12345678901234567890"
print(totp(secret, digits=8, t=59)) # 94287082
print(totp(secret, digits=8, t=1111111109)) # 07081804
Bien vérifier côté serveur
- Accepter le time step précédent et le suivant pour tolérer un léger décalage d’horloge.
- Refuser un code déjà utilisé, en mémorisant le dernier time step accepté.
- Limiter les tentatives : six chiffres, cela ne fait qu’un million de possibilités.
- Comparer en constant-time (
hmac.compare_digest) et stocker le secret chiffré, par exemple avec AES-GCM. - Fournir des codes de secours (backup codes), stockés hashés comme des mots de passe.
Les limites
Un code TOTP peut être volé par phishing en temps réel : la victime le saisit sur un faux site qui le rejoue aussitôt. Les clés d’accès (WebAuthn, passkeys) résistent à cette attaque parce qu’elles sont liées au domaine du vrai site.
Voir aussi : la plateforme de documents, qui utilise le TOTP