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