DES decryption in JavaScript not showing the original message - javascript

function des (key, message, encrypt, mode, iv, padding) {
//declaring this locally speeds things up a bit
var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
//create the 16 or 48 subkeys we will need
var keys = des_createKeys (key);
var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
var cbcleft, cbcleft2, cbcright, cbcright2
var endloop, loopinc;
var len = message.length;
var chunk = 0;
//set up the loops for single and triple des
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}
//pad the message depending on the padding parameter
if (padding == 2) message += " "; //pad the message with spaces
else if (padding == 1) {temp = 8-(len%8); message += String.fromCharCode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //PKCS7 padding
else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
//store the result here
result = "";
tempresult = "";
if (mode == 1) { //CBC mode
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
m=0;
}
//loop through each 64 bit chunk of the message
while (m < len) {
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}
//first each 64 but chunk of the message must be permuted according to IP
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
left = ((left << 1) | (left >>> 31));
right = ((right << 1) | (right >>> 31));
//do this either 1 or 3 times for each chunk of the message
for (j=0; j<iterations; j+=3) {
endloop = looping[j+1];
loopinc = looping[j+2];
//now go through and perform the encryption or decryption
for (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency
right1 = right ^ keys[i];
right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
//the result is attained by passing these bytes through the S selection functions
temp = left;
left = right;
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
| spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f]
| spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
| spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
}
temp = left; left = right; right = temp; //unreverse left and right
} //for either 1 or 3 iterations
//move then each one bit to the right
left = ((left >>> 1) | (left << 31));
right = ((right >>> 1) | (right << 31));
//now perform IP-1, which is IP in the opposite direction
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));
chunk += 8;
if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
} //for every 8 characters, or 64 bits in the message
//return the result as an array
return result + tempresult;
} //end of des
//des_createKeys
//this takes as input a 64 bit key (even though only 56 bits are used)
//as an array of 2 integers, and returns 16 48 bit keys
function des_createKeys (key) {
//declaring this locally speeds things up a bit
pc2bytes0 = new Array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
pc2bytes1 = new Array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
pc2bytes2 = new Array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
pc2bytes3 = new Array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
pc2bytes4 = new Array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
pc2bytes5 = new Array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
pc2bytes6 = new Array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
pc2bytes7 = new Array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
pc2bytes8 = new Array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
pc2bytes9 = new Array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
pc2bytes10 = new Array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
pc2bytes11 = new Array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
pc2bytes12 = new Array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
pc2bytes13 = new Array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);
//how many iterations (1 for des, 3 for triple des)
var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
//stores the return keys
var keys = new Array (32 * iterations);
//now define the left shifts which need to be done
var shifts = new Array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
//other variables
var lefttemp, righttemp, m=0, n=0, temp;
for (var j=0; j<iterations; j++) { //either 1 or 3 iterations
left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
temp = ((left >>> 2) ^ right) & 0x33333333; right ^= temp; left ^= (temp << 2);
temp = ((right >>> -16) ^ left) & 0x0000ffff; left ^= temp; right ^= (temp << -16);
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
//the right side needs to be shifted and to get the last four bits of the left side
temp = (left << 8) | ((right >>> 20) & 0x000000f0);
//left needs to be put upside down
left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
right = temp;
//now go through and perform these shifts on the left and right keys
for (var i=0; i < shifts.length; i++) {
//shift the keys either one or two bits to the left
if (shifts[i]) {left = (left << 2) | (left >>> 26); right = (right << 2) | (right >>> 26);}
else {left = (left << 1) | (left >>> 27); right = (right << 1) | (right >>> 27);}
left &= -0xf; right &= -0xf;
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
//rather than 48 consecutive bits and the order of lines will be according to
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf]
| pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf]
| pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf]
| pc2bytes6[(left >>> 4) & 0xf];
righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf]
| pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf]
| pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf]
| pc2bytes13[(right >>> 4) & 0xf];
temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
keys[n++] = lefttemp ^ temp; keys[n++] = righttemp ^ (temp << 16);
}
} //for each iterations
//return the keys we've created
return keys;
} //end of des_createKeys
////////////////////////////// TEST //////////////////////////////
function stringToHex (s) {
var r = "0x";
var hexes = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
for (var i=0; i<s.length; i++) {r += hexes [s.charCodeAt(i) >> 4] + hexes [s.charCodeAt(i) & 0xf];}
return r;
}
function hexToString (h) {
var r = "";
for (var i= (h.substr(0, 2)=="0x")?2:0; i<h.length; i+=2) {r += String.fromCharCode (parseInt (h.substr (i, 2), 16));}
return r;
}
var key = "12345678";
var message = "This is a test message";
var ciphertext = des (key, message, 1, 1,"23456789");
//console.log("Encrypted Value : " + ciphertext);
console.log ("Cipher Text is : " + stringToHex (ciphertext));
var deciphertext = des(key, stringToHex(ciphertext), 0, 1,"23456789");
console.log("Decipher Text is (Message) is :" + hexToString(deciphertext));
I am obtaining the correct encrypted value but for some reason during decryption i'm not obtaining the actual message which is "This is a test message". Instead,I'm obtaining a unicode value ±.
I am using DES with CBC mode of operation. Input vector is 23456789
The source code is from http://www.tero.co.uk/des/code.php.
I ran this script in Developer tools of Google Chrome.

Related

How to calculate a darker hex color

