w3schools password online encrypt desencriptar php hash salt blowfish crypt

online - php encrypt password



¿Por qué crypt/blowfish genera el mismo hash con dos sales diferentes? (4)

Esta pregunta tiene que ver con la implementación de crypt() PHP. Para esta pregunta, los primeros 7 caracteres de la sal no se cuentan, por lo que se dice que una sal '' $2a$07$a '' tiene una longitud de 1, ya que solo tiene 1 carácter de sal y siete caracteres de metadatos .

Cuando se usan cadenas de sal de más de 22 caracteres, no se produce ningún cambio en el hash generado (es decir, truncamiento), y cuando se usan cadenas de menos de 21 caracteres, la sal se rellenará automáticamente (con '' $ '' caracteres, aparentemente); esto es bastante sencillo. Sin embargo, si se le dan 20 caracteres de sal y 21 caracteres de sal, donde los dos son idénticos, excepto el carácter final de la sal de 21 de longitud, ambas cadenas de hash serán idénticas. Una sal de 22 caracteres de longitud, que es idéntica a la sal de 21 longitudes, excepto por el carácter final, el hash volverá a ser diferente.

Ejemplo en el código:

$foo = ''bar''; $salt_xx = ''$2a$07$''; $salt_19 = $salt_xx . ''b1b2ee48991281a439d''; $salt_20 = $salt_19 . ''a''; $salt_21 = $salt_20 . ''2''; $salt_22 = $salt_21 . ''b''; var_dump( crypt($foo, $salt_19), crypt($foo, $salt_20), crypt($foo, $salt_21), crypt($foo, $salt_22) );

Producirá:

string(60) "$2a$07$b1b2ee48991281a439d$$.dEUdhUoQXVqUieLTCp0cFVolhFcbuNi" string(60) "$2a$07$b1b2ee48991281a439da$.UxGYN739wLkV5PGoR1XA4EvNVPjwylG" string(60) "$2a$07$b1b2ee48991281a439da2.UxGYN739wLkV5PGoR1XA4EvNVPjwylG" string(60) "$2a$07$b1b2ee48991281a439da2O4AH0.y/AsOuzMpI.f4sBs8E2hQjPUQq"

¿Por qué es esto?

EDITAR:

Algunos usuarios notan que hay una diferencia en la cadena general, lo cual es cierto. En salt_20 , offset (28, 4) es da$. , mientras que en salt_21 , offset (28, 4) es da2. ; sin embargo, es importante tener en cuenta que la cadena generada incluye el hash, la sal, así como las instrucciones para generar la sal (es decir, $2a$07$ ); la parte en la que ocurre la diferencia es, de hecho, todavía la sal. El hash real no se modifica como UxGYN739wLkV5PGoR1XA4EvNVPjwylG .

Por lo tanto, esto de hecho no es una diferencia en el hash producido, sino una diferencia en la sal utilizada para almacenar el hash, que es precisamente el problema en cuestión: dos sales están generando el mismo hash.

Rembmer: el resultado será en el siguiente formato:

"$2a$##$saltsaltsaltsaltsaltsaHASHhashHASHhashHASHhashHASHhash" // ^ Hash Starts Here, offset 28,32

donde ## es el log-base-2 que determina la cantidad de iteraciones para las que se ejecuta el algoritmo

Editar 2:

En los comentarios, se solicitó que publicara información adicional, ya que el usuario no podía reproducir mi salida. Ejecución del siguiente código:

var_dump( PHP_VERSION, PHP_OS, CRYPT_SALT_LENGTH, CRYPT_STD_DES, CRYPT_EXT_DES, CRYPT_MD5, CRYPT_BLOWFISH );

Produce el siguiente resultado:

string(5) "5.3.0" string(5) "WINNT" int(60) int(1) int(1) int(1) int(1)

Espero que esto ayude.


De mi investigación, parece que la sal siempre tiene 22 caracteres y el desplazamiento del hash es 29, no 28, lo que hace que tenga 31 caracteres de longitud, no 32. Ejecuté este código:

