Time-based One-time Password : explication du TOTP

Les utilisateurs d’Internet sont régulièrement amenés à saisir des mots de passe pour se connecter aux réseaux sociaux, en faisant leur shopping en ligne ou pour consulter leur compte sur Internet. Les mots de passe permettent de sécuriser les données sensibles contre un accès non autorisé par des tiers. Toutefois, de nombreux utilisateurs ne se donnent pas la peine de prendre les précautions nécessaires : les mots de passe simples peuvent être craqués par les professionnels en quelques secondes seulement. D’autres personnes prennent soin de bien choisir leurs mots de passe, mais elles les conservent d’une mauvaise façon et offrent ainsi une porte d’entrée aux criminels. Les points faibles des services auxquels on se connecte en tant qu’utilisateur ne doivent pas non plus être négligés. Si les mots de passe n’y sont pas conservés de façon sécurisée, ce sont les données de milliers d’utilisateurs qui sont alors en péril.

L’authentification à double facteur ou l’authentification multifactorielle permet de réduire ce risque. Plutôt que d’utiliser uniquement un mot de passe, il est au minimum nécessaire d’indiquer un autre facteur d’authentification. Ce facteur est envoyé à l’utilisateur de cette technologie par smartphone ou via un token (jeton d’authentification). La plupart du temps, les facteurs supplémentaires ont en commun d’être générés une unique fois et d’être valables pour une durée limitée générant ainsi un Time-based One-time Password. Nous vous expliquons son fonctionnement.

À quoi sert un TOTP ?

Aussi sécurisés et minutieusement choisis qu’ils puissent être, les mots de passe habituels présentent un inconvénient de taille : la sécurité est compromise dès qu’une autre personne connaît cette suite de caractères. Une solution serait de changer régulièrement de mot de passe, mais même les utilisateurs les plus exemplaires ne le font que rarement. La solution est un TOTP : un mot de passe valable uniquement pour un bref laps de temps avant d’expirer à nouveau. L’Internet Engineering Task Force (IETF) a publié l’algorithme Time-based One-time Password en 2011 dans la RFC 6238 afin d’apporter une plus grande sécurité sur Internet.

Ces mots de passe uniques sont tout particulièrement populaires dans le cadre d’une authentification multifactorielle. Dans ce type d’authentification, les utilisateurs saisissent tout d’abord leur mot de passe personnel, qui reste identique, pour se connecter à un service en ligne ; un mot de passe à durée limitée dédié à ce processus de connexion est par ailleurs généré. L’utilisateur peut obtenir ce mot de passe via une application ou à l’aide d’un dispositif supplémentaire prévu à cet effet (token).

Le mot de passe expire s’il est utilisé ne serait-ce qu’une seule fois ou s’il n’est pas utilisé pendant une période donnée. Il est ainsi très difficile pour les cybercriminels de récupérer le second facteur. Même s’ils connaissent le mot de passe permanent, ils n’ont que peu de possibilités d’acquérir le TOTP, et pas assez de temps pour le craquer.

Comment fonctionne l’algorithme Time-based One-time Password ?

Le TOTP est basé sur une fonction de hachage, c’est-à-dire un procédé cryptographique. On utilise un mot de passe secret et un horodatage pour créer une séquence de caractères chiffrée. Le mot de passe est aussi bien connu de l’utilisateur que du serveur. L’indication temporelle est effectuée en temps Unix.

Remarque

Le temps Unix est une valeur indiquant les secondes écoulées depuis le 1er janvier 1970.

Le TOTP est en fait une amélioration du « HMAC-based One-time Password » abrégé en HOTP. Le TOTP est également basé sur la procédure HMAC, l’opération de hachage qui se déroule en arrière-plan. En associant le mot de passe secret à un compteur, l’appareil de l’utilisateur et le serveur génèrent tous deux une valeur de hachage. Les deux valeurs sont identiques, permettant ainsi l’authentification.

La fonction de hachage elle-même n’est pas fixe ; en pratique, on peut utiliser SHA-1 (c’est par exemple le cas du Google Authenticator), qui génère une valeur de hachage d’une longueur de 160 bits. Dans un souci de simplicité, cette valeur est encore raccourcie à l’aide d’une fonction de compression. À terme, on obtient par exemple un nombre à six chiffres, que les utilisateurs peuvent alors saisir en toute simplicité lors de leur connexion au service en ligne.

Note

Dans le cas d’un token, le mot de passe secret est ancré dans l’appareil. La plupart du temps, cette information n’est pas connue de l’utilisateur. Dans le cas contraire, la SecretKey doit être conservée en sécurité, si possible hors ligne en l’imprimant et en la stockant dans un endroit sécurisé. En cas de perte de ce mot de passe, il ne sera plus possible de se connecter au service.

Pour le second élément de la fonction, le HOTP utilise un compteur partagé par le serveur et l’utilisateur. Dans ce cas, le problème est que le mot de passe généré est valable jusqu’à ce qu’il soit utilisé. TOTP y ajoute une restriction : le code généré ne peut être utilisé que pendant une période limitée. Quel en est le fonctionnement ?

Trois formules sont essentielles pour l’algorithme Time-based-One-time :

TOTP = HOTP(SecretKey,CurrentTime)

Cette formule simple établit uniquement que TOTP est une procédure HOTP disposant des mêmes paramètres SecretKey et CurrentTime :

  • SecretKey : mot de passe généré au hasard et connu aussi bien du serveur que du client
  • CurrentTime : moment actuel en temps Unix

