Super réponse, et l'explication claire. Mais il me semble qu'il y a un bug dans la mise en œuvre ou une autre explication de l'intention est nécessaire {commentaires à ce poste expliquer pourquoi il n'est pas un bug}. Le courant de documentation de php états:
CRYPT_BLOWFISH - Blowfish hachage avec un sel comme suit: "$2a$", deux chiffres coût de paramètre, "$", et 22 de la base de 64 chiffres de l'alphabet "./0-9A-Za-z". En utilisant des caractères en dehors de cette plage dans le sel sera la cause de crypt() pour renvoyer une chaîne de longueur nulle. Les deux chiffres coût paramètre est le logarithme en base 2 du nombre d'itérations pour la sous-jacentes Blowfish-en fonction de hachage algorithmeter et doivent être à la portée 04-31, les valeurs en dehors de cette gamme sera la cause de crypt() à l'échec.
Ceci est cohérent avec ce qui a été dit et démontré ici. Malheureusement, la documentation n'est pas de décrire la valeur de retour très utile:
Retourne le haché de chaîne ou une chaîne plus courte de 13 caractères et il est garanti pour différer du sel en cas d'échec.
Mais comme le montre la réponse de Dereleased, si l'apport en sel est valide, la sortie se compose de l'entrée de sel rembourré pour une longueur fixe par '$' caractères, avec les 32 caractères de hachage calculée valeur ajoutée. Malheureusement, le sel, le résultat est rembourré à seulement 21 base64 chiffres, pas 22! Ceci est illustré par les trois dernières lignes de cette réponse, où l'on voit un '$' pour 20 chiffres, pas de '$' pour 21, et quand il y a 22 base64 chiffres dans le sel, le premier caractère de la valeur de hachage résultat remplace le 22 chiffres de l'entrée de sel. La fonction est encore utilisable, parce que la valeur complète, il calcule est disponible à l'appelant en tant que substr(crypt($pw,$salt), 28, 32)
, et l'appelant connaît déjà le complet le sel de la valeur parce qu'elle passait d'une chaîne comme argument. Mais il est très difficile de comprendre pourquoi la valeur de retour est conçu de sorte qu'il ne peut que vous donner 126 bits de la 128 bits de sel de valeur. En fait, il est difficile de comprendre pourquoi il comprend la saisie de sel à tous; mais en omettant 2 bits de il est vraiment insondable.
Voici un petit extrait de code montrant que le 22 base64 chiffres contribue juste à deux plus de bits pour le sel effectivement utilisés dans le calcul (il y a seulement 4 distincte de hachages de produit):
$alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$lim = strlen($alphabet);
$saltprefix = '$2a$04$123456789012345678901'; // 21 base64 digits
for ($i = 0; $i < $lim; ++$i ) {
if ($i = 16 || $i == 32 || $i == 48) echo "\n";
$salt = $saltprefix . substr($alphabet, $i, 1);
$crypt = crypt($password, $salt);
echo "salt ='$salt'\ncrypt='$crypt'\n";
}
salt ='$2a$04$123456789012345678901.'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901/'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901A'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901B'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901C'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901D'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901E'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901F'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901G'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901H'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901I'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901J'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901K'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901L'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901M'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901N'
crypt='$2a$04$123456789012345678901.YpaB4l25IJ3b3F3H8trjHXj5SC1UbUW'
salt ='$2a$04$123456789012345678901O'
crypt='$2a$04$123456789012345678901Ots44xXtSV0f6zMrHerQ2IANdsJ.2ioG'
salty='$2a$04$123456789012345678901P'
crypt='$2a$04$123456789012345678901Ots44xXtSV0f6zMrHerQ2IANdsJ.2ioG'
salty='$2a$04$123456789012345678901Q'
crypt='$2a$04$123456789012345678901Ots44xXtSV0f6zMrHerQ2IANdsJ.2ioG'
... 13 more pairs of output lines with same hash
salt ='$2a$04$123456789012345678901e'
crypt='$2a$04$123456789012345678901e.1cixwQ2qnBqwFeEcMfNfXApRK0ktqm'
... 15 more pairs of output lines with same hash
salt ='$2a$04$123456789012345678901u'
crypt='$2a$04$123456789012345678901u5yLyHIE2JetWU67zG7qvtusQ2KIZhAa'
... 15 more pairs of output lines with same hash
Le regroupement de l'identique des valeurs de hachage montre également que la cartographie de l'alphabet en fait utilisé est le plus souvent écrit ici, plutôt que dans l'ordre indiqué dans l'autre réponse.
Peut-être que l'interface a été conçu de cette façon pour une sorte de compatibilité, et peut-être parce qu'il a déjà expédié de cette façon, il ne peut pas être changé. {le premier commentaire sur le post qui explique pourquoi l'interface est de cette manière que}. Mais, certainement, la documentation doit expliquer ce qu'il se passe. Juste au cas où le bug pourrait se fixe un jour, il serait peut-être plus sûr d'obtenir la valeur de hachage avec:
substr(crypt($pw,$salt), -32)
Comme note finale, tandis que l'explication de pourquoi la valeur de hachage se répète lorsque le nombre de base64 chiffres spécifiés mod 4 == 1
a un sens en termes de pourquoi ce code peut se comporter de cette façon, ça n'explique pas pourquoi écrire le code de cette façon était une bonne idée. Le code pourraient et devraient sans doute inclure les bits à partir d'un base64 chiffres qui compose partielle d'un octet pour le calcul de la table de hachage, au lieu de simplement les jeter. Si le code a été écrit de cette façon, alors il semble probable que le problème de perdre le 22 chiffres de sel dans la sortie ne serait pas apparu, soit. {Comme les commentaires sur le post expliquer, même si la 22e chiffre est écrasé, les chiffres de la table de hachage qui remplace ce sera l'une des quatre valeurs possibles [.Oeu]
, et ce sont les seules valeurs significatives pour le 22 chiffres. Si la 22e chiffre n'est pas l'une de ces quatre valeurs, il sera remplacé par l'un de ces quatre, qui produit le même hachage.}
À la lumière des commentaires, il semble clair il n'y a pas de bug, juste incroyablement taciturne, documentation :-) Depuis que je ne suis pas un cryptographe, je ne peux pas dire cela avec n'importe quelle autorité, mais il me semble que c'est une faiblesse de l'algorithme de 21 chiffres de sel, apparemment, peut produire tous les possibles de valeurs de hachage, alors que 22 chiffres de sel limite le premier chiffre de la valeur de hachage à un seul des quatre valeurs.