$pass = ''foobarbazqux''; $salt = ''cmfh./TCmc3m0X.MnmHGO''; $cost = 8; $crypt_salt = sprintf(''$2a$%02d$%s'', $cost, $salt); $chars = ''./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz''; for ($i = 0; $i < strlen($chars); $i++) { $hash = crypt($pass, $crypt_salt . $chars[$i]); var_dump($crypt_salt . $chars[$i], $hash, crypt($pass, $hash)); }

Los resultados fueron:

string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO." string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO/" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO0" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO1" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO2" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO3" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO4" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO5" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO6" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO7" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO8" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGO9" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOA" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOB" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOC" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOD" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOE" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOF" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOH" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOI" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOJ" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOL" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOM" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGON" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGO.t0NzWGmKpRimP4RhjFMg3F020kVKG9S" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOO" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOP" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOQ" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOR" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOS" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOT" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOU" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOV" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOW" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOX" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOY" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOZ" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOa" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOb" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOc" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOd" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOOSYI2wLIE3NElcU7itPPQnj8iW922mwy" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOe" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOf" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOg" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOh" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOi" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOj" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOk" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOl" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOm" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOn" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOo" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOp" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOq" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOr" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOs" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOt" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOeLcyQf2JnDryc7eA43zx3qi1uJKZUtPK" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOu" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOv" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOw" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOx" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOy" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(29) "$2a$08$cmfh./TCmc3m0X.MnmHGOz" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG" string(60) "$2a$08$cmfh./TCmc3m0X.MnmHGOutgqolF/BikhkbIM1yMA7HQpkbDxULoG"

Esto sugiere que la porción de sal del hash devuelto solo almacena bits significativos, por lo que puede no coincidir siempre con la sal de entrada. El beneficio es que el hash se puede usar inalterado como la sal al verificar.Por lo tanto, es mejor que solo almacene el hash completo devuelto por crypt(), y nunca la sal de entrada que usa inicialmente. En terminos practicos:

$hash_to_store = crypt($new_password, $formatted_salt);

y

$verified = $stored_hash == crypt($entered_password, $stored_hash);

Rodar tus propias sales no es un problema, y ​​conocerlas (con esto, supongo que querías decir guardarlas por separado para el hash) no es necesario si estás almacenando crypt()el resultado tal como está.


Después de algunos experimentos, he llegado a la conclusión de que esto se debe a la forma en que se trata la sal. La sal no se considera texto literal, sino más bien una cadena codificada en base64, de modo que 22 bytes de datos de sal representarían realmente una cadena de 16 bytes ( floor(22 * 24 / 32) == 16 ) de sal. El "Gotcha!" con esta implementación, sin embargo, es que, al igual que Unix cripta, utiliza un alfabeto base64 "no estándar". Para ser exactos, usa este alfabeto:

./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$

El 65 ° personaje, '' $ '', es el personaje de relleno.

Ahora, la función crypt() parece ser capaz de tomar una sal de cualquier longitud menor o igual a su máximo, y manejar silenciosamente cualquier incoherencia en la base64 descartando cualquier dato que no componga otro byte completo. La función crypt fallará por completo si le pasa caracteres en la sal que no forman parte de su alfabeto base64, lo que confirma esta teoría de su funcionamiento.

Tome una sal imaginaria '' 1234 ''. Esto es perfectamente base64 consistente, ya que representa 24 bits de datos, por lo que 3 bytes, y no contiene ningún dato que deba descartarse. Esta es una sal cuyo Len Mod 4 es cero. Añada cualquier carácter a esa sal, y se convierte en una sal de 5 caracteres, y Len Mod 4 ahora es 1. Sin embargo, este carácter adicional representa solo seis bits de datos y, por lo tanto, no puede transformarse en otro byte completo, por lo que se descarta.

Por lo tanto, para cualquier dos sales A y B, donde

Len A Mod 4 == 0 && Len B Mod 4 == 1 // these two lines mean the same thing && Len B = Len A + 1 // but are semantically important separately && A == substr B, 0, Len A

La sal real utilizada por crypt() para calcular el hash será, de hecho, idéntica. Como prueba, incluyo algunos ejemplos de código PHP que se pueden usar para mostrar esto. La sal gira constantemente de una forma no aleatoria (basada en un segmento aleatorio del hash Whirlpool del tiempo actual al microsegundo), y los datos que se van a aplicar (denominados en este momento $seed ) son simplemente el tiempo actual de Unix-Epoch .