Using this solution I am trying to calculate the darker range of a color but the output is doesn't look like correct Hex value (missing one value).
> #84079
What am I doing wrong?
function LightenDarkenColor(col, amt) {
var usePound = false;
if (col[0] == "#") {
col = col.slice(1);
usePound = true;
}
var num = parseInt(col,16);
var r = (num >> 16) + amt;
if (r > 255) r = 255;
else if (r < 0) r = 0;
var b = ((num >> 8) & 0x00FF) + amt;
if (b > 255) b = 255;
else if (b < 0) b = 0;
var g = (num & 0x0000FF) + amt;
if (g > 255) g = 255;
else if (g < 0) g = 0;
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}
var firstColor = LightenDarkenColor("#3068A1", -20);
var NewColor = LightenDarkenColor(firstColor, -20);
console.log(NewColor);
Change this:
(usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
to this
(usePound?"#":"") + ('00000'+(b | (g << 8) | (r << 16)).toString(16)).slice(-6);
This will make sure that there are 6 digits and it fixes the green and blue location which were off in the original article.
(r << 16) moves the red to bits 32 to 47
(g << 8) moves the green to bits 16 to 31
and b leaves the blue in bits 0-15.
UPDATE
As was pointed out the b and g variables are reading the wrong values as well. So you want to do the following as well:
var g = ((num >> 8) & 0x00FF) + amt;
var b = (num & 0x0000FF) + amt;
Swap where the b and g get their values.
If you don't want to swap those then change my original line to this:
(usePound?"#":"") + ('00000'+(g | (b << 8) | (r << 16)).toString(16)).slice(-6);

Using ntlm authentication in Nativescript ios platform

I am building an app with authenticates the user against a sharepoint site which uses NTLM authentication. I found the ntlm.js which has been patched for nativescript here https://github.com/hdeshev/nativescript-ntlm-demo.
I have managed to get it working for android platform, but it fails on ios showing an 401 error. As far as I can tell, the difference happens in this segment:
Ntlm.setCredentials = function(domain, username, password) {
var magic = 'KGS!##$%'; // Create LM password hash.
var lmPassword = password.toUpperCase().substr(0, 14);
while (lmPassword.length < 14) lmPassword += '\0';
var key1 = Ntlm.createKey(lmPassword);
var key2 = Ntlm.createKey(lmPassword.substr(7));
var lmHashedPassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0);
var ntPassword = ''; // Create NT password hash.
for (var i = 0; i < password.length; i++)
ntPassword += password.charAt(i) + '\0';
var ntHashedPassword = str_md4(ntPassword);
Ntlm.domain = domain;
Ntlm.username = username;
Ntlm.lmHashedPassword = lmHashedPassword;
Ntlm.ntHashedPassword = ntHashedPassword;
};
When I log the result of 'lmhashedPassword' after going through the des() function, it simply returns 'A'. Whereas on android, it returns a longer string. Something in the des function must be cutting it off, but I cannot see what.
Here is the des function:
function des (key, message, encrypt, mode, iv, padding) {
//declaring this locally speeds things up a bit
var spfunction1 = new Array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
var spfunction2 = new Array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
var spfunction3 = new Array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
var spfunction4 = new Array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
var spfunction5 = new Array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
var spfunction6 = new Array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
var spfunction7 = new Array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
var spfunction8 = new Array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
//create the 16 or 48 subkeys we will need
var keys = des_createKeys (key);
var m=0, i, j, temp, temp2, right1, right2, left, right, looping;
var cbcleft, cbcleft2, cbcright, cbcright2
var endloop, loopinc;
var len = message.length;
var chunk = 0;
//set up the loops for single and triple des
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
if (iterations == 3) {looping = encrypt ? new Array (0, 32, 2) : new Array (30, -2, -2);}
else {looping = encrypt ? new Array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array (94, 62, -2, 32, 64, 2, 30, -2, -2);}
//pad the message depending on the padding parameter
if (padding == 2) message += " "; //pad the message with spaces
else if (padding == 1) {temp = 8-(len%8); message += String.fromCharCode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //PKCS7 padding
else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
//store the result here
result = "";
tempresult = "";
if (mode == 1) { //CBC mode
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
m=0;
}
//loop through each 64 bit chunk of the message
while (m < len) {
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}
//first each 64 but chunk of the message must be permuted according to IP
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
left = ((left << 1) | (left >>> 31));
right = ((right << 1) | (right >>> 31));
//do this either 1 or 3 times for each chunk of the message
for (j=0; j<iterations; j+=3) {
endloop = looping[j+1];
loopinc = looping[j+2];
//now go through and perform the encryption or decryption
for (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency
right1 = right ^ keys[i];
right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];
//the result is attained by passing these bytes through the S selection functions
temp = left;
left = right;
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]
| spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f]
| spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]
| spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
}
temp = left; left = right; right = temp; //unreverse left and right
} //for either 1 or 3 iterations
//move then each one bit to the right
left = ((left >>> 1) | (left << 31));
right = ((right >>> 1) | (right << 31));
//now perform IP-1, which is IP in the opposite direction
temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);
temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);
temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}
tempresult += String.fromCharCode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));
chunk += 8;
if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}
} //for every 8 characters, or 64 bits in the message
//return the result as an array
return result + tempresult;
} //end of des
In case it may be relevant, I have changed the way the request is made too. When the user clicks login, the following promise is called:
Ntlm.login('url')
.then(() => {
console.log('Success');
appSettings.setString('token', 'abc123');
this.router.navigate(['/ilt']);
})
.catch(error => {
console.log('Failed');
appSettings.remove('token');
alert('Failed! ' + error );
})
I created a new login function in the ntlm.js file:
Ntlm.login = function(url) {
return new Promise((resolve, reject) => {
if (!Ntlm.domain || !Ntlm.username || !Ntlm.lmHashedPassword || !Ntlm.ntHashedPassword) {
Ntlm.error('No NTLM credentials specified. Use Ntlm.setCredentials(...) before making calls.');
}
var hostname = Ntlm.getLocation(url).hostname;
var msg1 = Ntlm.createMessage1(hostname);
var request = new XMLHttpRequest();
request.onload = function() {
var response = request.getResponseHeader('WWW-Authenticate');
var challenge = Ntlm.getChallenge(response);
var msg3 = Ntlm.createMessage3(challenge, hostname);
request.open('GET', url, false);
var authorization = 'NTLM ' + msg3.toBase64();
request.setRequestHeader('Authorization', authorization);
request.onload = function() {
if (request.readyState == 4 && request.status == 200) {
resolve(request.status);
}
else if (request.readyState == 4 && request.status != 200) {
reject(request.status);
}
};
request.send(null);
};
request.open('GET', url, false);
request.setRequestHeader('Authorization', 'NTLM ' + msg1.toBase64());
request.send(null);
})
};
This is all working fine on the Android version, just cant understand why it isnt on ios. Very frustrating! If anyone can make sense of this, I would be eternally grateful. I realise it is a lot of code and quite niche area!
Many thanks,
UPDATE
I think there may be a difference in the way console.log behaves in Android and iOS, which could explain some of the missing characters. I created a new test account (testuser / testing), and logged various points to try and establish what was happening in the NTLM process step by step. Here are the logs for android:
NTLM WALKTHROUGH ON ANDROID
Step 1: Creates a cryptographic hash of the users password:
lmHashedPassword = -UE}{}*ªÓ´5µî
ntHashedPassword = |SÏ¥ê}�;�� ûQ£õ
Step 2: Sends first request to the server, with the following Authorisation header:
NTLM TlRMTVNTUAABAAAAA7IAAAUABQBEAAAAJAAkACAAAABHQVRFV0FZLlNUUEFVTFNDQVRIT0xJQ0NPTExFR0UuQ08uVUtBRE1JTg==
Step 3: Server sends a challenge back to client:
¡2#�³Q%Ï
Step 4: Client encrypts this challenge with the hash of the users password and sends back to server (response).
The Authorization header is: NTLM TlRMTVNTUAADAAAAGAAYAKQAAAAYABgAvAAAAAoACgBAAAAAEgASAEoAAABIAEgAXAAAAAAAAADUAAAAAYIAAEEARABNAEkATgB0AGUAcwB0AHMAdABhAGYAZgBHAEEAVABFAFcAQQBZAC4AUwBUAFAAQQBVAEwAUwBDAEEAVABIAE8ATABJAEMAQwBPAEwATABFAEcARQAuAEMATwAuAFUASwBsEslcvTQhhY3+RgKtqufBzFrmufFKNkAHXJRcA6ThOAU105+NJBGnsn2ri6Ziuv8=
Step 5: Now the server has sent the username, challenge and response to the Domain Controller.
The DC compares and returns status of: 200
Here are the logs for iOS:
NTLM WALKTHROUGH ON IOS
Step 1: Creates a cryptographic hash of the users password:
lmHashedPassword = -UE}{}*ªÓ´5µî
ntHashedPassword = |SÏ¥ê}�;�� ûQ£õ
Step 2: Sends the first request to the server, with the following Authorisation header:
NTLM TlRMTVNTUAABAAAAA7IAAAUABQBEAAAAJAAkACAAAABHQVRFV0FZLlNUUEFVTFNDQVRIT0xJQ0NPTExFR0UuQ08uVUtBRE1JTg==
Step 3: Server sends a challenge back to client:
q�v¹,
Step 4: Client encrypts this challenge with the hash of the users password and sends back to server (response).
The Authorization header is: NTLM TlRMTVNTUAADAAAAGAAYAKQAAAAYABgAvAAAAAoACgBAAAAAEgASAEoAAABIAEgAXAAAAAAAAADUAAAAAYIAAEEARABNAEkATgB0AGUAcwB0AHMAdABhAGYAZgBHAEEAVABFAFcAQQBZAC4AUwBUAFAAQQBVAEwAUwBDAEEAVABIAE8ATABJAEMAQwBPAEwATABFAEcARQAuAEMATwAuAFUASwAP9HN5WjPCs9hMRrmttnYHieFrThwyUAWanKWtVdzOqDOJ2isUdQeV0ISmv9TT0ek=
Step 5: Now the server has sent the username, challenge and response to the Domain Controller.
The DC compares returns status of: 401
Seems the credentials are worked out the same, and then the challenge returned from the server is random. But on iOS, the challenge seems to be missing characters - possibly due to the type of characters. The client then encrypts the challenge with the hashed passwords and sends back to the server. I imagine it might be this part which is not correct on iOS.

