Hash & chiffrement

Hash & chiffrement

Je commence par ces deux vastes questions pour vous donner un vernis à leur propos.

Initialement je voulais vous parler de certificats (qui viendront donc dans un deuxième temps), mais cela m’a amené à parler de chiffrement et je me suis dit qu’un article préliminaire à ce sujet était nécessaire. Et quitte à l’aborder, autant parler au passage de hash car il y a trop souvent une confusion entre ces deux notions, du fait sans doute que l’opposé des deux notions est la même : le “en clair”.

Sécurité vs intégrité

Le hash, ça se fume non ?

Commençons par le commencement : le hash et l’idée qu’il y a derrière.

Supposons que vous gériez un service d’adresses email pour lequel vos utilisateurs s’identifient par login et mot de passe (abrégé mdp pour la suite). Pour vérifier que votre utilisateur est bien qui il prétend, vous devrez donc vérifier que le couple login/mdp fourni est exact, ce qui vous oblige à avoir une référence stockée de votre côté (sans doute en base de données).

La façon naïve (en informatique, on a pour coutume d’appeler naïve l’implémentation la plus directe et simple d’une solution qui présente donc souvent des carences) d’implémenter un système de login/mdp est donc de stocker ces deux informations en clair au moment de la création de compte. On peut alors au moment d’une tentative de login vérifier que le mdp saisi correspond bien à celui dont on dispose en base de données et autoriser l’accès le cas échéant.

Cette implémentation pose de gros problèmes de sécurité, en particulier :

  • Si la connexion (le lien entre votre PC et le serveur distant) utilisée lors du login n’est pas chiffrée (voir le futur article sur les certificats), quelqu’un pourrait s’interposer entre vous et le serveur et intercepter votre mot de passe en clair (attaque dite de man in the middle)
  • Si quelqu’un vient hacker votre base de données, il dispose instantanément des mots de passe en clair de vos utilisateurs.

Sur cela vient s’ajouter un autre problème qui est le suivant : les utilisateurs lambda du web, inconscients qu’ils sont, réutilisent bien souvent leurs mots de passe sur plusieurs site web (quand ce n’est pas tout bonnement pour tous les sites web pour lesquels ils disposent d’un compte). Ainsi, si le mot de passe est intercepté ou récupéré par le biais de votre serveur mal sécurisé, vous mettez en péril d’autres comptes de ces mêmes utilisateurs (bon, admis, sur ce coup-là ils n’ont qu’à ne pas être cons et arrêter de réutiliser leur mdp partout…).

La solution à ce problème est assez simple : on utilise une fonction de hash. Une fonction de hash prend une donnée d’entrée quelconque et produit une donnée de sortie donc la structure est figée. Par exemple, pour une donnée d’entrée quelconque, un hash sha512crypt est obligatoirement constitué d’exactement 512 bits, qu’on représente communément comme 128 caractères hexadécimaux, chaque groupe de 2 représentant un octet, soit 8 bits (sisi faites le calcul, ça fonctionne).

Ainsi, une implémentation plus sécurisée de votre serveur est de hasher côté serveur le mdp fourni par l’utilisateur. A la création de compte, vous stockez le hash dans votre base de données puis vous comparez à chaque login votre couple login/hash avec celui de votre base de données. Cela ne solutionne pas notre problème de man in the middle, qui peut continuer à intercepter votre mot de passe en clair dans le flux de login, mais par contre votre base de données, elle, ne contient plus les mdps en clair.

Une fonction de hash donne toujours la même donnée en sortie pour une entrée donnée et une bonne fonction de hash se doit d’avoir des propriétés supplémentaires, notamment :

  • l’impossibilité de retrouver la donnée d’entrée à partir de la donnée de sortie (non-réversibilité de l’algorithme)
  • la capacité à fournir des sorties radicalement différentes pour des données d’entrée qui se ressemblent (dispersion de l’algorithme)
  • la répartition uniforme dans l’espace des sorties (autrement dit, on utilise bien tout le spectre des sorties possibles et on n’a pas dans les faits une plus grande probabilité de trouver des hashs proches de telle ou telle valeur)

Ces trois propriétés sont très importantes pour sécuriser nos mots de passe. Eh bien oui, puisqu’on ne peut pas retrouver la donnée d’entrée à partir de son hash, le seul moyen de retrouver le mot de passe en clair est de hasher les uns après les autres des mots de passes choisis arbitrairement en espérant retomber sur le même hash que celui qu’on a récupéré (attaque dite “par dictionnaire”).

De plus, comme l’algorithme a de la dispersion, si on vient de tester “toto”, qui donne 10e06b990d44de0091a2113fd95c92fc905166af147aa7632639c41aa7f26b162
0c47443813c605b924c05591c161ecc35944fc69c4433a49d10fc6b04a33611
et qu’on essaie de matcher le hash 10e06b990d44de0091a2113fd95c92fc905166af147aa7632639c41aa7f26b162
0c47443813c605b924c05591c161ecc35944fc69c4433a49d10fc6b04a33610
, on ne peut pas crier victoire en se disant qu’on n’est pas loin et commencer à tester totos, qui par dispersion donne tout à fait autre chose : 579f12c2ab8906d4a4f9a64056779d62bcc68aa59be4cabe53796d25efee5791c
65af22fa29b16b79022a7b6ff12a233bce378ef788ec420b3b01c63d796c576
.