$salt = substr(hash(''whirlpool'',microtime()),rand(0,105),22); $seed = time(); for ($i = 0, $j = strlen($salt); $i <= $j; ++$i) { printf(''%02d = %s%s%c'', $i, crypt($seed,''$2a$07$'' . substr($salt, 0, $i)), $i%4 == 0 || $i % 4 == 1 ? '' <-'' : '''', 0x0A ); }

Y esto produce un resultado similar al siguiente

00 = $2a$07$$$$$$$$$$$$$$$$$$$$$$.rBxL4x0LvuUp8rhGfnEKSOevBKB5V2. <- 01 = $2a$07$e$$$$$$$$$$$$$$$$$$$$.rBxL4x0LvuUp8rhGfnEKSOevBKB5V2. <- 02 = $2a$07$e8$$$$$$$$$$$$$$$$$$$.WEimjvvOvQ.lGh/V6HFkts7Rq5rpXZG 03 = $2a$07$e89$$$$$$$$$$$$$$$$$$.Ww5p352lsfQCWarRIWWGGbKa074K4/. 04 = $2a$07$e895$$$$$$$$$$$$$$$$$.ZGSPawtL.pOeNI74nhhnHowYrJBrLuW <- 05 = $2a$07$e8955$$$$$$$$$$$$$$$$.ZGSPawtL.pOeNI74nhhnHowYrJBrLuW <- 06 = $2a$07$e8955b$$$$$$$$$$$$$$$.2UumGVfyc4SgAZBs5P6IKlUYma7sxqa 07 = $2a$07$e8955be$$$$$$$$$$$$$$.gb6deOAckxHP/WIZOGPZ6/P3oUSQkPm 08 = $2a$07$e8955be6$$$$$$$$$$$$$.5gox0YOqQMfF6FBU9weAz5RmcIKZoki <- 09 = $2a$07$e8955be61$$$$$$$$$$$$.5gox0YOqQMfF6FBU9weAz5RmcIKZoki <- 10 = $2a$07$e8955be616$$$$$$$$$$$.hWHhdkS9Z3m7/PMKn1Ko7Qf2S7H4ttK 11 = $2a$07$e8955be6162$$$$$$$$$$.meHPOa25CYG2G8JrbC8dPQuWf9yw0Iy 12 = $2a$07$e8955be61624$$$$$$$$$.vcp/UGtAwLJWvtKTndM7w1/30NuYdYa <- 13 = $2a$07$e8955be616246$$$$$$$$.vcp/UGtAwLJWvtKTndM7w1/30NuYdYa <- 14 = $2a$07$e8955be6162468$$$$$$$.OTzcPMwrtXxx6YHKtaX0mypWvqJK5Ye 15 = $2a$07$e8955be6162468d$$$$$$.pDcOFp68WnHqU8tZJxuf2V0nqUqwc0W 16 = $2a$07$e8955be6162468de$$$$$.YDv5tkOeXkOECJmjl1R8zXVRMlU0rJi <- 17 = $2a$07$e8955be6162468deb$$$$.YDv5tkOeXkOECJmjl1R8zXVRMlU0rJi <- 18 = $2a$07$e8955be6162468deb0$$$.aNZIHogUlCn8H7W3naR50pzEsQgnakq 19 = $2a$07$e8955be6162468deb0d$$.ytfAwRL.czZr/K3hGPmbgJlheoZUyL2 20 = $2a$07$e8955be6162468deb0da$.0xhS8VgxJOn4skeI02VNI6jI6324EPe <- 21 = $2a$07$e8955be6162468deb0da3.0xhS8VgxJOn4skeI02VNI6jI6324EPe <- 22 = $2a$07$e8955be6162468deb0da3ucYVpET7X/5YddEeJxVqqUIxs3COrdym

¿La conclusión? Doble. Primero, funciona según lo previsto y, en segundo lugar, conozca su propia sal o no lance su propia sal.


Gran respuesta y explicación clara. Pero me parece que hay un error en la implementación o se necesita una explicación adicional de la intención {los comentarios al post explican por qué no hay un error}. La crypt() dice:

CRYPT_BLOWFISH - Hash de Blowfish con una sal de la siguiente manera: "$ 2a $", un parámetro de costo de dos dígitos, "$", y 22 dígitos de base 64 del alfabeto "./0-9A-Za-z". Usar caracteres fuera de este rango en la sal hará que crypt () devuelva una cadena de longitud cero. El parámetro de costo de dos dígitos es el logaritmo de base 2 del recuento de iteraciones para el algoritmo de hashing basado en Blowfish subyacente y debe estar en el rango 04-31, los valores fuera de este rango causarán que crypt () falle.

Esto es consistente con lo que se ha declarado y demostrado aquí. Lamentablemente, la documentación no describe el valor de retorno de manera muy útil:

Devuelve la cadena hash o una cadena que tiene menos de 13 caracteres y se garantiza que difiere de la sal en caso de error.

Pero como se muestra en la respuesta de , si la cadena de sal de entrada es válida, la salida consiste en la sal de entrada ajustada a una longitud fija con ''$'' caracteres, con el valor hash computable de 32 caracteres anexado. Desafortunadamente, la sal en el resultado se reduce a solo 21 dígitos base64, ¡no 22! Esto se muestra con las últimas tres líneas en esa respuesta, donde vemos un ''$'' por 20 dígitos, no ''$'' por 21, y cuando hay 22 dígitos base64 en la sal, el primer carácter del resultado hash reemplaza al 22do dígito de la sal de entrada. La función aún se puede usar, porque el valor completo que calcula está disponible para la persona que llama como substr(crypt($pw,$salt), 28, 32) , y la persona que llama ya conoce el valor de sal completo porque pasó esa cadena como una argumento. Pero es muy difícil entender por qué el valor de retorno está diseñado para que solo le pueda dar 126 bits del valor de sal de 128 bits. De hecho, es difícil entender por qué incluye la sal de entrada; pero omitir 2 bits es realmente insondable.

Aquí hay un pequeño fragmento que muestra que el 22º dígito base64 aporta solo dos bits más a la sal realmente utilizada en el cálculo (solo se producen 4 hashes distintos):

$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

La agrupación de los valores hash idénticos también muestra que es muy probable que la asignación del alfabeto realmente utilizado esté escrita aquí, en lugar del orden que se muestra en la otra respuesta.

Tal vez la interfaz fue diseñada de esta manera para algún tipo de compatibilidad, y tal vez porque ya se ha enviado de esta manera no se puede cambiar. {el primer comentario de la publicación explica por qué la interfaz es así}. Pero ciertamente la documentación debería explicar qué está pasando. En caso de que el error pueda solucionarse algún día, quizás sería más seguro obtener el valor de hash con:

substr(crypt($pw,$salt), -32)

Como nota final, aunque la explicación de por qué el valor hash se repite cuando el número de dígitos base64 especificado mod 4 == 1 tiene sentido en términos de por qué el código podría comportarse de esa manera, no explica por qué escribir el código una buena idea. El código podría y debería incluir los bits de un dígito base64 que constituye un byte parcial al calcular el hash, en lugar de simplemente descartarlos. Si el código se hubiera escrito de esa manera, parece probable que tampoco haya aparecido el problema de perder el 22º dígito de la sal en la salida. {Como explican los comentarios a la publicación, aunque se sobrescribe el 22º dígito, el dígito del hash que lo sobrescribe será solo uno de los cuatro valores posibles [.Oeu] , y estos son los únicos valores significativos para el 22º dígito . Si el 22º dígito no es uno de esos cuatro valores, será reemplazado por uno de esos cuatro que produce el mismo hash.}

A la luz de los comentarios, parece claro que no hay errores, solo documentación increíblemente taciturna :-) Como no soy un criptógrafo, no puedo decir esto con autoridad, pero me parece que es una debilidad del Algoritmo que una sal de 21 dígitos aparentemente puede producir todos los posibles valores hash, mientras que una sal de 22 dígitos limita el primer dígito del hash a solo uno de cuatro valores.


Parece que los resultados son realmente diferentes. (da $, vs da2) para el resultado de salt_20 y salt_21.