I prefer a little more elegant method by creating to public keys one on the server and one generated on the users browser when these two keys are combined you get the private key for use.
$pkey = $_POST["chash"]; //Private Key Generated on the users side for safety
class user {
function hash_generator($email, $password) {
$email = strip_tags($email);
$email = trim($email);
$email = strtolower($email);
$password = strip_tags($password);
$password = trim($password);
$salt = preg_replace('/'. '[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'. '|[\x00-\x7F][\x80-\xBF]+'. '|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'. '|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'. '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|'. '(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})'. '/S', '', $email);
$salt = preg_replace('/'. '\xE0[\x80-\x9F][\x80-\xBF]'. '|\xED[\xA0-\xBF][\x80-\xBF]'. '/S', '', $salt );
$salt = preg_replace('/[^a-zA-Z0-9\s]/', '', $salt);
$salt = substr($salt,0,16);
$hash = $password;
for($i=0; $i <= 19; $i++){
$hash = crypt($hash, '$5$'.$salt.'$');
$salt = substr($hash,9,16);
}
$hash = str_replace('$5$', '', $hash);
$salt = preg_replace('/'. '[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'. '|[\x00-\x7F][\x80-\xBF]+'. '|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'. '|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'. '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|'. '(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})'. '/S', '', $hash);
$salt = preg_replace('/'. '\xE0[\x80-\x9F][\x80-\xBF]'. '|\xED[\xA0-\xBF][\x80-\xBF]'. '/S', '', $salt );
$salt = preg_replace('/[^a-zA-Z0-9\s]/', '', $salt);
$salt = substr($salt,9,16);
$hash = $email;
for($i=0; $i <= 19; $i++){
$hash = crypt($hash, '$5$'.$salt.'$');
$salt = substr($hash,9,16);
}
$hash = str_replace('$5$', '', $hash);
echo "Hash: ".$hash."<br />";
}
}
<form name="userinfo" method="post" action="#">
Email: <input type="text" name="email" tabindex="1" onchange="myHash();" /><br />
Password: <input type="password" name="pw" tabindex="2" onchange="confirmPassword();myHash();" /><br />
Confirm Password: <input type="password" name="pwc" tabindex="3" onchange="confirmPassword();" /><span id="span1"></span><br />
First Name: <input type="text" name="fname" tabindex="4" /><br />
Last Name: <input type="text" name="lname" tabindex="5" /><br />
<input type="hidden" name="chash" /><input type="submit" name="submit" value="submit" tabindex="6" />
</form>
Validator.js
function confirmPassword() {
var pw = document.userinfo.pw;
var pwc = document.userinfo.pwc;
var s = document.userinfo.submit;
var txt = " ";
if ((pw.value === pwc.value) && (pw.value.length >= "8") && (pwc.value.length >= "8")) {
pw.className = "valid";
pwc.className = "valid"; //Greenish background color
s.disabled = false;
} else {
pw.className = "invalid";
pwc.className = "invalid"; //Reddish background color
s.disabled = true;
txt += "Warning Passwords do not match! ";
}
if ((pw.value.length <= "7") && (pwc.value.length <= "7")) {
txt += "Pasword must be at least 8 character\'s long!";
}
document.getElementById('span1').innerHTML = txt;
}
function myHash(){
var message = document.userinfo.email.value;
var secretkey = document.userinfo.pw.value;
var i = secretkey.length;
secretkey = secretkey.replace(/[^a-zA-Z 0-9]+/g,'');
if(i%2){
secretkey = secretkey.substr(0,i-1);
}
mac_hex = HMAC_SHA256_MAC(secretkey, message);
document.userinfo.chash.value = mac_hex;
}
jssha256.js
function string_to_array(str) {
var len = str.length;
var res = new Array(len);
for(var i = 0; i < len; i++)
res[i] = str.charCodeAt(i);
return res;
}
function array_to_hex_string(ary) {
var res = "";
for(var i = 0; i < ary.length; i++)
res += SHA256_hexchars[ary[i] >> 4] + SHA256_hexchars[ary[i] & 0x0f];
return res;
}
function SHA256_init() {
SHA256_H = new Array(0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19);
SHA256_buf = new Array();
SHA256_len = 0;
}
function SHA256_write(msg) {
if (typeof(msg) == "string")
SHA256_buf = SHA256_buf.concat(string_to_array(msg));
else
SHA256_buf = SHA256_buf.concat(msg);
for(var i = 0; i + 64 <= SHA256_buf.length; i += 64)
SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf.slice(i, i + 64));
SHA256_buf = SHA256_buf.slice(i);
SHA256_len += msg.length;
}
function SHA256_finalize() {
SHA256_buf[SHA256_buf.length] = 0x80;
if (SHA256_buf.length > 64 - 8) {
for(var i = SHA256_buf.length; i < 64; i++)
SHA256_buf[i] = 0;
SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf);
SHA256_buf.length = 0;
}
for(var i = SHA256_buf.length; i < 64 - 5; i++)
SHA256_buf[i] = 0;
SHA256_buf[59] = (SHA256_len >>> 29) & 0xff;
SHA256_buf[60] = (SHA256_len >>> 21) & 0xff;
SHA256_buf[61] = (SHA256_len >>> 13) & 0xff;
SHA256_buf[62] = (SHA256_len >>> 5) & 0xff;
SHA256_buf[63] = (SHA256_len << 3) & 0xff;
SHA256_Hash_Byte_Block(SHA256_H, SHA256_buf);
var res = new Array(32);
for(var i = 0; i < 8; i++) {
res[4 * i + 0] = SHA256_H[i] >>> 24;
res[4 * i + 1] = (SHA256_H[i] >> 16) & 0xff;
res[4 * i + 2] = (SHA256_H[i] >> 8) & 0xff;
res[4 * i + 3] = SHA256_H[i] & 0xff;
}
delete SHA256_H;
delete SHA256_buf;
delete SHA256_len;
return res;
}
function SHA256_hash(msg) {
var res;
SHA256_init();
SHA256_write(msg);
res = SHA256_finalize();
return array_to_hex_string(res);
}
function HMAC_SHA256_init(key) {
if (typeof(key) == "string")
HMAC_SHA256_key = string_to_array(key);
else
HMAC_SHA256_key = new Array().concat(key);
if (HMAC_SHA256_key.length > 64) {
SHA256_init();
SHA256_write(HMAC_SHA256_key);
HMAC_SHA256_key = SHA256_finalize();
}
for(var i = HMAC_SHA256_key.length; i < 64; i++)
HMAC_SHA256_key[i] = 0;
for(var i = 0; i < 64; i++)
HMAC_SHA256_key[i] ^= 0x36;
SHA256_init();
SHA256_write(HMAC_SHA256_key);
}
function HMAC_SHA256_write(msg) {
SHA256_write(msg);
}
function HMAC_SHA256_finalize() {
var md = SHA256_finalize();
for(var i = 0; i < 64; i++)
HMAC_SHA256_key[i] ^= 0x36 ^ 0x5c;
SHA256_init();
SHA256_write(HMAC_SHA256_key);
SHA256_write(md);
for(var i = 0; i < 64; i++)
HMAC_SHA256_key[i] = 0;
delete HMAC_SHA256_key;
return SHA256_finalize();
}
function HMAC_SHA256_MAC(key, msg) {
var res;
HMAC_SHA256_init(key);
HMAC_SHA256_write(msg);
res = HMAC_SHA256_finalize()
return array_to_hex_string(res);
}
SHA256_hexchars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f');
SHA256_K = new Array(
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
);
function SHA256_sigma0(x) {
return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
}
function SHA256_sigma1(x) {
return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
}
function SHA256_Sigma0(x) {
return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^
((x >>> 22) | (x << 10));
}
function SHA256_Sigma1(x) {
return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^
((x >>> 25) | (x << 7));
}
function SHA256_Ch(x, y, z) {
return z ^ (x & (y ^ z));
}
function SHA256_Maj(x, y, z) {
return (x & y) ^ (z & (x ^ y));
}
function SHA256_Hash_Word_Block(H, W) {
for(var i = 16; i < 64; i++)
W[i] = (SHA256_sigma1(W[i - 2]) + W[i - 7] +
SHA256_sigma0(W[i - 15]) + W[i - 16]) & 0xffffffff;
var state = new Array().concat(H);
for(var i = 0; i < 64; i++) {
var T1 = state[7] + SHA256_Sigma1(state[4]) +
SHA256_Ch(state[4], state[5], state[6]) + SHA256_K[i] + W[i];
var T2 = SHA256_Sigma0(state[0]) + SHA256_Maj(state[0], state[1], state[2]);
state.pop();
state.unshift((T1 + T2) & 0xffffffff);
state[4] = (state[4] + T1) & 0xffffffff;
}
for(var i = 0; i < 8; i++)
H[i] = (H[i] + state[i]) & 0xffffffff;
}
function SHA256_Hash_Byte_Block(H, w) {
var W = new Array(16);
for(var i = 0; i < 16; i++)
W[i] = w[4 * i + 0] << 24 | w[4 * i + 1] << 16 |
w[4 * i + 2] << 8 | w[4 * i + 3];
SHA256_Hash_Word_Block(H, W);
}