web-dev-qa-db-fra.com

Bcrypt a-t-il une longueur de mot de passe maximale?

Je déconnais avec bcrypt aujourd'hui et j'ai remarqué quelque chose:

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsddddddddddddddddd', salt)
Output: '$2a$15$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'

hashpw('testtdsdddddddddddddddddddddddddddddddddddddddddddddddsdddddddddddddddddd', salt)
Output: '$2a$15$jQYbLa5m0PIo7eZ6MGCzr.BC17WEAHyTHiwv8oLvyYcg3guP5Zc1y'

Bcrypt a-t-il une longueur de mot de passe maximale?

91
d0ctor

Oui, bcrypt a une longueur de mot de passe maximale. Le article d'origine contient ceci:

l'argument clé est une clé de cryptage secrète, qui peut être un mot de passe choisi par l'utilisateur jusqu'à 56 octets (y compris un octet zéro de fin lorsque la clé est une chaîne ASCII).

On pourrait donc déduire une longueur maximale de mot de passe d'entrée de 55 caractères (sans compter le zéro de fin). ASCII caractères, attention: un caractère Unicode générique, lorsqu'il est codé en UTF-8, peut utiliser jusqu'à quatre octets; et le concept visuel d'un glyphe peut consister en un nombre illimité de caractères Unicode. Vous économiserez beaucoup de soucis si vous limitez vos mots de passe en simple ASCII.

Cependant, il existe une confusion considérable sur la limite réelle. Certaines personnes pensent que la limite de "56 octets" inclut un sel de 4 octets, conduisant à une limite inférieure de 51 caractères. D'autres personnes soulignent que l'algorithme, en interne, gère les choses comme 18 mots 32 bits, pour un total de 72 octets, vous pouvez donc passer à 71 caractères (ou même 72 si vous ne gérez pas les chaînes avec un zéro de fin).

Réel implémentations aura une limite qui dépend de ce que l'implémentateur a cru et appliqué dans tout ce qui précède. Toutes les implémentations décentes vous permettront au moins 50 caractères. Au-delà, le support n'est pas garanti. Si vous devez prendre en charge des mots de passe de plus de 50 caractères, vous pouvez ajouter une étape de hachage préliminaire, comme indiqué dans cette question (mais, bien sûr, cela signifie que vous ne calculez plus "le" bcrypt, mais une variante locale, donc l'interopérabilité va à l'égout).

Edit: on m'a fait remarquer que même si, du point de vue d'un cryptographe, le article est le référence ultime, ce n'est pas forcément la façon dont les designers y ont pensé. L'implémentation "d'origine" peut traiter jusqu'à 72 octets. Selon votre position sur le formalisme, vous pouvez affirmer que la mise en œuvre est correcte et que l'article est faux. Quoi qu'il en soit, l'état actuel des choses est tel que mon conseil reste valable: si vous gardez moins de 50 caractères, vous irez bien partout. (Bien sûr, il aurait été préférable que l'algorithme ne soit pas limité en longueur en premier lieu.)

76
Tom Leek

tl; lr: BCrypt est limité à 72 octets, pas 56.

Contexte

BCrypt est limité à 72 octets. L'article original mentionne également l'utilisation d'un terminateur nul. Cela signifie que vous seriez généralement limité à:

  • 71 caractères + terminateur nul 1 octet

Mais la révision BCrypt 2a spécifie l'utilisation du codage UTF-8 (alors que le livre blanc d'origine fait référence à ASCII). Lorsque vous utilisez UTF-8, un caractère ne signifie pas un octet, par exemple:

  • Noël est composé de quatre caractères, mais de cinq octets (Noe¨l)
  • ???? est un caractère, mais quatre octets (F09F92A9)
  • M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉̊̋̌̍̎̏̐̑̒̓̔̕̚ est un caractère, mais 74 octets (avec le terminateur nul inclus)

Donc, cela jette une clé pour savoir combien caractères vous êtes autorisé.

D'où vient alors 55 ou 56?

Le livre blanc d'origine mentionne une longueur de clé maximale de 56 octets:

