Zokreb | Pour répondre à ta question "pourquoi ne pas utiliser SHA ?" :
Je suis un quiche en cryptographie, mais il parait que c'est mal de voir 2 fois le même mot de passe crypté sur une page (au cas où deux personnes utiliseraient le meme mot de passe). Du coup, j'ai aucune idée de pourquoi, mais je m'exécute, je préfère utiliser la méthode avec le sel (le salt quoi) qui donne des mdp toujours différents.
Cela dit, avec tes infos, j'ai pu me dépatouiller. Le site proposait une validation à partir du programme openSSL, mais voilà, dans php, c'est pas implémenté à coup sûr suivant les hébergeurs. Alors j'ai voulu faire pareil avec la fonction PHP maison.
Pour les futurs visiteurs que ca intéresserait :
Lorsque le mot de passe est généré par apache, il est généré sous la forme suivante : $apr1$bbsZplNF$w7GEYf5TXmK5LHGItX8Vg1
la première partie $apr1 sert à indiquer à apache quel est le codage utilisé. La deuxième partie $bbsZplNF est le "sel" non crypté qui est généré par une fonction à part. Enfin, la troisième partie correspond à notre mot de passe auquel a été concaténé le sel au cours du processus de hash (qui comprend je le rappelle 1000 md5 successifs dans le cas de l'authentification apache, mais ca on s'en fout).
autrement dit, pour comparer le mot de passe il nous faut aussi le sel et on met les deux à la moulinette.
Du coup, j'ai légèrement modifié la fonction présente sur le site http://www.phpbuilder.com/tips/item.php?id=991 pour passer à la fois le mot de passe et le sel.
La fonction est donc la suivante :
function crypt_apr1_md5($plain,$salt) {
$length = strlen($plain);
$context = $plain . '$apr1$' . $salt;
$binary = pack('H32', md5($plain . $salt . $plain));
for($i = $length; $i > 0; $i -= 16) {
$context .= substr($binary, 0, min(16, $i));
}
for($i = $length; $i > 0; $i >>= 1) {
$context .= ($i & 1) ? chr(0) : $plain{0};
}
$binary = pack('H32', md5($context));
for($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $plain : $binary;
if ($i % 3) $new .= $salt;
if ($i % 7) $new .= $plain;
$new .= ($i & 1) ? $binary : $plain;
$binary = pack('H32', md5($new));
}
$q = '';
for ($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if ($j == 16) $j = 5;
$q = $binary{$i} . $binary{$k} . $binary{$j} . $q;
}
$q = chr(0) . chr(0) . $binary{11} . $q;
$q = strtr(strrev(substr(base64_encode($q), 2)),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
return "\$apr1\$$salt\$$q";
}
function generate_salt($len) {
$randset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$randset .= './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$salt = "";
for ($i=0;$i<$len;$i++) {
$choice = rand(0,strlen($randset)-1);
$salt .= (substr($randset,$choice,1));
}
return $salt;
} |
Pour générer le mot de passe une premiere fois, on l'appelle par :
crypt_apr1_md5($motdepasse,generate_salt(8)); |
ensuite, on récupère les infos contenues dans le fichier .htpasswd par exemple comme ca :
$rowuser=substr($row,0,strlen($user.':'));
$rowsalt=substr($row , strlen($user.':$apr1$'),8);
$rowpasswd=substr($row , strlen($user.':') , 37); |
et on peut comparer le mot de passe de l'utilisateur avec :
if($rowpasswd!=crypt_apr1_md5($motdepasse,$rowsalt)) |
Voilà, j'ai bien conscience de pas avoir inventé la poudre, mais chuis content d'avoir compris ça car ça me prenait la tête depuis hier.
Merci Message édité par Zokreb le 07-08-2009 à 19:31:27
|