Comment stocker correctement un PBKDF2 hachage de mot de passe

J'ai fait quelques recherches pour une bonne façons de hachage/crypter un mot de passe et de les stocker dans une base de données. Je savais à propos de Sel et de Hachage donc j'ai regardé autour et PBKDF2 semblait être un bon choix. J'ai donc trouvé ce site internet qui a donné un bon tutoriel sur elle ainsi que sur une adaptation de PBKDF2 pour PHP (qui est ce que j'utilise pour mon site).

Donc j'ai mis en place mon site web pour utiliser ces fonctions pour générer/créer des mots de passe, mais comme vous pouvez le voir dans le code suivant:

function create_hash($password) {
//format: algorithm:iterations:salt:hash
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" .
    base64_encode(pbkdf2(
        PBKDF2_HASH_ALGORITHM,
        $password,
        $salt,
        PBKDF2_ITERATIONS,
        PBKDF2_HASH_BYTES,
        true
    )); }

Le sel est généré dans le create_hash de la fonction, et est stocké dans le résultat de hachage qui finit par ressembler à sha256:1000:sel:hashed_password. C'est ce que j'avais à stocker dans ma base de données, et car le sel a été inclus dans le résultat de hachage, je n'ai pas besoin de l'ajouter à ma base de données. Cependant, suite à la production de quelques utilisateurs de test avec cela, je me demandais si le fait d'avoir le PBKDF2 paramètres à l'intérieur de mon hachage de mot de passe dans la base de données était en fait une bonne chose. Ils mon newbie auto voir c'est un hacker, après le craquage de ma base de données, serait de voir ces tas de sha256:1000:le sel:le mot de passe des choses, et de déterminer ce que chaque partie se, qui l'aiderait grandement dans ses tentatives, non?

Alors je l'ai modifié un peu pour avoir un externe de sel que je générer et stocker dans ma base de données, et d'inclure le sel dans le mot de passe avant de l'exécuter à travers PBKDF2. Je puis faire la même chose pour comparer le mot de passe donné avec ce que j'ai dans ma base de données pour la connexion, et ça fonctionne. Mon seul souci est que un avec 128bit le sel, le hachage de mot de passe est à peine plus de 50 caractères, cela ne semble pas juste pour moi.

Voici mon code actuel:

define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 10000);
define("PBKDF2_SALT_BYTES", 128);
define("PBKDF2_HASH_BYTES", 24);
define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);
function create_hash($password, $salt)
{
//format: salthash
return  
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
));
}
function validate_password($password, $salt, $good_hash)
{
$pbkdf2 = base64_decode($good_hash);
return slow_equals(
$pbkdf2,
pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
)
);
}
//Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0; 
}
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
//$i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
//first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
//perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}

Est ma préoccupation que le format d'enregistrement du mot de passe du sens? Ou est-ce juste montant à la même chose de toute façon, puisque, de par le fait d'avoir mon sel dans ma base de données, une fois qu'il est fissuré, le hacker peut encore brute-forcer son chemin à travers?

Merci, et désolé pour la longue question.

Voir la réponse à ces questions pour une bonne compréhension de la façon inutile de cacher un sel est here, à l'aide de bcrypt (puisque dans votre lien, pas de mise en œuvre est donnée) hereet les meilleures pratiques sur la façon d'utiliser hachage des mots de passe sécurisés here. Enfin, ne sous-estimez jamais votre adversaire!
C'est la réponse que je cherchais. Faits l'un pour l'instant mais n'hésitez pas à répondre à vous-même.

OriginalL'auteur Alex | 2012-07-31