Para el registro, esto fue solo para fines de aprendizaje, se me ha dicho que ni siquiera lo use para un sitio web personal que no espero que nadie visite, por lo que este post es, desafortunadamente, el último que veré de este código. Sin embargo, he hecho todas las cosas sobre las que leo y me parecen decentes (pero no soy un experto), así que tengo curiosidad por saber qué partes podrían ser lo suficientemente malas como para que la recomendación para todos sea nunca ¿Alguna vez usó una solución personalizada?
No nombro a nadie, pero estoy bastante seguro de que ya he hecho un trabajo mucho mejor que el host web gratuito que comienza con un número triple jaja, mi contraseña de texto simple fue robada desde allí.
Aquí está la idea básica de lo que hice:
Salt and IV
Cada sal se genera mediante una función aleatoria pero no criptográficamente segura en PHP (aunque es mejor que el valor aleatorio predeterminado). Luego se encripta con blowfish usando una clave definida en el código y una IV definida en un archivo real (que está protegido por htaccess). El valor cifrado se almacena, por lo que es muy fácil cambiar la clave de IV o sal para invalidar todas las contraseñas. Además, si la base de datos está en peligro, las sales aún no se pueden descifrar sin tener acceso al sistema de archivos.
Hash
Utiliza el estiramiento de teclas y sha512. La cantidad de estiramiento de la clave se define mediante un módulo de un valor crc32 de la contraseña y la sal, por lo que cada usuario tiene una cantidad diferente, y puede cambiar el valor para permitir tiempos de procesamiento más largos. Cada hash de repetición utiliza algunos hashes dentro de él para intentar mantenerlo bastante aleatorio.
Aquí está el código real que tengo, si no sabes PHP todavía es bastante fácil ver lo que sucede en línea por línea:
$salt_key = 'íSgüý[Îaí²zÿCV™F÷œDDa©^fU©êm‹“.Ù ®Kâ³ÃX}rÿ,¢\ˆÿ7L³¢QÆH’YeTsÙõŸ¥éÙí#W—c´VÆ';
function get_iv(){
// It stores it as a file, but there's no point showing that part so here's the actual code bit
return mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
}
function generate_salt(){
global $salt_key;
$salt = substr(uniqid(mt_rand(), true), 0, 32);
$key = hash('sha256', $salt_key, true);
$iv = get_iv();
$encrypt = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $salt, MCRYPT_MODE_CFB, $iv);
return array($salt, $encrypt);
}
function decrypt_salt($encrypted){
global $salt_key;
$key = hash('sha256', $salt_key, true);
$iv = get_iv();
return mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB, $iv);
}
function hash_password($password, $salt){
#return hash('sha512', $password.$salt, true);
$hash = $salt;
for($i=0; $i<(crc32($salt.$password) % 129197); $i++){
$hash = hash('sha512', $hash.$password.$salt.hash('sha512', $salt.$hash.$password).md5($salt.md5($password.$hash)), true);
}
return $hash;
}
La parte para verificar si la contraseña es válida, básicamente solo compara el hash nuevo con el anterior, así que lo dejé fuera. El único inconveniente basado en las cosas que he leído que debería hacer un buen algoritmo es que no utiliza mucha memoria.