Shorter version of md5 using JavaScript..?

I have an array of objects in a JSON file. The objects don't have unique ids so I need to create either a unique id, or a unique string.
[
{
"name": "Jack Potts",
"age": "56"
}, {
"name": "Rusty Carr",
"age": "31"
}
]
I know I can use MD5, passing in the object, but I'm going to use the string in a URL, so I'd prefer it to be shorter.
Rather than /people/3449c9e5e332f1dbb81505cd739fbf3f, I'd prefer something more like /people/1dbb81505.
It still needs to be a representation of the object because I'm going to lookup the person again from the URL.
Is there anything that produces a string shorter than the MD5 string..?
I'm going to guess that MD5 is my best/only option, but I thought I'd ask.
UPDATE
I maybe wasn't as clear as I could have been. I don't just need to generate a unique id. I won't be updating the JSON file with whatever I generate.
I need a way to take the object in question, create a URL for it, then when the URL is visited use the URL to get back to that object in the array.
As far as I know, if you pass in the same string to MD5 over and over, it will always return the same MD5 string because it's a representation. Don't people use this when storing passwords in a database for the same reason?
Maybe MD5 is fine, I just thought there might be something which produced a shorter string which is a representation of the data. That's my question.
UPDATE 2
The people in the array may change. People may be added and removed so using the array index won't work.
If you just want a shorter output that MD5 but are otherwise satisfied with the uniqueness just truncate to the length you need, each bit is as random as any other bit, that is any subset of the bits you choose are just as good as any other subset.
But realize that if two names are the same you will get the same hash.
As you must realize the shorter the hash the higher change of a collision, you are making a tradeoff of hash length vs uniqueness, that is not bad, just be sure you have enough uniqueness for your needs.
Use the following function:
function generateUID() {
var firstPart = (Math.random() * 46656) | 0;
var secondPart = (Math.random() * 46656) | 0;
firstPart = ("000" + firstPart.toString(36)).slice(-3);
secondPart = ("000" + secondPart.toString(36)).slice(-3);
return firstPart + secondPart;
}
A 6-character alphanumeric sequence is good enough to randomly index a 10k collection (366 = 2.2 billion and 363 = 46656).
I won't be updating the JSON file with whatever I generate.
I need a way to take the object in question, create a URL for it, then when the URL is visited use the URL to get back to that object in the array.
Then use the index of the object in the array: that way people/0 will return {"name": "Jack Potts", "age": "56"}, people/1 will return {"name": "Rusty Carr", "age": "31"}, and so on...
I suggest you use sha1, it proces a relatively short hash. Supposing your data set is relatively limited < 1000000000000...etc... items chances of collisions should be minimal.
https://github.com/emn178/js-sha1 is a nice library
edit modified this to make it shorter
It now does a substring, + a collision detection modification that should be dependable, as long as the order of the items doesn't change if they have the smae values. But then again, if they have the same values it shouldn't matter ;-)
/*
* [js-sha1]{#link https://github.com/emn178/js-sha1}
*
* #version 0.4.1
* #author Chen, Yi-Cyuan [emn178#gmail.com]
* #copyright Chen, Yi-Cyuan 2014-2016
* #license MIT
*/
/*jslint bitwise: true */
(function() {
'use strict';
var root = typeof window === 'object' ? window : {};
var NODE_JS = !root.JS_SHA1_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
if (NODE_JS) {
root = global;
}
var COMMON_JS = !root.JS_SHA1_NO_COMMON_JS && typeof module === 'object' && module.exports;
var AMD = typeof define === 'function' && define.amd;
var HEX_CHARS = '0123456789abcdef'.split('');
var EXTRA = [-2147483648, 8388608, 32768, 128];
var SHIFT = [24, 16, 8, 0];
var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
var blocks = [];
var createOutputMethod = function (outputType) {
return function (message) {
return new Sha1(true).update(message)[outputType]();
};
};
var createMethod = function () {
var method = createOutputMethod('hex');
if (NODE_JS) {
method = nodeWrap(method);
}
method.create = function () {
return new Sha1();
};
method.update = function (message) {
return method.create().update(message);
};
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
var type = OUTPUT_TYPES[i];
method[type] = createOutputMethod(type);
}
return method;
};
var nodeWrap = function (method) {
var crypto = require('crypto');
var Buffer = require('buffer').Buffer;
var nodeMethod = function (message) {
if (typeof message === 'string') {
return crypto.createHash('sha1').update(message, 'utf8').digest('hex');
} else if (message.constructor === ArrayBuffer) {
message = new Uint8Array(message);
} else if (message.length === undefined) {
return method(message);
}
return crypto.createHash('sha1').update(new Buffer(message)).digest('hex');
};
return nodeMethod;
};
function Sha1(sharedMemory) {
if (sharedMemory) {
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
this.blocks = blocks;
} else {
this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
this.h0 = 0x67452301;
this.h1 = 0xEFCDAB89;
this.h2 = 0x98BADCFE;
this.h3 = 0x10325476;
this.h4 = 0xC3D2E1F0;
this.block = this.start = this.bytes = 0;
this.finalized = this.hashed = false;
this.first = true;
}
Sha1.prototype.update = function (message) {
if (this.finalized) {
return;
}
var notString = typeof(message) !== 'string';
if (notString && message.constructor === root.ArrayBuffer) {
message = new Uint8Array(message);
}
var code, index = 0, i, length = message.length || 0, blocks = this.blocks;
while (index < length) {
if (this.hashed) {
this.hashed = false;
blocks[0] = this.block;
blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
}
if(notString) {
for (i = this.start; index < length && i < 64; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
}
} else {
for (i = this.start; index < length && i < 64; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
} else if (code < 0x800) {
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else if (code < 0xd800 || code >= 0xe000) {
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
}
}
}
this.lastByteIndex = i;
this.bytes += i - this.start;
if (i >= 64) {
this.block = blocks[16];
this.start = i - 64;
this.hash();
this.hashed = true;
} else {
this.start = i;
}
}
return this;
};
Sha1.prototype.finalize = function () {
if (this.finalized) {
return;
}
this.finalized = true;
var blocks = this.blocks, i = this.lastByteIndex;
blocks[16] = this.block;
blocks[i >> 2] |= EXTRA[i & 3];
this.block = blocks[16];
if (i >= 56) {
if (!this.hashed) {
this.hash();
}
blocks[0] = this.block;
blocks[16] = blocks[1] = blocks[2] = blocks[3] =
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
}
blocks[15] = this.bytes << 3;
this.hash();
};
Sha1.prototype.hash = function () {
var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4;
var f, j, t, blocks = this.blocks;
for(j = 16; j < 80; ++j) {
t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16];
blocks[j] = (t << 1) | (t >>> 31);
}
for(j = 0; j < 20; j += 5) {
f = (b & c) | ((~b) & d);
t = (a << 5) | (a >>> 27);
e = t + f + e + 1518500249 + blocks[j] << 0;
b = (b << 30) | (b >>> 2);
f = (a & b) | ((~a) & c);
t = (e << 5) | (e >>> 27);
d = t + f + d + 1518500249 + blocks[j + 1] << 0;
a = (a << 30) | (a >>> 2);
f = (e & a) | ((~e) & b);
t = (d << 5) | (d >>> 27);
c = t + f + c + 1518500249 + blocks[j + 2] << 0;
e = (e << 30) | (e >>> 2);
f = (d & e) | ((~d) & a);
t = (c << 5) | (c >>> 27);
b = t + f + b + 1518500249 + blocks[j + 3] << 0;
d = (d << 30) | (d >>> 2);
f = (c & d) | ((~c) & e);
t = (b << 5) | (b >>> 27);
a = t + f + a + 1518500249 + blocks[j + 4] << 0;
c = (c << 30) | (c >>> 2);
}
for(; j < 40; j += 5) {
f = b ^ c ^ d;
t = (a << 5) | (a >>> 27);
e = t + f + e + 1859775393 + blocks[j] << 0;
b = (b << 30) | (b >>> 2);
f = a ^ b ^ c;
t = (e << 5) | (e >>> 27);
d = t + f + d + 1859775393 + blocks[j + 1] << 0;
a = (a << 30) | (a >>> 2);
f = e ^ a ^ b;
t = (d << 5) | (d >>> 27);
c = t + f + c + 1859775393 + blocks[j + 2] << 0;
e = (e << 30) | (e >>> 2);
f = d ^ e ^ a;
t = (c << 5) | (c >>> 27);
b = t + f + b + 1859775393 + blocks[j + 3] << 0;
d = (d << 30) | (d >>> 2);
f = c ^ d ^ e;
t = (b << 5) | (b >>> 27);
a = t + f + a + 1859775393 + blocks[j + 4] << 0;
c = (c << 30) | (c >>> 2);
}
for(; j < 60; j += 5) {
f = (b & c) | (b & d) | (c & d);
t = (a << 5) | (a >>> 27);
e = t + f + e - 1894007588 + blocks[j] << 0;
b = (b << 30) | (b >>> 2);
f = (a & b) | (a & c) | (b & c);
t = (e << 5) | (e >>> 27);
d = t + f + d - 1894007588 + blocks[j + 1] << 0;
a = (a << 30) | (a >>> 2);
f = (e & a) | (e & b) | (a & b);
t = (d << 5) | (d >>> 27);
c = t + f + c - 1894007588 + blocks[j + 2] << 0;
e = (e << 30) | (e >>> 2);
f = (d & e) | (d & a) | (e & a);
t = (c << 5) | (c >>> 27);
b = t + f + b - 1894007588 + blocks[j + 3] << 0;
d = (d << 30) | (d >>> 2);
f = (c & d) | (c & e) | (d & e);
t = (b << 5) | (b >>> 27);
a = t + f + a - 1894007588 + blocks[j + 4] << 0;
c = (c << 30) | (c >>> 2);
}
for(; j < 80; j += 5) {
f = b ^ c ^ d;
t = (a << 5) | (a >>> 27);
e = t + f + e - 899497514 + blocks[j] << 0;
b = (b << 30) | (b >>> 2);
f = a ^ b ^ c;
t = (e << 5) | (e >>> 27);
d = t + f + d - 899497514 + blocks[j + 1] << 0;
a = (a << 30) | (a >>> 2);
f = e ^ a ^ b;
t = (d << 5) | (d >>> 27);
c = t + f + c - 899497514 + blocks[j + 2] << 0;
e = (e << 30) | (e >>> 2);
f = d ^ e ^ a;
t = (c << 5) | (c >>> 27);
b = t + f + b - 899497514 + blocks[j + 3] << 0;
d = (d << 30) | (d >>> 2);
f = c ^ d ^ e;
t = (b << 5) | (b >>> 27);
a = t + f + a - 899497514 + blocks[j + 4] << 0;
c = (c << 30) | (c >>> 2);
}
this.h0 = this.h0 + a << 0;
this.h1 = this.h1 + b << 0;
this.h2 = this.h2 + c << 0;
this.h3 = this.h3 + d << 0;
this.h4 = this.h4 + e << 0;
};
Sha1.prototype.hex = function () {
this.finalize();
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +
HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +
HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +
HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +
HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F];
};
Sha1.prototype.toString = Sha1.prototype.hex;
Sha1.prototype.digest = function () {
this.finalize();
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
return [
(h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,
(h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,
(h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,
(h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,
(h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF
];
};
Sha1.prototype.array = Sha1.prototype.digest;
Sha1.prototype.arrayBuffer = function () {
this.finalize();
var buffer = new ArrayBuffer(20);
var dataView = new DataView(buffer);
dataView.setUint32(0, this.h0);
dataView.setUint32(4, this.h1);
dataView.setUint32(8, this.h2);
dataView.setUint32(12, this.h3);
dataView.setUint32(16, this.h4);
return buffer;
};
var exports = createMethod();
if (COMMON_JS) {
module.exports = exports;
} else {
root.sha1 = exports;
if (AMD) {
define(function () {
return exports;
});
}
}
})();
+function() {
var HASHLENGTH = 5;
document.getElementById('clickme').onclick = function() {
// get all the values as objects
var values = JSON.parse(document.getElementById('sample').value);
for (var c = 0; c < values.length; c++) {
// Hash it and substring it given the hashlength
values[c].hash = sha1(JSON.stringify(values[c])).substring(0,HASHLENGTH);
// If you don't need the collision detection, you can just remove these loops.
// check for collisions
for(var i = 0;i < c; i++) {
// collision detected. add a dependable value to get a new hash.
if(values[i].hash == values[c].hash) {
if(values[c].hasOwnProperty('_change')) {
values[c]._change = sha1(values[c]._change);
}
else {
values[c]._change = sha1(values[c].hash);
}
c--;break; // return to same thing for a rehash
}
}
}
console.log(JSON.stringify(values,null,4));
}
}();
textarea { width:100%;height:200px;}
<button id="clickme"> Parse </button>
<textarea id="sample">
[
{
"name": "Jack Potts",
"age": "56"
}, {
"name": "Rusty Carr",
"age": "31"
},
{
"name": "Rusty Carr",
"age": "31"
},
{
"name": "Rusty Carr",
"age": "31"
},
{
"name": "Rusty Carr",
"age": "31"
},
{
"name": "Rusty Carr",
"age": "31"
},
{
"name": "Rusty Carr",
"age": "31"
}
]
</textarea>
Here is native JavaScript code to get an MD5 hash, shortened to a desired length. Mind you, the shorter the hash, the more likely you get collisions.
var md5 = function(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}
function tinymd5(str, length) {
length = length || 16;
str = window.btoa(md5(str)).replace(/[aiueoAIUEO\+\/]/g, '').substring(0, length);
if(str.length < length) {
str += Array(length - str.length).join('=');
}
return str;
}
// example usage:
var shortHash = tinymd5(JSON.stringify(someObj), 16);
The md5 function is from https://stackoverflow.com/a/33486055/7475450
The tinymd5 function is code converted to JavaScript based on https://rolandeckert.com/notes/md5
Maybe it works using 3125 chars :
const md5=str=>{var a=(r,t)=>r+t&0xffffffff,l=(r,t)=>{var e=r[0],n=r[1],o=r[2],l=r[3],e=h(e,n,o,l,t[0],7,-0x28955b88),l=h(l,e,n,o,t[1],12,-0x173848aa),o=h(o,l,e,n,t[2],17,0x242070db),n=h(n,o,l,e,t[3],22,-0x3e423112);e=h(e,n,o,l,t[4],7,-0xa83f051),l=h(l,e,n,o,t[5],12,0x4787c62a),o=h(o,l,e,n,t[6],17,-0x57cfb9ed),n=h(n,o,l,e,t[7],22,-0x2b96aff),e=h(e,n,o,l,t[8],7,0x698098d8),l=h(l,e,n,o,t[9],12,-0x74bb0851),o=h(o,l,e,n,t[10],17,-42063),n=h(n,o,l,e,t[11],22,-0x76a32842),e=h(e,n,o,l,t[12],7,0x6b901122),l=h(l,e,n,o,t[13],12,-0x2678e6d),o=h(o,l,e,n,t[14],17,-0x5986bc72),n=h(n,o,l,e,t[15],22,0x49b40821),e=c(e,n,o,l,t[1],5,-0x9e1da9e),l=c(l,e,n,o,t[6],9,-0x3fbf4cc0),o=c(o,l,e,n,t[11],14,0x265e5a51),n=c(n,o,l,e,t[0],20,-0x16493856),e=c(e,n,o,l,t[5],5,-0x29d0efa3),l=c(l,e,n,o,t[10],9,0x2441453),o=c(o,l,e,n,t[15],14,-0x275e197f),n=c(n,o,l,e,t[4],20,-0x182c0438),e=c(e,n,o,l,t[9],5,0x21e1cde6),l=c(l,e,n,o,t[14],9,-0x3cc8f82a),o=c(o,l,e,n,t[3],14,-0xb2af279),n=c(n,o,l,e,t[8],20,0x455a14ed),e=c(e,n,o,l,t[13],5,-0x561c16fb),l=c(l,e,n,o,t[2],9,-0x3105c08),o=c(o,l,e,n,t[7],14,0x676f02d9),n=c(n,o,l,e,t[12],20,-0x72d5b376),e=d(e,n,o,l,t[5],4,-378558),l=d(l,e,n,o,t[8],11,-0x788e097f),o=d(o,l,e,n,t[11],16,0x6d9d6122),n=d(n,o,l,e,t[14],23,-0x21ac7f4),e=d(e,n,o,l,t[1],4,-0x5b4115bc),l=d(l,e,n,o,t[4],11,0x4bdecfa9),o=d(o,l,e,n,t[7],16,-0x944b4a0),n=d(n,o,l,e,t[10],23,-0x41404390),e=d(e,n,o,l,t[13],4,0x289b7ec6),l=d(l,e,n,o,t[0],11,-0x155ed806),o=d(o,l,e,n,t[3],16,-0x2b10cf7b),n=d(n,o,l,e,t[6],23,0x4881d05),e=d(e,n,o,l,t[9],4,-0x262b2fc7),l=d(l,e,n,o,t[12],11,-0x1924661b),o=d(o,l,e,n,t[15],16,0x1fa27cf8),n=d(n,o,l,e,t[2],23,-0x3b53a99b),e=g(e,n,o,l,t[0],6,-0xbd6ddbc),l=g(l,e,n,o,t[7],10,0x432aff97),o=g(o,l,e,n,t[14],15,-0x546bdc59),n=g(n,o,l,e,t[5],21,-0x36c5fc7),e=g(e,n,o,l,t[12],6,0x655b59c3),l=g(l,e,n,o,t[3],10,-0x70f3336e),o=g(o,l,e,n,t[10],15,-0x100b83),n=g(n,o,l,e,t[1],21,-0x7a7ba22f),e=g(e,n,o,l,t[8],6,0x6fa87e4f),l=g(l,e,n,o,t[15],10,-0x1d31920),o=g(o,l,e,n,t[6],15,-0x5cfebcec),n=g(n,o,l,e,t[13],21,0x4e0811a1),e=g(e,n,o,l,t[4],6,-0x8ac817e),l=g(l,e,n,o,t[11],10,-0x42c50dcb),o=g(o,l,e,n,t[2],15,0x2ad7d2bb),n=g(n,o,l,e,t[9],21,-0x14792c6f),r[0]=a(e,r[0]),r[1]=a(n,r[1]),r[2]=a(o,r[2]),r[3]=a(l,r[3])},f=(r,t,e,n,o,l)=>(t=a(a(t,r),a(n,l)),a(t<<o|t>>>32-o,e));let h=(r,t,e,n,o,l,a)=>f(t&e|~t&n,r,t,o,l,a),c=(r,t,e,n,o,l,a)=>f(t&n|e&~n,r,t,o,l,a),d=(r,t,e,n,o,l,a)=>f(t^e^n,r,t,o,l,a),g=(r,t,e,n,o,l,a)=>f(e^(t|~n),r,t,o,l,a);var n="0123456789abcdef".split("");return(t=>{for(let r=0;r<t.length;r++)t[r]=(r=>{let t="",e=0;for(;e<4;e++)t+=n[r>>8*e+4&15]+n[r>>8*e&15];return t})(t[r]);return t.join("")})((r=>{let t=r.length,e=[0x67452301,-0x10325477,-0x67452302,0x10325476],n;for(n=64;n<=r.length;n+=64)l(e,(r=>{let t=[],e;for(e=0;e<64;e+=4)t[e>>2]=r.charCodeAt(e)+(r.charCodeAt(e+1)<<8)+(r.charCodeAt(e+2)<<16)+(r.charCodeAt(e+3)<<24);return t})(r.substring(n-64,n)));r=r.substring(n-64);let o=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(n=0;n<r.length;n++)o[n>>2]|=r.charCodeAt(n)<<(n%4<<3);if(o[n>>2]|=128<<(n%4<<3),55<n)for(l(e,o),n=0;n<16;n++)o[n]=0;return o[14]=8*t,l(e,o),e})("string"==typeof str?str:""+str))};

Create SHA-256 hash from a Blob/File in javascript

I need to create a SHA-256 digest from a file (~6MB) inside the browser. The only way that I've managed to do it so far was like this:
var reader = new FileReader();
reader.onload = function() {
// this gets rid of the mime-type data header
var actual_contents = reader.result.slice(reader.result.indexOf(',') + 1);
var what_i_need = new jsSHA(actual_contents, "B64").getHash("SHA-256", "HEX");
}
reader.readAsDataURL(some_file);
While this works correctly, the problem is that it's very slow. It took ~2-3 seconds for a 6MB file. How can I improve this?
You may want to take a look at the Stanford JS Crypto Library
GitHub
Website with Examples
From the website:
SJCL is secure. It uses the industry-standard AES algorithm at 128, 192 or 256 bits; the SHA256 hash function; the HMAC authentication code; the PBKDF2 password strengthener; and the CCM and OCB authenticated-encryption modes.
SJCL has a test page that shows how long it will take.
184 milliseconds for a SHA256 iterative. And 50 milliseconds for a SHA-256 from catameringue.
Test page
Sample code:
Encrypt data:
sjcl.encrypt("password", "data")
Decrypt data: sjcl.decrypt("password", "encrypted-data")
This is an old question but I thought it's worth noting that asmCrypto is significantly faster than jsSHA, and faster than CryptoJS and SJCL
https://github.com/vibornoff/asmcrypto.js/
There is also a lite version (a fork of the above) maintained by OpenPGP.js
https://github.com/openpgpjs/asmcrypto-lite
Which only includes SHA256, and a couple of AES features.
To use asmCrypto You can simply do the following:
var sha256HexValue = asmCrypto.SHA256.hex(myArraybuffer);
I'm able to hash a 150MB+ file in < 2 seconds consistently in Chrome.
Here is what your looking for. I derived this from a C version of the SHA256 algorithm. It also includes SHA256D. I don't think your going to get much faster than this with javascript. I tried expanding the loops and it ran slower due to optimizations run by the javascript interpreter.
// From: https://github.com/Hartland/GPL-CPU-Miner/blob/master/sha2.c
if ("undefined" == typeof vnet) {
vnet = new Array();
}
if ("undefined" == typeof vnet.crypt) {
vnet.crypt = new Array();
}
vnet.crypt.sha2 = function() {
var sha256_h = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
var sha256_k = [
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
];
var sha256_init = function(s) {
s.state = [
sha256_h[0],
sha256_h[1],
sha256_h[2],
sha256_h[3],
sha256_h[4],
sha256_h[5],
sha256_h[6],
sha256_h[7],
];
}; this.sha256_init = sha256_init;
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
var sha256_transform = function(s, b, swap) {
var block = b.block;
var state = s.state;
var W;
var S;
var t0;
var t1;
var i;
/* 1. Prepare message schedule W. */
if (swap) {
W = [
((((block[0] ) << 24) & 0xff000000) | (((block[0] ) << 8) & 0x00ff0000) | (((block[0] ) >> 8) & 0x0000ff00) | (((block[0] ) >> 24) & 0x000000ff)),
((((block[1] ) << 24) & 0xff000000) | (((block[1] ) << 8) & 0x00ff0000) | (((block[1] ) >> 8) & 0x0000ff00) | (((block[1] ) >> 24) & 0x000000ff)),
((((block[2] ) << 24) & 0xff000000) | (((block[2] ) << 8) & 0x00ff0000) | (((block[2] ) >> 8) & 0x0000ff00) | (((block[2] ) >> 24) & 0x000000ff)),
((((block[3] ) << 24) & 0xff000000) | (((block[3] ) << 8) & 0x00ff0000) | (((block[3] ) >> 8) & 0x0000ff00) | (((block[3] ) >> 24) & 0x000000ff)),
((((block[4] ) << 24) & 0xff000000) | (((block[4] ) << 8) & 0x00ff0000) | (((block[4] ) >> 8) & 0x0000ff00) | (((block[4] ) >> 24) & 0x000000ff)),
((((block[5] ) << 24) & 0xff000000) | (((block[5] ) << 8) & 0x00ff0000) | (((block[5] ) >> 8) & 0x0000ff00) | (((block[5] ) >> 24) & 0x000000ff)),
((((block[6] ) << 24) & 0xff000000) | (((block[6] ) << 8) & 0x00ff0000) | (((block[6] ) >> 8) & 0x0000ff00) | (((block[6] ) >> 24) & 0x000000ff)),
((((block[7] ) << 24) & 0xff000000) | (((block[7] ) << 8) & 0x00ff0000) | (((block[7] ) >> 8) & 0x0000ff00) | (((block[7] ) >> 24) & 0x000000ff)),
((((block[8] ) << 24) & 0xff000000) | (((block[8] ) << 8) & 0x00ff0000) | (((block[8] ) >> 8) & 0x0000ff00) | (((block[8] ) >> 24) & 0x000000ff)),
((((block[9] ) << 24) & 0xff000000) | (((block[9] ) << 8) & 0x00ff0000) | (((block[9] ) >> 8) & 0x0000ff00) | (((block[9] ) >> 24) & 0x000000ff)),
((((block[10]) << 24) & 0xff000000) | (((block[10]) << 8) & 0x00ff0000) | (((block[10]) >> 8) & 0x0000ff00) | (((block[10]) >> 24) & 0x000000ff)),
((((block[11]) << 24) & 0xff000000) | (((block[11]) << 8) & 0x00ff0000) | (((block[11]) >> 8) & 0x0000ff00) | (((block[11]) >> 24) & 0x000000ff)),
((((block[12]) << 24) & 0xff000000) | (((block[12]) << 8) & 0x00ff0000) | (((block[12]) >> 8) & 0x0000ff00) | (((block[12]) >> 24) & 0x000000ff)),
((((block[13]) << 24) & 0xff000000) | (((block[13]) << 8) & 0x00ff0000) | (((block[13]) >> 8) & 0x0000ff00) | (((block[13]) >> 24) & 0x000000ff)),
((((block[14]) << 24) & 0xff000000) | (((block[14]) << 8) & 0x00ff0000) | (((block[14]) >> 8) & 0x0000ff00) | (((block[14]) >> 24) & 0x000000ff)),
((((block[15]) << 24) & 0xff000000) | (((block[15]) << 8) & 0x00ff0000) | (((block[15]) >> 8) & 0x0000ff00) | (((block[15]) >> 24) & 0x000000ff))
];
} else {
W = [
block[0],
block[1],
block[2],
block[3],
block[4],
block[5],
block[6],
block[7],
block[8],
block[9],
block[10],
block[11],
block[12],
block[13],
block[14],
block[15]
];
}
for (i = 16; i < 64; i += 2) {
W[i] = ((
((((W[i-2] >>> 17) | (W[i-2] << 15)) ^ ((W[i-2] >>> 19) | ((W[i-2] << 13)>>>0) ) ^ (W[i - 2] >>> 10)) >>> 0) + //s1 (W[i - 2]) +
W[i - 7] +
((((W[i - 15] >>> 7) | (W[i - 15] << 25)) ^ ((W[i - 15] >>> 18) | ((W[i - 15] << 14) >>> 0)) ^ (W[i - 15] >>> 3)) >>> 0) + //s0 (W[i - 15]) +
W[i - 16]
) & 0xffffffff) >>> 0;
W[i+1] = ((
((((W[i-1] >>> 17) | (W[i-1] << 15)) ^ ((W[i-1] >>> 19) | (W[i-1] << 13)) ^ (W[i - 1] >>> 10)) >>> 0)+ //s1 (W[i - 1]) +
W[i - 6] +
((((W[i - 14] >>> 7) | (W[i - 14] << 25)) ^ ((W[i - 14] >>> 18) | (W[i - 14] << 14)) ^ (W[i - 14] >>> 3)) >>> 0) + //s0 (W[i - 14]) +
W[i - 15]
) & 0xffffffff) >>> 0;
}
/* 2. Initialize working variables. */
S = [
state[0],
state[1],
state[2],
state[3],
state[4],
state[5],
state[6],
state[7],
];
/* 3. Mix. */
i=0;
for(;i<64;++i) {
//RNDr(S,W,i)
t0 = S[(71 - i) % 8] +
((((S[(68 - i) % 8] >>> 6) | (S[(68 - i) % 8] << 26)) ^ ((S[(68 - i) % 8] >>> 11) | (S[(68 - i) % 8] << 21)) ^ ((S[(68 - i) % 8] >>> 25) | (S[(68 - i) % 8] << 7)))) + //S1 (S[(68 - i) % 8]) +
(((S[(68 - i) % 8] & (S[(69 - i) % 8] ^ S[(70 - i) % 8])) ^ S[(70 - i) % 8]) ) + // Ch
W[i] +
sha256_k[i];
t1 = ((((S[(64 - i) % 8] >>> 2) | ((S[(64 - i) % 8] & 3) << 30)) ^ ((S[(64 - i) % 8] >>> 13) | (S[(64 - i) % 8] << 19)) ^ ((S[(64 - i) % 8] >>> 22) | (S[(64 - i) % 8] << 10)))) + //S0 (S[(64 - i) % 8]) +
(((S[(64 - i) % 8] & (S[(65 - i) % 8] | S[(66 - i) % 8])) | (S[(65 - i) % 8] & S[(66 - i) % 8]))); // Maj
S[(67 - i) % 8] = ((S[(67 - i) % 8] + t0) & 0xFFFFFFFF) >>> 0;
S[(71 - i) % 8] = ((t0 + t1) & 0xFFFFFFFF) >>> 0;
}
/* 4. Mix local working variables into global state */
i=0;
for(;i<8;++i) {
s.state[i] = (0xFFFFFFFF & (state[i] + S[i])) >>> 0;
}
}; this.sha256_transform = sha256_transform;
var sha256d_hash1 = [
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x80000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000100
];
var sha256d_80_swap = function(hash, data)
{
var S = new Array();
var i;
var b1 = new Array();
var b2 = new Array();
var b3 = new Array();
b1.block = [
data[0],
data[1],
data[2],
data[3],
data[4],
data[5],
data[6],
data[7],
data[8],
data[9],
data[10],
data[11],
data[12],
data[13],
data[14],
data[15]
];
b2.block = [
data[16],
data[17],
data[18],
data[19],
data[20],
data[21],
data[22],
data[23],
data[24],
data[25],
data[26],
data[27],
data[28],
data[29],
data[30],
data[31]
];
sha256_init(S);
sha256_transform(S, b1, 0);
sha256_transform(S, b2, 0);
b3.block = [
S.state[0],
S.state[1],
S.state[2],
S.state[3],
S.state[4],
S.state[5],
S.state[6],
S.state[7],
sha256d_hash1[8],
sha256d_hash1[9],
sha256d_hash1[10],
sha256d_hash1[11],
sha256d_hash1[12],
sha256d_hash1[13],
sha256d_hash1[14],
sha256d_hash1[15]
];
sha256_init(hash);
sha256_transform(hash, b3, 0);
for (i = 0; i < 8; i++) {
hash.state[i] = ((((hash.state[i] ) << 24) & 0xff000000) | (((hash.state[i] ) << 8) & 0x00ff0000) | (((hash.state[i] ) >> 8) & 0x0000ff00) | (((hash.state[i] ) >> 24) & 0x000000ff)); //swab32(hash[i]);
}
}; this.sha256d_80_swap = sha256d_80_swap;
var sha256d = function(hash, data) {
var S;
var T;
var block_in;
S = new Array();
T = new Array();
T.block = [];
var i, r;
//hash.hash = new Array(32).join('0').split('').map(parseFloat);
sha256_init(S);
for (r = data.length; r > -9; r -= 64) {
if (r < 64) {
if (r > 0) {
block_in = data.slice(data.length - r,data.length);
block_in.push.apply(block_in, new Array(64-r).join('0').split('').map(parseFloat));
} else {
block_in = new Array(64).join('0').split('').map(parseFloat);
}
} else {
block_in = data.slice(data.length - r,data.length - r + 64);
}
//memcpy(T, data + len - r, r > 64 ? 64 : (r < 0 ? 0 : r));
if (r >= 0 && r < 64) {
block_in[r] = 0x80;
}
for (i = 0; i < 16; i++) {
T.block[i] = (((0xff & block_in[(i*4)]) << 24) | ((0xff & block_in[(i*4)+1]) << 16) | ((0xff & block_in[(i*4)+2]) << 8) | (0xff & block_in[(i*4)+3])) >>> 0;
}
if (r < 56) {
T.block[15] = 8 * data.length;
}
sha256_transform(S, T, 0);
}
//memcpy(S + 8, sha256d_hash1 + 8, 32);
S.block = S.state;
for(i=8;i<16;i++) {
S.block[i] = sha256d_hash1[i];
}
sha256_init(T);
sha256_transform(T, S, 0);
hash.hash = [
(T.state[0] >> 24) & 0xff,
(T.state[0] >> 16) & 0xff,
(T.state[0] >> 8) & 0xff,
T.state[0] & 0xff,
(T.state[1] >> 24) & 0xff,
(T.state[1] >> 16) & 0xff,
(T.state[1] >> 8) & 0xff,
T.state[1] & 0xff,
(T.state[2] >> 24) & 0xff,
(T.state[2] >> 16) & 0xff,
(T.state[2] >> 8) & 0xff,
T.state[2] & 0xff,
(T.state[3] >> 24) & 0xff,
(T.state[3] >> 16) & 0xff,
(T.state[3] >> 8) & 0xff,
T.state[3] & 0xff,
(T.state[4] >> 24) & 0xff,
(T.state[4] >> 16) & 0xff,
(T.state[4] >> 8) & 0xff,
T.state[4] & 0xff,
(T.state[5] >> 24) & 0xff,
(T.state[5] >> 16) & 0xff,
(T.state[5] >> 8) & 0xff,
T.state[5] & 0xff,
(T.state[6] >> 24) & 0xff,
(T.state[6] >> 16) & 0xff,
(T.state[6] >> 8) & 0xff,
T.state[6] & 0xff,
(T.state[7] >> 24) & 0xff,
(T.state[7] >> 16) & 0xff,
(T.state[7] >> 8) & 0xff,
T.state[7] & 0xff
];
}; this.sha256d = sha256d;
var sha256 = function(hash, data) {
var S;
var T;
var block_in;
S = new Array();
T = new Array();
T.block = [];
var i, r;
hash.hash = new Array(32).join('0').split('').map(parseFloat);
sha256_init(S);
for (r = data.length; r > -9; r -= 64) {
if (r < 64) {
if (r > 0) {
block_in = data.slice(data.length - r,data.length);
block_in.push.apply(block_in, new Array(64-r).join('0').split('').map(parseFloat));
} else {
block_in = new Array(64).join('0').split('').map(parseFloat);
}
} else {
block_in = data.slice(data.length - r,data.length - r + 64);
}
//memcpy(T, data + len - r, r > 64 ? 64 : (r < 0 ? 0 : r));
if (r >= 0 && r < 64) {
block_in[r] = 0x80;
}
for (i = 0; i < 16; i++) {
T.block[i] = (((0xff & block_in[(i*4)]) << 24) | ((0xff & block_in[(i*4)+1]) << 16) | ((0xff & block_in[(i*4)+2]) << 8) | (0xff & block_in[(i*4)+3])) >>> 0;
}
if (r < 56) {
T.block[15] = 8 * data.length;
}
sha256_transform(S, T, 0);
}
for (i = 0; i < 8; i++) {
//be32enc((uint32_t *)hash + i, T[i]);
hash.hash[(i * 4)] = (S.state[i] >> 24) & 0xff;
hash.hash[(i * 4)+1] = (S.state[i] >> 16) & 0xff
hash.hash[(i * 4)+2] = (S.state[i] >> 8) & 0xff
hash.hash[(i * 4)+3] = S.state[i] & 0xff;
}
}; this.sha256 = sha256;
};
It might be faster to use an emscripten compiled version of the crypto libraries,
Q. How fast will the compiled code be?
A. Emscripten's default code generation mode is in asm.js format,
which is a subset of JavaScript designed to make it possible for
JavaScript engines to execute very quickly. See here for up-to-date
benchmark results. In many cases, asm.js can get quite close to native
speed.
You can find an Emscripten-compiled NaCl cryptographic library here.
I use SubtleCrypto.digest()
test file about ~85MB, It doesn't take a second to finish.
<input type="file" multiple/>
<input placeholder="Press `Enter` when done."/>
<script>
/**
* #param {"SHA-1"|"SHA-256"|"SHA-384"|"SHA-512"} algorithm https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
* #param {string|Blob} data
*/
async function getHash(algorithm, data) {
const main = async (msgUint8) => { // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
const hashBuffer = await crypto.subtle.digest(algorithm, msgUint8)
const hashArray = Array.from(new Uint8Array(hashBuffer))
return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
}
if (data instanceof Blob) {
const arrayBuffer = await data.arrayBuffer()
const msgUint8 = new Uint8Array(arrayBuffer)
return await main(msgUint8)
}
const encoder = new TextEncoder()
const msgUint8 = encoder.encode(data)
return await main(msgUint8)
}
const inputFile = document.querySelector(`input[type="file"]`)
const inputText = document.querySelector(`input[placeholder^="Press"]`)
inputFile.onchange = async (event) => {
for (const file of event.target.files) {
console.log(file.name, file.type, file.size + "bytes")
const hashHex = await getHash("SHA-256", new Blob([file]))
console.log(hashHex)
}
}
inputText.onkeyup = async (keyboardEvent) => {
if (keyboardEvent.key === "Enter") {
const hashHex = await getHash("SHA-256", keyboardEvent.target.value)
console.log(hashHex)
}
}
</script>
As some have answered, it can be done in vanillajs :
async function getChecksumSha256(blob: Blob): Promise<string> {
const uint8Array = new Uint8Array(await blob.arrayBuffer());
const hashBuffer = await crypto.subtle.digest('SHA-256', uint8Array);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((h) => h.toString(16).padStart(2, '0')).join('');
}
Source : https://gist.github.com/bilelz/c96fb0b1f62983d061910e8d310a5162
You can do that without external libraries using Crypto.subtle API. More details here.
Example:
function b2h(buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
const FILEREADER = new FileReader();
FILEREADER.readAsArrayBuffer(file);
FILEREADER.onloadend = async function(entry) {
const FILE_HASH = b2h(await crypto.subtle.digest('SHA-256', entry.target.result)); // output: the sha256 digest hex encoded of the file
}

base 64 encoding in javascript

Below is a base 64 image encoding function that I got from Philippe Tenenhaus (http://www.philten.com/us-xmlhttprequest-image/).
It's very confusing to me, but I'd love to understand.
I think I understand the bitwise & and | , and moving through byte position with << and >>.
I'm especially confused at those lines :
((byte1 & 3) << 4) | (byte2 >> 4);
((byte2 & 15) << 2) | (byte3 >> 6);
And why it still using byte1 for enc2, and byte2 for enc3.
And the purpose of enc4 = byte3 & 63; ...
Can someone could explain this function.
function base64Encode(inputStr)
{
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var outputStr = "";
var i = 0;
while (i < inputStr.length)
{
//all three "& 0xff" added below are there to fix a known bug
//with bytes returned by xhr.responseText
var byte1 = inputStr.charCodeAt(i++) & 0xff;
var byte2 = inputStr.charCodeAt(i++) & 0xff;
var byte3 = inputStr.charCodeAt(i++) & 0xff;
var enc1 = byte1 >> 2;
var enc2 = ((byte1 & 3) << 4) | (byte2 >> 4);
var enc3, enc4;
if (isNaN(byte2))
{
enc3 = enc4 = 64;
}
else
{
enc3 = ((byte2 & 15) << 2) | (byte3 >> 6);
if (isNaN(byte3))
{
enc4 = 64;
}
else
{
enc4 = byte3 & 63;
}
}
outputStr += b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
}
return outputStr;
}
It probably helps to understand what Base64 encoding does. It converts 24 bits in groupings of 8 bits into groupings of 6 bits. (http://en.wikipedia.org/wiki/Base64)
So enc1, is the first 6-bits which are the first 6-bits of the first Byte.
enc2, is the next 6-bits, the last 2-bits of the first Byte and first 4-bits of the second Byte. The bitwise and operation byte1 & 3 targets the last 2 bits in the first Byte.
So,
XXXXXXXX & 00000011 = 000000XX
It is then shifted to the left 4 bits.
000000XX << 4 = 00XX0000.
The byte2 >> 4 performs a right bit shift, isolating the first 4 bits of the second Byte, shown below
YYYYXXXX >> 4 = 0000YYYY
So, ((byte1 & 3) << 4) | (byte2 >> 4) combines the results with a bitwise or
00XX0000 | 0000YYYY = 00XXYYYY
enc3, is the last 4-bits of the second byte and the first 2-bits of the 3rd Byte.
enc4 is the last 6-bits of the 3rd Byte.
charCodeAt returns a Unicode code point which is a 16-bit value, so it appears there is an assumption that the relevant information is only in the low 8-bits. This assumption makes me wonder if there still is a bug in the code. There could be some information lost as a result of this assumption.

Categories

Resources