|
<?php |
|
function parseRequest() |
|
{ |
|
if (!isset($_POST['username']) || empty($_POST['username'])) |
|
return 'You did not enter a username'; |
|
if (!isset($_POST['password']) || empty($_POST['password'])) |
|
return 'You did not enter a password'; |
|
$request = array(); |
|
$request['username'] = $_POST['username']; |
|
$ePass = $_POST['password']; |
|
$ePass = base64_decode($ePass, true); |
|
if ($ePass === false) |
|
return 'Your password was not correctly encoded'; |
|
$dPass = decryptPassword($ePass); |
|
if ($dPass === false || empty($dPass)) |
|
return 'Your password could not be decrypted'; |
|
$request['password'] = $dPass; |
|
//check the login and return true or a failure message |
|
echo "Your Password is \"$dPass\", but you didn't hear it from me!\n\n"; |
|
return true; |
|
} |
|
|
|
function decryptPassword($ePass) |
|
{ |
|
$eKey = file_get_contents('priv.pem'); |
|
$pKey = openssl_pkey_get_private($eKey); |
|
if ($pKey === false) |
|
return false; |
|
$kData = openssl_pkey_get_details($pKey); |
|
if ($kData['type'] !== OPENSSL_KEYTYPE_RSA) |
|
return false; |
|
$digest = $kData['bits'] / 8; |
|
$limit = $digest; |
|
$hUse = 20; |
|
$limit -= $hUse * 2; |
|
$limit -= 2; |
|
$salt = 16; |
|
$type = ''; |
|
$sRet = ''; |
|
for ($a = 0; $a < strlen($ePass); $a+= $digest) |
|
{ |
|
$bSeg = substr($ePass, $a, $digest); |
|
$sSeg = ''; |
|
$ret = openssl_private_decrypt($bSeg, $sSeg, $pKey, OPENSSL_PKCS1_OAEP_PADDING); |
|
if ($ret === false) |
|
return false; |
|
$sSeg = substr(base64_decode($sSeg), $salt); |
|
$sRet.= $sSeg; |
|
} |
|
$sRet = urldecode($sRet); |
|
return $sRet; |
|
} |
|
|
|
if (isset($_POST['username']) && isset($_POST['password'])) |
|
{ |
|
header('Content-Type: text/plain'); |
|
$ret = parseRequest(); |
|
if ($ret === true) |
|
{ |
|
//logged in |
|
echo "Welcome to the site!"; |
|
} |
|
else |
|
{ |
|
//the login failed |
|
echo "Error: $ret - Please try again!"; |
|
} |
|
return; |
|
} |
|
?> |
|
<form id="login"> |
|
<table> |
|
<tr> |
|
<td colspan="2">Log In</td> |
|
</tr> |
|
<tr><td> </td></tr> |
|
<tr> |
|
<td><label for="txtUser">Username: </label></td> |
|
<td><input id="txtUser" type="text"></td> |
|
</tr> |
|
<tr> |
|
<td><label for="txtPass">Password: </label></td> |
|
<td><input id="txtPass" type="password"></td> |
|
</tr> |
|
<tr> |
|
<td></td><td><button name="submit" id="submit" type="submit" value="login">Secure Log In</button></td> |
|
</tr> |
|
</table> |
|
</form> |
|
|
|
<script> |
|
function checkInput(event) |
|
{ |
|
event.preventDefault(); |
|
var sUser = document.getElementById('txtUser').value; |
|
var sPass = document.getElementById('txtPass').value; |
|
if (sUser.length < 1) |
|
{ |
|
alert('You must enter a username!'); |
|
document.getElementById('txtUser').focus(); |
|
return; |
|
} |
|
if (sPass.length < 1) |
|
{ |
|
alert('You must enter your password!'); |
|
document.getElementById('txtPass').focus(); |
|
return; |
|
} |
|
console.log('1'); |
|
sendInput(); |
|
} |
|
|
|
async function sendInput() |
|
{ |
|
var sUser = document.getElementById('txtUser').value; |
|
var sPass = document.getElementById('txtPass').value; |
|
|
|
var eKey = await messagecrypto.getEncryptKey(); |
|
var ePass = await messagecrypto.encryptText(eKey, sPass); |
|
|
|
var myData = new Map(); |
|
myData.set('username', sUser); |
|
myData.set('password', ePass); |
|
//add any other form variables you wish to pass along. |
|
sendRequest(myData); |
|
} |
|
|
|
function sendRequest(data) |
|
{ |
|
var frmContinue = document.createElement('FORM'); |
|
frmContinue.method = 'POST'; |
|
frmContinue.style.display = 'none'; |
|
document.body.appendChild(frmContinue); |
|
for (const [key, value] of data.entries()) |
|
{ |
|
var iEntry = document.createElement('INPUT'); |
|
iEntry.type = 'hidden'; |
|
iEntry.name = key; |
|
iEntry.value = value; |
|
frmContinue.appendChild(iEntry); |
|
} |
|
frmContinue.submit(); |
|
} |
|
|
|
document.getElementById('login').addEventListener('submit', checkInput, false); |
|
|
|
var tools = { |
|
arrayBufferToBase64: function(buffer) |
|
{ |
|
var binary = ''; |
|
var bytes = new Uint8Array(buffer); |
|
var len = bytes.byteLength; |
|
for (var i = 0; i < len; i++) |
|
{ |
|
binary += String.fromCharCode(bytes[i]); |
|
} |
|
return window.btoa(binary); |
|
}, |
|
base64ToArrayBuffer: function(b64) |
|
{ |
|
var binary_string = window.atob(b64); |
|
var len = binary_string.length; |
|
var bytes = new Uint8Array( len ); |
|
for (var i = 0; i < len; i++) |
|
{ |
|
bytes[i] = binary_string.charCodeAt(i); |
|
} |
|
return bytes.buffer; |
|
} |
|
}; |
|
|
|
var messagecrypto = { |
|
getEncryptKey: async function() |
|
{ |
|
var bPub = '<?php echo file_get_contents('pub.b64'); ?>'; |
|
var sPub = tools.base64ToArrayBuffer(bPub); |
|
return await window.crypto.subtle.importKey('spki', sPub, {name: 'RSA-OAEP', hash: {name: 'SHA-1'}}, false, ['encrypt']); |
|
}, |
|
getDigestSize: function(key) |
|
{ |
|
return key.algorithm.modulusLength / 8; |
|
}, |
|
calcDigestSpace: function(spaceLimit, hash) |
|
{ |
|
var space = spaceLimit; |
|
var hashUse = 20; |
|
space -= hashUse * 2; |
|
space -= 2; |
|
return space; |
|
}, |
|
calcSaltSize: function(spaceLimit) |
|
{ |
|
var salt = 16; |
|
return salt; |
|
}, |
|
encryptText: async function(enc_pub, text) |
|
{ |
|
var t64 = await messagecrypto.segmentateAndEncrypt(enc_pub, encodeURIComponent(text)); |
|
if (t64 === false) |
|
return false; |
|
return t64; |
|
}, |
|
segmentateAndEncrypt: async function(enc_pub, plaintext) |
|
{ |
|
var digest = messagecrypto.getDigestSize(enc_pub); |
|
var limit = messagecrypto.calcDigestSpace(digest, enc_pub.algorithm.hash.name); |
|
if (limit === false) |
|
return false; |
|
var salt = messagecrypto.calcSaltSize(limit); |
|
var baseSaltLen = Math.ceil(salt * (4 / 3)); |
|
var baseTextLen = limit - baseSaltLen; |
|
var plainTextLen = Math.floor(baseTextLen * 0.75); |
|
plainTextLen = Math.floor(plainTextLen / 4) * 4; |
|
if (plaintext.length <= plainTextLen) |
|
return tools.arrayBufferToBase64(await messagecrypto.encryptSegment(enc_pub, plaintext, salt)); |
|
var segments = plaintext.match(new RegExp('.{1,' + plainTextLen + '}', 'g')); |
|
var totalLen = segments.length * digest; |
|
var ret = new Uint8Array(totalLen); |
|
for (var s = 0; s < segments.length; s++) |
|
{ |
|
var segRet = await messagecrypto.encryptSegment(enc_pub, segments[s], salt); |
|
ret.set(segRet, s * digest); |
|
} |
|
return tools.arrayBufferToBase64(ret); |
|
}, |
|
encryptSegment: async function(enc_pub, segment, salt) |
|
{ |
|
var bText = new TextEncoder().encode(segment); |
|
var bData = new Uint8Array(bText.length + salt); |
|
var bSalt = new Uint8Array(salt); |
|
window.crypto.getRandomValues(bSalt); |
|
if (salt > 0) |
|
bData.set(bSalt, 0); |
|
bData.set(bText, salt); |
|
var aData = tools.arrayBufferToBase64(bData); |
|
aData = aData.replace(/=+$/, ''); |
|
var tData = new TextEncoder().encode(aData); |
|
var aRet = await window.crypto.subtle.encrypt('RSA-OAEP', enc_pub, tData); |
|
return new Uint8Array(aRet); |
|
} |
|
}; |
|
</script> |