Eh bien, vous pouvez le chercher sur Wikipedia ... Mais puisque vous voulez une explication, je ferai de mon mieux ici:
Fonctions de hachage
Ils fournissent un mappage entre une entrée de longueur arbitraire et une sortie (généralement) de longueur fixe (ou de plus petite longueur). Il peut s'agir d'un simple crc32, à une fonction de hachage cryptographique complète telle que MD5 ou SHA1 / 2/256/512. Le fait est qu'il y a une cartographie à sens unique en cours. C'est toujours un mappage plusieurs: 1 (ce qui signifie qu'il y aura toujours des collisions) car chaque fonction produit une sortie plus petite qu'elle ne peut en entrer (si vous alimentez chaque fichier 1 Mo possible dans MD5, vous obtiendrez une tonne de collisions).
La raison pour laquelle ils sont difficiles (ou impossibles en pratique) à inverser est la façon dont ils fonctionnent en interne. La plupart des fonctions de hachage cryptographiques parcourent plusieurs fois l'ensemble d'entrée pour produire la sortie. Donc, si nous regardons chaque bloc d'entrée de longueur fixe (qui dépend de l'algorithme), la fonction de hachage appellera cela l'état actuel. Il itérera ensuite sur l'état et le changera en un nouveau et l'utilisera comme rétroaction en lui-même (MD5 le fait 64 fois pour chaque bloc de données de 512 bits). Il combine ensuite en quelque sorte les états résultants de toutes ces itérations pour former le hachage résultant.
Maintenant, si vous voulez décoder le hachage, vous devez d'abord comprendre comment diviser le hachage donné en ses états itérés (1 possibilité pour des entrées plus petites que la taille d'un bloc de données, beaucoup pour des entrées plus grandes). Ensuite, vous devez inverser l'itération pour chaque état. Maintenant, pour expliquer pourquoi il est très difficile, imaginez essayer de déduire a
et b
de la formule suivante: 10 = a + b
. Il existe 10 combinaisons positives de a
etb
cela peut fonctionner. Maintenant, passez en revue plusieurs fois:tmp = a + b; a = b; b = tmp
. Pour 64 itérations, vous auriez plus de 10 ^ 64 possibilités d'essayer. Et ce n'est qu'un simple ajout où un état est préservé d'itération en itération. Les fonctions de hachage réelles effectuent beaucoup plus d'une opération (MD5 effectue environ 15 opérations sur 4 variables d'état). Et puisque la prochaine itération dépend de l'état de la précédente et que la précédente est détruite lors de la création de l'état actuel, il est presque impossible de déterminer l'état d'entrée qui a conduit à un état de sortie donné (pour chaque itération pas moins). Combinez cela, avec le grand nombre de possibilités impliquées, et le décodage même un MD5 prendra une quantité presque infinie (mais pas infinie) de ressources. Tellement de ressources que ça '
Fonctions de cryptage
Ils fournissent un mappage 1: 1 entre une entrée et une sortie de longueur arbitraire. Et ils sont toujours réversibles. La chose importante à noter est qu'elle est réversible à l'aide d'une méthode. Et c'est toujours 1: 1 pour une clé donnée. Maintenant, il existe plusieurs entrées: des paires de clés qui peuvent générer la même sortie (en fait, il y en a généralement, selon la fonction de cryptage). De bonnes données chiffrées ne se distinguent pas du bruit aléatoire. Ceci est différent d'une bonne sortie de hachage qui est toujours d'un format cohérent.
Cas d'utilisation
Utilisez une fonction de hachage lorsque vous souhaitez comparer une valeur mais ne pouvez pas stocker la représentation simple (pour un certain nombre de raisons). Les mots de passe devraient très bien s'adapter à ce cas d'utilisation car vous ne voulez pas les stocker en texte brut pour des raisons de sécurité (et ne devriez pas). Mais que se passe-t-il si vous souhaitez vérifier un système de fichiers pour les fichiers de musique piratés? Il serait impossible de stocker 3 Mo par fichier musical. Donc, à la place, prenez le hachage du fichier et stockez-le (md5 stockerait 16 octets au lieu de 3 Mo). De cette façon, il vous suffit de hacher chaque fichier et de le comparer à la base de données stockée de hachages (cela ne fonctionne pas aussi bien dans la pratique en raison du ré-encodage, du changement des en-têtes de fichier, etc., mais c'est un exemple de cas d'utilisation).
Utilisez une fonction de hachage lorsque vous vérifiez la validité des données d'entrée. C'est pour cela qu'ils sont conçus. Si vous avez 2 entrées et que vous souhaitez vérifier si elles sont identiques, exécutez les deux via une fonction de hachage. La probabilité d'une collision est astronomiquement faible pour les petites tailles d'entrée (en supposant une bonne fonction de hachage). C'est pourquoi il est recommandé pour les mots de passe. Pour les mots de passe jusqu'à 32 caractères, md5 a 4 fois l'espace de sortie. SHA1 a 6 fois l'espace de sortie (environ). SHA512 a environ 16 fois l'espace de sortie. Vous ne vous souciez pas vraiment ce que le mot de passe était , vous vous souciez si c'est le même que celui qui a été stocké. C'est pourquoi vous devez utiliser des hachages pour les mots de passe.
Utilisez le cryptage chaque fois que vous avez besoin de récupérer les données d'entrée. Remarquez le mot besoin . Si vous stockez des numéros de carte de crédit, vous devez les récupérer à un moment donné, mais vous ne voulez pas les stocker en texte brut. Au lieu de cela, stockez la version cryptée et conservez la clé aussi sûre que possible.
Les fonctions de hachage sont également idéales pour signer des données. Par exemple, si vous utilisez HMAC, vous signez une donnée en prenant un hachage des données concaténées avec une valeur connue mais non transmise (une valeur secrète). Ainsi, vous envoyez le texte brut et le hachage HMAC. Ensuite, le récepteur hache simplement les données soumises avec la valeur connue et vérifie si elles correspondent au HMAC transmis. Si c'est la même chose, vous savez qu'elle n'a pas été falsifiée par une partie sans la valeur secrète. Ceci est couramment utilisé dans les systèmes de cookies sécurisés par les cadres HTTP, ainsi que dans la transmission de messages de données sur HTTP où vous voulez une certaine assurance d'intégrité dans les données.
Une note sur les hachages pour les mots de passe:
Une caractéristique clé des fonctions de hachage cryptographique est qu'elles doivent être très rapides à créer et très difficiles / lentes à inverser (à tel point que c'est pratiquement impossible). Cela pose un problème avec les mots de passe. Si vous stockez sha512(password)
, vous ne faites rien pour vous prémunir contre les tables arc-en-ciel ou les attaques par force brute. N'oubliez pas que la fonction de hachage a été conçue pour la vitesse. Il est donc trivial pour un attaquant de simplement exécuter un dictionnaire via la fonction de hachage et de tester chaque résultat.
L'ajout d'un sel aide les choses car il ajoute un peu de données inconnues au hachage. Ainsi, au lieu de trouver tout ce qui correspond md5(foo)
, ils doivent trouver quelque chose qui, lorsqu'il est ajouté au sel connu, produit md5(foo.salt)
(ce qui est beaucoup plus difficile à faire). Mais cela ne résout toujours pas le problème de vitesse car s'ils connaissent le sel, il suffit de parcourir le dictionnaire.
Il y a donc des moyens de gérer cela. Une méthode populaire est appelée renforcement des touches (ou étirement des touches). Fondamentalement, vous répétez plusieurs fois un hachage (des milliers généralement). Cela fait deux choses. Tout d'abord, cela ralentit considérablement l'exécution de l'algorithme de hachage. Deuxièmement, s'il est implémenté correctement (en passant l'entrée et le sel à chaque itération), cela augmente réellement l'entropie (espace disponible) pour la sortie, ce qui réduit les risques de collisions. Une implémentation triviale est:
var hash = password + salt;
for (var i = 0; i < 5000; i++) {
hash = sha512(hash + password + salt);
}
Il existe d'autres implémentations plus standard telles que PBKDF2 , BCrypt . Mais cette technique est utilisée par de nombreux systèmes liés à la sécurité (tels que PGP, WPA, Apache et OpenSSL).
En bout de ligne, ce hash(password)
n'est pas assez bon. hash(password + salt)
c'est mieux, mais toujours pas assez bon ... Utilisez un mécanisme de hachage étiré pour produire vos hachages de mot de passe ...
Une autre note sur l'étirement trivial
Ne réinjectez en aucun cas la sortie d'un hachage directement dans la fonction de hachage :
hash = sha512(password + salt);
for (i = 0; i < 1000; i++) {
hash = sha512(hash); // <-- Do NOT do this!
}
La raison en est liée aux collisions. N'oubliez pas que toutes les fonctions de hachage ont des collisions car l'espace de sortie possible (le nombre de sorties possibles) est plus petit que l'espace d'entrée. Pour voir pourquoi, regardons ce qui se passe. Pour préfacer cela, supposons qu'il y a un risque de collision de 0,001% sha1()
(il est beaucoup plus faible en réalité, mais à des fins de démonstration).
hash1 = sha1(password + salt);
Maintenant, hash1
a une probabilité de collision de 0,001%. Mais quand nous faisons le suivant hash2 = sha1(hash1);
, toutes les collisions de hash1
deviennent automatiquement des collisions dehash2
. Alors maintenant, nous avons le taux de hash1 à 0,001%, et le deuxième sha1()
appel ajoute à cela. Alors maintenant, hash2
a une probabilité de collision de 0,002%. C'est deux fois plus de chances! Chaque itération ajoutera une autre 0.001%
chance de collision au résultat. Ainsi, avec 1000 itérations, le risque de collision est passé de 0,001% à 1%. Maintenant, la dégradation est linéaire et les probabilités réelles sont beaucoup plus petites, mais l'effet est le même (une estimation du risque de collision unique avec md5
est d'environ 1 / (2 128 ) ou 1 / (3x10 38). Bien que cela semble petit, grâce à l'attaque d'anniversaire, ce n'est pas vraiment aussi petit qu'il y paraît).
Au lieu de cela, en ré-ajoutant le sel et le mot de passe à chaque fois, vous réintroduisez des données dans la fonction de hachage. Ainsi, les collisions d'un round particulier ne sont plus des collisions du round suivant. Donc:
hash = sha512(password + salt);
for (i = 0; i < 1000; i++) {
hash = sha512(hash + password + salt);
}
A les mêmes chances de collision que la sha512
fonction native . C'est ce que tu veux. Utilisez-le à la place.