Enfin, pour vous expliquer l’importance de l’utilisation uniforme des sorties possibles, il faut que je vous parle de collision. De fait, un algorithme de hash peut a priori prendre une entrée arbitraire et est donc capable de transformer une infinité de valeurs possibles. Cependant, comme précisé plus haut, il a un format bien connu en sortie, ce qui donne un espace fini de données de sorties possibles. Il n’y a pas besoin d’être docteur en mathématiques pour comprendre que si on veut faire rentrer l’infini dans 512 bits (pour reprendre notre sha512crypt), on va pouvoir avoir des sorties identiques pour des données d’entrée différentes : c’est ce qu’on appelle une collision.

La collision pose un petit souci car cela veut dire que potentiellement en faisant son attaque par dictionnaire, votre hacker malfaisant peut tomber sur un mot de passe qui n’est pas le vôtre, mais qui produit pourtant le même hash. Ainsi, ce “mot de passe alternatif” permet lui aussi de déverrouiller votre compte. C’est là que la répartition uniforme des sorties entre en jeu : si les sorties sont concentrées dans une toute petite sous-partie de l’espace des possibles, la collision a beaucoup plus de chances de se produire. Ainsi, utiliser tout l’espace équitablement réduit énormément le risque de réussite par collision de l’attaque par dictionnaire.

Et le chiffrement dans tout ça ?

L’idée derrière le chiffrement est toute autre : on veut transformer le message pour le rendre illisible (ce que fait très bien une fonction de hash), mais on veut aussi que le destinataire légitime puisse le déchiffrer après réception. On veut donc bien ici conserver l’intégrité de notre message en clair et être capable de le reconstituer à partir de la version chiffrée. Il va ainsi falloir recourir à quelque chose d’un peu différent.

Photo d’une machine Enigma

Il existe deux types de chiffrement : symétrique ou asymétrique. Dans les deux cas l’idée principale est la même : on dispose d’un algorithme qui, armé d’un message et d’une donnée maîtresse appelée clé, permet d’obtenir une version chiffrée de ce message, et d’une autre fonction qui permet à partir d’un message chiffré et d’une clé de reconstituer le message d’origine en clair.

A partir de là, deux cas de figure sont possibles :

  • il existe une clé unique qui permet à la fois de chiffrer et de déchiffrer, elle est donc gardée secrète de tous les utilisateurs concernés : c’est le cas du chiffrement symétrique
  • il existe deux clés, l’une pour chiffrer et l’autre pour déchiffrer : c’est le cas du chiffrement asymétrique.

Dans le cas du chiffrement asymétrique, la clé destinée au chiffrement est habituellement appelée clé publique car elle peut être librement diffusée, la clé de déchiffrement – appelée clé privée – est par contre gardée secrète. Il est bien sûr important d’utiliser des algorithmes qui rendent impossible dans la pratique de déduire la clé privée à partir de la clé publique.

Le chiffrement symétrique pose le problème de devoir se partager la clé secrète entre individus de confiance de façon sécurisée, soucis que ne présente pas l’asymétrique. En revanche, le chiffrement asymétrique est plus lent et plus vulnérable par essence.

Alors là, vous vous dites : “Oui c’est bien beau mais du coup en symétrique, tous les gardiens du secret peuvent chiffrer et déchiffrer alors qu’en symétrique, le monde entier peut chiffrer et seuls les gardiens du secret peuvent déchiffrer. En plus tu nous dis que c’est moins sécurisé… Quel intérêt ? “. Question légitime s’il en est !

Déjà, dans les faits, dire que la clé publique sert à chiffrer et que la clé privée sert à déchiffrer est une convention que j’ai toujours trouvée débile car l’inverse est vrai aussi : un message qu’on chiffre avec la clé privée pourra être décrypté avec la clé publique (et donc par tout le monde). Ça y’est, vous voyez l’intérêt maintenant ?

Supposons que je me créé un couple clé publique/clé privée. Je garde la clé privée pour moi et moi seul et je diffuse la clé publique au monde entier. Dès lors n’importe qui peut communiquer avec moi en étant sûr que leur message ne pourra être lu par personne d’autre : le man in the middle dont on parlait plus haut peut bien essayer de capter votre mdp en clair dans le flux, c’est le flux complet qu’on vient de crypter. Là, la boucle est bouclée, on vient de solutionner intégralement notre problème de login/mdp (allez hop, victoire : une bière et au lit).

Second bénéfice : si je crypte un message avec ma clé privée, certes le monde entier peut le décrypter mais il est alors sûr et certain que moi et moi seul peut être à l’origine du message en question.

Ainsi, l’intérêt du chiffrement asymétrique est double : il permet de sécuriser les communications entre un tiers détenteur de la clé publique et le détenteur de la clé privée (chiffrement) et il permet d’authentifier l’auteur des messages cryptés avec la clé privée (signature).

Ça vous paraît flou ? On va donner des exemples très concrets dans le prochain article sur les certificats.

Parenthèse sur l’encodage

Il existe une autre confusion entre les notions de chiffrement de d’encodage. De fait, le fonctionnement est le même – le message est transformé dans un format qui ne permet plus sa consultation directe, puis retransformé dans son format d’origine – mais la finalité est toute autre.

Dans le cas d’un encodage/décodage, le but est de transformer la donnée dans un format précis – par exemple pour assurer la compatibilité avec un autre système (encodage JSON, encodage URL, base64…) ou encore pour en réduire la taille (compression de données) – mais pas dans le but de protéger l’information contenue. Ainsi, les méthodes d’encodage et de décodage ne reposent pas sur des clés mais simplement sur des algorithmes publiquement connus.


One response to “Hash & chiffrement”

  1. […] bonne solution, qui consiste à utiliser des méthodes de cryptographie asymétriques (voir l’article introductif à ce sujet). Pour faire simple : on dispose de deux blocs de données, appelées clé publique et clé […]

Leave a Reply to Certificats : quèsaco ? – Le Blog du Tech' Cancel reply

Your email address will not be published.