Salted Hash in PHP
Mi è venuto in mente che un po' di tempo fa ho buttato giù qualche riga di codice in PHP per implementare un meccanismo di memorizzazione e verifica di password utente con il meccanismo del salted hash.Il codice che vedrete compare anche nel blog del mio amico Roberto Scaccia, quindi non vi preoccupate non c'è nessun copia e incolla, ma solo una condivisione di codice con il caro amico Roberto (Link).
Questa è la classe in PHP che modella la logica (potete estenderla anche ad altri algoritmi oltre lo SHA1):
/**
* Classe per la manipolazioni degli hash di sicurezza
*
*/
class Hasher
{
private $text;
private $nchar_salt;
private $nchar_cycle;
// Costruttore
// @text testo di cui calcolare l'hash
// @ncahr_salt numero di caratteri da utilizzare per il salt
// @nchar_cycle numero dei caratteri necessari per memorizzare i cicli
function __construct($text, $nchar_salt, $nchar_cycle)
{
$this->text = $text;
$this->nchar_salt = $nchar_salt;
$this->nchar_cycle = $nchar_cycle;
}
// Calcola un salt randomico come concatenazione di caratteri scelti
// randomicamente nell'intervallo di cahrcode (32,127)
static private function get_salt($nchar_salt)
{
$s = "";
for ($i=0;$i<$nchar_salt;$i++)
$s .= chr(rand(32,127));
return $s;
}
// Calcola lo Sha1 + salt per un certo numero di cicli
public function secure_sha1($cycle = 1000)
{
$salt = Hasher::get_salt($this->nchar_salt);
return $this->secure_sha1_2($cycle, $salt);
}
// Calcola lo Sha1 per un certo numero di cicli
public function secure_sha1_2($cycle = 1000, $salt)
{
$sha1 = $this->text;
for ($i=0;$i<$cycle;$i++)
$sha1 = sha1($sha1.$salt, TRUE);
$cycle = str_pad($cycle,$this->nchar_cycle,"0",STR_PAD_LEFT);
$sha1 = $sha1.$salt.$cycle;
return base64_encode($sha1);
}
// Verifica che il testo corrisponda all'hash
public function verify_sha1($b64_text)
{
// Faccio la decodifica Base64
$text = base64_decode($b64_text);
$n = strlen($text);
// Ricavo il numero di caratteri del salt
$cycle = substr($text,$n-$this->nchar_cycle, $this->nchar_cycle);
$n -= $this->nchar_cycle;
//ricavo il SALT
$salt = substr($text,$n-$this->nchar_salt, $this->nchar_salt);
// Ricalcolo l'hash e controllo se coincide
$calculated_hash = $this->secure_sha1_2($cycle, $salt);
if ($calculated_hash==$b64_text) return true;
return false;
}
}
Per generare il salted hash della propria password:
$hash = new Hasher("thisismypassword", 8,8);
$salted_hash = $hash->secure_sha1(1000);
Per verificare che la password immessa dall'utente corrisponda a quella memorizzata come salted hash nel file delle password (in questo caso un file XML):
// Autentica l'utente
static public function authenticate($us, $pd, $filename) {
// leggo l'XML dal file
$xmlDOM=Logic::read_xml($filename);
// Verifico che la password immessa corrisponda a quella hashata nel file
$hash = new Hasher($pd, 8,8);
$ret = $hash->verify_sha1($xmlDOM->hashedpassword[0]);
if ($us==$xmlDOM->username[0] && $ret==true) {
return true;
}
return false;
}
Non sono stato prodigo di spiegazione off-code, ma i commenti ci sono e sono anche abbastanza esplicativi.
Ciao
MisterX