Cependant, l’indication temporelle change toutes les secondes et ce délai n’est pas suffisant pour transmettre le code à l’application. Une seconde suffirait pour que le TOTP ne soit plus valide et pour que le serveur génère une nouvelle valeur de hachage. C’est la raison pour laquelle on utilise une autre formule :

CurrentTime = floor((unixtime(now) – unixtime(T0))/T1)

Le paramètre CurrentTime est donc défini :

  • unixtime(now) : moment actuel en temps Unix
  • unixtime(T0) : le temps Unix à l’instant T0 à partir duquel le décompte est effectué, dans la plupart des cas le 01/01/1970 à minuit (= 0)
  • T1 : intervalle dans lequel le TOTP doit être valide, généralement 30 secondes
  • floor : fonction permettant d’arrondir la valeur calculée à un nombre entier
Note

En théorie, il est également possible de choisir une autre valeur que 0 pour T0. Il est simplement essentiel que le client et le serveur choisissent la même valeur.

La division et l’arrondissement ont pour effet de modifier le résultat à intervalles réguliers.

La valeur de hachage générée est ensuite raccourcie une nouvelle fois pour être plus conviviale :

Result = TOTPmod10d

Le calcul du modulo nous permet de générer une somme de contrôle :

  • mod 10 : modulo en cas de diviseur 10
  • d : le nombre de chiffres que le TOTP doit comporter

On multiplie donc la base 10 par le nombre de chiffres que le code doit comporter, on divise le TOTP par cette valeur et on retranche le reste.

Calcul du TOTP à travers un exemple

Supposons que l’on souhaite générer un TOTP disposant d’une validité de 30 secondes. Nous pouvons déjà calculer le CurrentTime et voir comment la période de validité est garantie. Nous prenons comme unixtime(now) 1548322860, le 24/01/2019 à 10 h 41. Si l’on divise cette valeur par 30, on obtient précisément 51610762. Étant donné qu’il s’agit déjà d’un nombre entier, l’arrondissement donne le même résultat. Si nous utilisons le temps actuel 15 secondes plus tard (c’est-à-dire 1548322875), nous obtenons le résultat 51610762,5 après la division. Cette valeur est également arrondie en 51610762. Le CurrentTime reste donc identique. Dans le tableau suivant, on peut voir que l’on obtient uniquement une autre valeur après 30 secondes :

unixtime(now) unixtime(now)/30 floor(unixtime(now)/30)
1548322857 51610761,9000 51610761
1548322858 51610761,9333 51610761
1548322859 51610761,9667 51610761
1548322860 51610762,0000 51610762
1548322861 51610762,0333 51610762
1548322862 51610762,0667 51610762
1548322863 51610762,1000 51610762
1548322864 51610762,1333 51610762
1548322865 51610762,1667 51610762
1548322866 51610762,2000 51610762
1548322867 51610762,2333 51610762
1548322868 51610762,2667 51610762
1548322869 51610762,3000 51610762
1548322870 51610762,3333 51610762
1548322871 51610762,3667 51610762
1548322872 51610762,4000 51610762
1548322873 51610762,4333 51610762
1548322874 51610762,4667 51610762
1548322875 51610762,5000 51610762
1548322876 51610762,5333 51610762
1548322877 51610762,5667 51610762
1548322878 51610762,6000 51610762
1548322879 51610762,6333 51610762
1548322880 51610762,6667 51610762
1548322881 51610762,7000 51610762
1548322882 51610762,7333 51610762
1548322883 51610762,7667 51610762
1548322884 51610762,8000 51610762
1548322885 51610762,8333 51610762
1548322886 51610762,8667 51610762
1548322887 51610762,9000 51610762
1548322888 51610762,9333 51610762
1548322889 51610762,9667 51610762
1548322890 51610763,0000 51610763
1548322891 51610763,0333 51610763

Nous avons donc déterminé le CurrentTime (51610762). Nous générons la SecretKey à l’aide du générateur de mot de passe : >cHSB_UQ#O5m;~b

HMAC avec SHA-1 crée une valeur de hachage (en notation hexadécimale) à partir de ce mot de passe et de l’heure : c0 62 37 94 dd 37 7a 3a f0 91 22 08 1f 21 6f 9b 17 4b 17 45. Cette valeur de 160 bits ou de 20 bytes est à présent raccourcie à 31 bits par une Dynamic Truncation. Pour ce faire, on considère tout d’abord les 4 premiers bits, c’est-à-dire le nombre 0x5, que l’on note 5 en notation hexadécimale. Cela correspond à la valeur Offset de la Dynamic Truncation et signifie que l’on extrait quatre bytes en partant du byte avec l’index 5 (compter en partant de la gauche en commençant par 0) : 0x377a3af0. Dans ce cas, la valeur commence déjà avec un bit sur 0. Si tel n’était pas le cas, on le modifierait pour obtenir un bit de départ sur 0. La valeur de 31 bits est donc également de : 0x377a3af0 ou 930757360.

Afin de réduire cette séquence de neuf chiffres à six chiffres, on effectue une opération de modulo et on ajoute si besoin des zéros à gauche : 930757360 mod (106) = 757360. Ce chiffre est donc le TOTP qui sera valide pendant 30 secondes. Associé à un autre facteur, il permet d’obtenir une procédure de connexion relativement sûre.