web-dev-qa-db-fra.com

Comment bcrypt peut-il avoir des sels intégrés?

L'article de Coda Hale "Comment conserver un mot de passe en toute sécurité" affirme que:

bcrypt a des sels intégrés pour empêcher les attaques de la table Rainbow.

Il cite ce document , qui dit que dans la mise en oeuvre par OpenBSD de bcrypt:

OpenBSD génère le sel bcrypt 128 bits à partir d’un flux de clé arcfour (arc4random (3)), contenant des données aléatoires que le noyau collecte à partir des timings des périphériques.

Je ne comprends pas comment cela peut fonctionner. Dans ma conception d'un sel:

  • Il doit être différent pour chaque mot de passe stocké, afin qu’une table Rainbow distincte soit générée pour chaque mot de passe.
  • Il doit être stocké quelque part pour qu'il soit répétable: lorsqu'un utilisateur tente de se connecter, nous prenons sa tentative de mot de passe, répétons la même procédure salt-and-hash que celle que nous avions utilisée lorsque nous avons stocké son mot de passe, et comparons

Lorsque j'utilise Devise (un Rails gestionnaire de connexion) avec bcrypt, il n'y a pas de colonne salt dans la base de données, je suis donc confus. Si le sel est aléatoire et non stocké nulle part, comment pouvons-nous répéter de manière fiable le processus de hachage?

En bref, comment bcrypt peut-il avoir des sels intégrés ?

549
Nathan Long

C'est bcrypt:

Générer un sel aléatoire. Un facteur "coût" a été préconfiguré. Recueillir un mot de passe.

Dérivez une clé de chiffrement à partir du mot de passe en utilisant les facteurs sel et coût. Utilisez-le pour chiffrer une chaîne connue. Stockez le coût, le sel , le sel et le texte chiffré. Comme ces trois éléments ont une longueur connue, il est facile de les concaténer et de les stocker dans un seul champ, tout en pouvant les séparer ultérieurement.

Lorsque quelqu'un tente de s'authentifier, récupérez le coût stocké et le sel. Dérivez une clé du mot de passe en entrée, du coût et du sel. Crypter la même chaîne bien connue. Si le texte chiffré généré correspond au texte chiffré stocké, le mot de passe est une correspondance.

Bcrypt fonctionne de manière très similaire aux schémas plus traditionnels basés sur des algorithmes tels que PBKDF2. La principale différence réside dans l’utilisation d’une clé dérivée pour chiffrer le texte brut connu; d'autres schémas (raisonnablement) supposent que la fonction de dérivation de clé est irréversible et stockent directement la clé dérivée.


Stocké dans la base de données, un bcrypt "hash" pourrait ressembler à ceci:

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

Il s’agit en réalité de trois champs, délimités par "$":

  • 2a identifie la version de l'algorithme bcrypt utilisée.
  • 10 est le facteur de coût; 2dix des itérations de la fonction de dérivation de clé sont utilisées (ce qui ne suffit pas, d'ailleurs, je recommanderais un coût de 12 ou plus.)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa est le sel et le texte chiffré, concaténés et codés dans une Base-64 modifiée. Les 22 premiers caractères sont décodés en une valeur de 16 octets pour le sel. Les caractères restants sont du texte chiffré à comparer pour l'authentification.

Cet exemple est tiré de documentation relative à l'implémentation de Coda Hale Ruby.

710
erickson

Je pense que cette phrase aurait dû être libellée comme suit:

bcrypt a des sels intégrés dans les hachages générés pour empêcher les attaques sur la table Rainbow.

L'utilitaire bcrypt lui-même ne semble pas gérer de liste de sels. Au lieu de cela, les sels sont générés aléatoirement et ajoutés à la sortie de la fonction afin qu'ils soient rappelés ultérieurement (selon l'implémentation Java de bcrypt ). En d'autres termes, le "hachage" généré par bcrypt n'est pas mais juste le hachage . C'est plutôt le hachage et le sel concaténé.

165
Adam Paynter

Ceci est tiré de la documentation de l'interface PasswordEncoder de Spring Security,

 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

Ce qui signifie qu'il faudra faire correspondre rawPassword que l'utilisateur entrera de nouveau lors de la prochaine connexion et le faire correspondre au mot de passe codé Bcrypt qui est stocké dans la base de données lors de la connexion/enregistrement précédente.

0
Meet Shah