Enfin, l'argument clé est une clé de chiffrement secrète, qui peut être un mot de passe choisi par l'utilisateur jusqu'à 56 octets (y compris un zéro octet de fin lorsque la clé est une chaîne ASCII).

Il s'agissait d'un malentendu basé sur la taille de clé maximale recommandée de Blowfish 448 bits. (448/8 = 56 octets). L'algorithme de chiffrement Blowfish, dont dérive bcrypt, a une taille de clé maximale de 448 bits. Extrait de l'article original de Bruce Schneier de 1993 Description d'une nouvelle clé à longueur variable, chiffrement par blocs 64 bits (Blowfish) :

La taille du bloc est de 64 bits et la clé peut être de n'importe quelle longueur jusqu'à 448 bits.

D'autre part, l'algorithme bcrypt peut (et fait), prendre en charge jusqu'à 72 octets pour la clé, par exemple:

  • 71 caractères 8 bits + terminateur nul

La limite de 72 octets provient de la taille Blowfish P-Box, qui est de 18 DWORD (18 * 4 octets = 72 octets). À partir du livre blanc bcrypt original:

Blowfish est un chiffrement par blocs de 64 bits, structuré comme un réseau Feistel à 16 tours [14]. Il utilise 18 sous-clés 32 bits , P1, ..., P18, qu'il dérive de la clé de chiffrement. Les sous-clés sont appelées collectivement le P-Array

L'implémentation canonique d'OpenBSD tronquera toute clé dépassant 72 octets.

Cela signifie que si votre chaîne UTF8 dépasse 72 octets, elle sera tronquée à 72 octets.

Avertissement :

  • cette troncature supprimera le terminateur nul
  • cette troncature se produira même au milieu du caractère (pour un caractère de point multi-code)

Par exemple, si vos mots de passe se terminent par "agrafeuse ????", l'encodage UTF-8 pour BCrypt sera:

    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗        
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║ 73   74
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║ 0xA9 \0
    ══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝
                                               |
                                            cutoff

Dans l'implémentation canonique d'OpenBSD, les octets sont coupés au milieu d'un caractère (même si cela vous laisse une séquence d'octets utf-8 invalide):

    ══╤══╤═══╤═══╤═══╤═══╤═══╤═════╤═════╤═════╗
... 63│64│ 65│ 66│ 67│ 68│ 69│ 70  │ 71  │ 72  ║
    s │ t│ a │ p │ l │ e │ r │ 0xF0│ 0x9F│ 0x92║
    ══╧══╧═══╧═══╧═══╧═══╧═══╧═════╧═════╧═════╝

Débarrassez-vous de la longueur maximale

Ces dernières années, il a été reconnu comme une bonne idée qu'un algorithme de hachage de mot de passe ne devrait pas avoir de limite maximale. Mais il y a un problème à permettre à un client d'utiliser un mot de passe illimité :

  • il introduit une attaque par déni de service par une personne soumettant un mot de passe de plusieurs gigaoctets.

C'est pourquoi il devient maintenant courant de pré-hachage le mot de passe d'un utilisateur avec quelque chose comme SHA2-256. La chaîne codée en base 64 résultante, par exemple:

n4bQgYhMfWWaL + qgxVrQFaO/TxsrC4Is0V1sFbDwCgg =

ne sera jamais que 44 ASCII caractères (45 avec le terminateur nul).

C'est l'approche adoptée par DropBox , et est incluse dans bcrypt.net :

BCrypt.EnhancedHashPassword("correct battery horse staple Noël ???? M̡̢̛̖̗̘̙̜̝̞̟̠̀́̂̃̄̅̆̇̉̊̋̌̍̎̏̐̑̒̓̔̕̚");

Cela signifie que votre algorithme de hachage cher ne vous causera pas un déni de service.

21
Ian Boyd

Oui, BCrypt a une limite supérieure de 72 caractères. C'est une limitation par le chiffrement Blowfish lui-même. Une façon de contourner ce problème est d'utiliser d'abord SHA-256, puis BCrypt le résultat. Dans votre cas, ce serait quelque chose comme

hashpw(sha256('pass'), salt)
17
Adi