var MD5 = function (string) {
function RotateLeft(lValue, iShiftBits) {
return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
}
function AddUnsigned(lX,lY) {
var lX4,lY4,lX8,lY8,lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
}
function F(x,y,z) { return (x & y) | ((~x) & z); }
function G(x,y,z) { return (x & z) | (y & (~z)); }
function H(x,y,z) { return (x ^ y ^ z); }
function I(x,y,z) { return (y ^ (x | (~z))); }
function FF(a,b,c,d,x,s,ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function GG(a,b,c,d,x,s,ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function HH(a,b,c,d,x,s,ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function II(a,b,c,d,x,s,ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
function ConvertToWordArray(string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWords_temp1=lMessageLength + 8;
var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
var lWordArray=Array(lNumberOfWords-1);
var lBytePosition = 0;
var lByteCount = 0;
while ( lByteCount < lMessageLength ) {
lWordCount = (lByteCount-(lByteCount % 4))/4;
lBytePosition = (lByteCount % 4)*8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount-(lByteCount % 4))/4;
lBytePosition = (lByteCount % 4)*8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
lWordArray[lNumberOfWords-2] = lMessageLength<<3;
lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
return lWordArray;
};
function WordToHex(lValue) {
var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
for (lCount = 0;lCount<=3;lCount++) {
lByte = (lValue>>>(lCount*8)) & 255;
WordToHexValue_temp = "0" + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
}
return WordToHexValue;
};
function Utf8Encode(string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
var x=Array();
var k,AA,BB,CC,DD,a,b,c,d;
var S11=7, S12=12, S13=17, S14=22;
var S21=5, S22=9 , S23=14, S24=20;
var S31=4, S32=11, S33=16, S34=23;
var S41=6, S42=10, S43=15, S44=21;
string = Utf8Encode(string);
x = ConvertToWordArray(string);
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
for (k=0;k<x.length;k+=16) {
AA=a; BB=b; CC=c; DD=d;
a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
d=GG(d,a,b,c,x[k+10],S22,0x2441453);
c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
a=II(a,b,c,d,x[k+0], S41,0xF4292244);
d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
c=II(c,d,a,b,x[k+6], S43,0xA3014314);
b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
a=AddUnsigned(a,AA);
b=AddUnsigned(b,BB);
c=AddUnsigned(c,CC);
d=AddUnsigned(d,DD);
}
var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
return temp.toLowerCase();
}
Usage
MD5("whatever");
Like possibly snagging a Gravatar.
Would it be a good or a bad idea to replace a password in a login form on submit to the md5 string instead of the actually password?
I would figure it would create added security… Please correct me if I’m wrong..
I don’t think so. If the user has JavaScript disabled the password will still be sent in plain text and there is no way for the server to know if it was passed an md5 encrypted string or the users password.
Yes, that’s a good idea.
@Johnathan Barett:
But the server could try both possibilities ;)
(in PHP “$correct = $_GET[“pwd”] == $password || md5($_GET[“pwd”]) == $password;”)
It would be great only if it happens on server side
MD5 is ridiculously easy to decrypt now, and using SSL basically does the same thing but a lot better (and for all data sent and received between client and server).
That said, security by obscurity can often be a good idea nonetheless.
Regarding the issue of JavaScript being enabled/disabled, it would be very easy to add an additional piece of data to the request through JavaScript, in which case the server would only have to look for the presence or absence of that (absence implying JavaScript was disabled, and the string was sent without first being hashed).
I would strongly recommend against checking for both the hashed and unhashed version on the server side. A lock should only open with the right key, not attempt to look for two different keys and accepting both.
As for megatrons reply: That wouldn’t change the fact that the string is being sent unhashed from the client to the server, so it doesn’t really answer the question.
Why not just use the md5() mysql function?
Because he’s not using MySQL. I’m going to assume you mean the PHP MD5 function. The problem with this is how do you take a JavaScript input and run it through a PHP function? LIke grabbing a Gravatar, user types in email address, how do you pass that value to a PHP function without loading another page in the background to send the result back.
No I’m talking about the md5 MySQL function, which there is an equivalent function for SQL Server, or whatever database manager your using. If your encrypting passwords, I assume your storing in a database.
Passwords should not be stored using MD5, as it was never designed to be an encryption algorithm. There are however other use cases for hashing on client side, such as comparing checksums.
Hmmmm… so what you’re suggesting is: Plain Text Password to MD5 (whether implemented frontend or backend) and then encrypt the MD5 instead of the Plain Text Password. I think thats pretty smart.
I know exactly what you’re talking about, but it’s not about storing information, it’s about sending information through the browser.
hey thanks guys for sharing this invaluable script.
@Johnathan Barrett: There in fact a way for the server to know whether JavaScript was enabled or not in the client’s browser.
To do so, add a hidden field named “hasjavascript” to your form with a default value of “false” and, with JavaScript, simply set the value of this field to “true”.
Then, in the server-side code, checks for the value of the GET variable “hasjavascript”.
Hashing the password with JavaScript’s only effect is that, if someone gets the submitted values, they won’t be able to know the plain-text one and will (hopefully) not be able to login with this password on other website.
Note that he will still be able to login on your website by simply submitting the intercepted hashed password, as the browser would do.
To prevent that, you would have to use an asymmetric encryption algorithm like RSA.
Read more on this on: http://en.wikipedia.org/wiki/Public-key_cryptography
I’ve used this for websites where the client doesn’t want https (they’re crazy, I know). What I do is use challenge-authentication (Actually I stole it from Yahoo! mail :P ). It’s simple:
1) Generate a random “salt” (generate a random string) and store it in the session. Send it to the browser.
2) In the client, concatenate the salt and the password, and md5 it. send the result. Also send the salt.
3) In the server, check if the salt is the same, and if md5(salt . password) match. If not, generate a NEW salt and repeat.
If you need to encrypt the password on the server, do the same thing but instead of comparing the password, compare the encrypted password (obviously you need to replicate the database-pw-encryption process in the browser).
Still, that’s not match for an HTTPS connection.
As for detecting whether the client has javascript enabled, simply make the form unsubmittable unless the client has js enabled. Use something like action=”javascript:;” and then use onsubmit for the real submission (you’d need to make an invisible form).
great script
@all and @ROMAC
Hi, I see that the threads from above are not very actual ones, but may be somebody reads them in 2013 :-)
I think it is a very interesting topic, to concern whether sensitive user data, as passwords are, will transferred over internet plain or encrypted / hashed, or not. Also, if they are saved in database encrypted / hashed or not.
As I am very concerned on users data security I picked the following as my favorite way, setting up a website:
1. – Given that nobody disables javascript today (he would never get a contemporary web experience, as there are almost no websites running without ) I assume, that users would totally agree, to use javascript to strengthen his or his datas security.
2. – On register process, I require email address as first username and send it plain to server, and passwords as md5-hash (since a couple of months I am using sha256 for hashing).
After successful registration, email verification and first login, he can set another username (or mobile number, see following point 6.)
3. – There are different ways to check serverside, if the sent password is a hash (via enabled js) or not.
… – a) use the solution of ROMAC above, set hidden field from “false” to “true” (or whatever known values),
… – b) count length of string on server (who the f**k will use a 32 characters long password, or 64 with sha256 ?)
… – c) create login form using js/jquery when page is loaded, instead of php/html (if js is disabled, no login form will appear)
… – d) don´t include a type=submit button, but a type=button and send login form using js and onclick event, even it is created with php/html (without submit button ENTER key will not work for submitting form)
4. – Serverside, incoming password hash will be hashed again using sha256 together with a random salt. The resulting hash and the salt are stored in database.
5. – On login, the incoming password (assumed as a hash) will hashed again with stored salt, saved in a temp variable, which will be compared to the hash stored in database, if both are equal… everything fine.
6. – Again considering ROMACs post (asymetric encryption like RSA): I prefer sms key, as some online banking institutes do.
If the owner of a website agrees with it, as he has minimal knowledge of security and encryption, I book a sms-account for him (I am using german provider goyya.com, as I am German :-) ). For very sensitive user account data settings user has to trigger a sms code (mobile phone number required on registration) and he gets two codes: The salt from servers database, and a 4 digits random number, stored in session.
Now the entire sensitive data traffic (and just this) will be sent AES encrypted, and will readable in local browser decrypted via jquery AES libraries. The key is never transmitted over internet, it equals to the hashed password from database, hashed again with the random sms key.
It sounds horrible ? Hmm, may be. But it works nice. Once implemented its easy to handle and more safe than RSA or HTTPS, as asymmetric keys are not going through internet at all.
Just one challenge is, when user lost or changed his mobile number… In users profile must be assigned one ore two reliable friends (mothers, fathers) mobile number(s), that one can use to change his own mobile number in user profile settings. This friend or minimum his mobile phone must be present at the moment, when user wants to login into his private area.
In Premium tariff it costs 85 Euro for 1000 sms, which is much cheaper than a website HTTPS certificate, assuming that one doesn´t need to access his personal account settings everyday.
@Rick, the reason for not using https is that recent browsers throw up a big red warning, “THIS IS AN UNTRUSTED SITE!” if you use a selfsigned cert.
This effectively means that https can only be used on sites whose budget vustifies a Verisign cert, and on webspace where such a cert can be hosted. All others must send plaintext data. Call it counterproductive security.
Hi guys! Maybe someone know how it can be possible that I am encrypting some string using js function described above and when encrypt it using online services like http://md5decrypt.net/en/ it says that hash is invalid?
thank you, thank you, thank you
thank you very much brother
you save me!
Thank’s for this solution :)
Can someone provide the reverse logic for this? I mean decryption in JS itself.
Depending on your needs you might consider calling a rest API to generate the md5 for you or even attempt to reverse it. Checkout out https://crypto.apitools.zone/md5.html and https://crypto.apitools.zone/md5-decode.html both are really fast.