Skip to content

Instantly share code, notes, and snippets.

@wadeharrell
Created August 9, 2011 18:33
Show Gist options
  • Save wadeharrell/1134823 to your computer and use it in GitHub Desktop.
Save wadeharrell/1134823 to your computer and use it in GitHub Desktop.
condensed version of Paul Johnston's sha512.js
/*
* This script is derived from Paul Johnston's sha512.js
*/
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
* in FIPS 180-2
* Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
(function(ns){
var $,
rstr2hex,
rstr_sha512,
str2rstr_utf8,
binb2rstr,
binb_sha512,
rstr2binb,
sha512_k,
Int64,
int64copy,
int64rrot,
int64revrrot,
int64shr,
int64add,
int64add4,
int64add5;
/*
* Core function of the namespace
*/
$ = function(s){
return rstr2hex(rstr_sha512(str2rstr_utf8(s)));
};
/*
* Convert a raw string to a hex string
*/
rstr2hex = function(input){
var hex_tab = '0123456789abcdef',
output = '',
x,i,l;
for(i=0,l=input.length;i<l;i++){
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F);
output += hex_tab.charAt( x & 0x0F);
}
return output;
};
/*
* Calculate the SHA-512 of a raw string
*/
rstr_sha512 = function(s){
return binb2rstr(binb_sha512(rstr2binb(s),s.length*8));
};
/*
* Encode a string as utf-8.
* For efficiency, this assumes the input is valid utf-16.
*/
str2rstr_utf8 = function(input){
var output = '',
i = -1,
l = input.length,
x, y;
while(++i<l){
/* Decode utf-16 surrogate pairs */
x = input.charCodeAt(i);
y = (i+1 < l)?input.charCodeAt(i+1):0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF){
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
/* Encode output as utf-8 */
if(x <= 0x7F){
output += String.fromCharCode(x);
}else if(x <= 0x7FF){
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
0x80 | ( x & 0x3F));
}else if(x <= 0xFFFF){
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}else if(x <= 0x1FFFFF){
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}
}
return output;
};
/*
* Convert an array of big-endian words to a string
*/
binb2rstr = function(input){
var i,l,output = '';
for(i=0,l=input.length*32;i<l;i+=8){
output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
}
return output;
};
/*
* Calculate the SHA-512 of an array of big-endian dwords, and a bit length
*/
binb_sha512 = function(x,len){
var H,T1,T2,a,b,c,d,e,f,g,h,s0,s1,Ch,Maj,r1,r2,r3,j,i,l,W,hash;
if(sha512_k === undefined){
//SHA512 constants
sha512_k = [
new Int64(0x428a2f98,-685199838), new Int64(0x71374491,0x23ef65cd),
new Int64(-1245643825,-330482897), new Int64(-373957723,-2121671748),
new Int64(0x3956c25b,-213338824), new Int64(0x59f111f1,-1241133031),
new Int64(-1841331548,-1357295717), new Int64(-1424204075,-630357736),
new Int64(-670586216,-1560083902), new Int64(0x12835b01,0x45706fbe),
new Int64(0x243185be,0x4ee4b28c), new Int64(0x550c7dc3,-704662302),
new Int64(0x72be5d74,-226784913), new Int64(-2132889090,0x3b1696b1),
new Int64(-1680079193,0x25c71235), new Int64(-1046744716,-815192428),
new Int64(-459576895,-1628353838), new Int64(-272742522,0x384f25e3),
new Int64(0xfc19dc6,-1953704523), new Int64(0x240ca1cc,0x77ac9c65),
new Int64(0x2de92c6f,0x592b0275), new Int64(0x4a7484aa,0x6ea6e483),
new Int64(0x5cb0a9dc,-1119749164), new Int64(0x76f988da,-2096016459),
new Int64(-1740746414,-295247957), new Int64(-1473132947,0x2db43210),
new Int64(-1341970488,-1728372417), new Int64(-1084653625,-1091629340),
new Int64(-958395405,0x3da88fc2), new Int64(-710438585,-1828018395),
new Int64(0x6ca6351,-536640913), new Int64(0x14292967,0xa0e6e70),
new Int64(0x27b70a85,0x46d22ffc), new Int64(0x2e1b2138,0x5c26c926),
new Int64(0x4d2c6dfc,0x5ac42aed), new Int64(0x53380d13,-1651133473),
new Int64(0x650a7354,-1951439906), new Int64(0x766a0abb,0x3c77b2a8),
new Int64(-2117940946,0x47edaee6), new Int64(-1838011259,0x1482353b),
new Int64(-1564481375,0x4cf10364), new Int64(-1474664885,-1136513023),
new Int64(-1035236496,-789014639), new Int64(-949202525,0x654be30),
new Int64(-778901479,-688958952), new Int64(-694614492,0x5565a910),
new Int64(-200395387,0x5771202a), new Int64(0x106aa070,0x32bbd1b8),
new Int64(0x19a4c116,-1194143544), new Int64(0x1e376c08,0x5141ab53),
new Int64(0x2748774c,-544281703), new Int64(0x34b0bcb5,-509917016),
new Int64(0x391c0cb3,-976659869), new Int64(0x4ed8aa4a,-482243893),
new Int64(0x5b9cca4f,0x7763e373), new Int64(0x682e6ff3,-692930397),
new Int64(0x748f82ee,0x5defb2fc), new Int64(0x78a5636f,0x43172f60),
new Int64(-2067236844,-1578062990), new Int64(-1933114872,0x1a6439ec),
new Int64(-1866530822,0x23631e28), new Int64(-1538233109,-561857047),
new Int64(-1090935817,-1295615723), new Int64(-965641998,-479046869),
new Int64(-903397682,-366583396), new Int64(-779700025,0x21c0c207),
new Int64(-354779690,-840897762), new Int64(-176337025,-294727304),
new Int64(0x6f067aa,0x72176fba), new Int64(0xa637dc5,-1563912026),
new Int64(0x113f9804,-1090974290), new Int64(0x1b710b35,0x131c471b),
new Int64(0x28db77f5,0x23047d84), new Int64(0x32caab7b,0x40c72493),
new Int64(0x3c9ebe0a,0x15c9bebc), new Int64(0x431d67c4,-1676669620),
new Int64(0x4cc5d4be,-885112138), new Int64(0x597f299c,-60457430),
new Int64(0x5fcb6fab,0x3ad6faec), new Int64(0x6c44198c,0x4a475817)
];
}
//Initial hash values
H = [
new Int64(0x6a09e667,-205731576),
new Int64(-1150833019,-2067093701),
new Int64(0x3c6ef372,-23791573),
new Int64(-1521486534,0x5f1d36f1),
new Int64(0x510e527f,-1377402159),
new Int64(-1694144372,0x2b3e6c1f),
new Int64(0x1f83d9ab,-79577749),
new Int64(0x5be0cd19,0x137e2179)
];
T1 = new Int64(0,0);
T2 = new Int64(0,0);
a = new Int64(0,0);
b = new Int64(0,0);
c = new Int64(0,0);
d = new Int64(0,0);
e = new Int64(0,0);
f = new Int64(0,0);
g = new Int64(0,0);
h = new Int64(0,0);
//Temporary variables not specified by the document
s0 = new Int64(0,0);
s1 = new Int64(0,0);
Ch = new Int64(0,0);
Maj = new Int64(0,0);
r1 = new Int64(0,0);
r2 = new Int64(0,0);
r3 = new Int64(0,0);
W = new Array(80);
for(i=0;i<80;i++){
W[i] = new Int64(0,0);
}
// append padding to the source string. The format is described in the FIPS.
x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
x[((len + 128 >> 10)<< 5) + 31] = len;
for(i=0,l=x.length;i<l;i+=32){ //32 dwords is the block size
int64copy(a,H[0]);
int64copy(b,H[1]);
int64copy(c,H[2]);
int64copy(d,H[3]);
int64copy(e,H[4]);
int64copy(f,H[5]);
int64copy(g,H[6]);
int64copy(h,H[7]);
for(j=0;j<16;j++){
W[j].h = x[i + 2*j];
W[j].l = x[i + 2*j + 1];
}
for(j=16;j<80;j++){
//sigma1
int64rrot(r1, W[j-2], 19);
int64revrrot(r2, W[j-2], 29);
int64shr(r3, W[j-2], 6);
s1.l = r1.l ^ r2.l ^ r3.l;
s1.h = r1.h ^ r2.h ^ r3.h;
//sigma0
int64rrot(r1, W[j-15], 1);
int64rrot(r2, W[j-15], 8);
int64shr(r3, W[j-15], 7);
s0.l = r1.l ^ r2.l ^ r3.l;
s0.h = r1.h ^ r2.h ^ r3.h;
int64add4(W[j], s1, W[j-7], s0, W[j-16]);
}
for(j=0;j<80;j++){
//Ch
Ch.l = (e.l & f.l) ^ (~e.l & g.l);
Ch.h = (e.h & f.h) ^ (~e.h & g.h);
//Sigma1
int64rrot(r1, e, 14);
int64rrot(r2, e, 18);
int64revrrot(r3, e, 9);
s1.l = r1.l ^ r2.l ^ r3.l;
s1.h = r1.h ^ r2.h ^ r3.h;
//Sigma0
int64rrot(r1, a, 28);
int64revrrot(r2, a, 2);
int64revrrot(r3, a, 7);
s0.l = r1.l ^ r2.l ^ r3.l;
s0.h = r1.h ^ r2.h ^ r3.h;
//Maj
Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
int64add(T2, s0, Maj);
int64copy(h, g);
int64copy(g, f);
int64copy(f, e);
int64add(e, d, T1);
int64copy(d, c);
int64copy(c, b);
int64copy(b, a);
int64add(a, T1, T2);
}
int64add(H[0], H[0], a);
int64add(H[1], H[1], b);
int64add(H[2], H[2], c);
int64add(H[3], H[3], d);
int64add(H[4], H[4], e);
int64add(H[5], H[5], f);
int64add(H[6], H[6], g);
int64add(H[7], H[7], h);
}
//represent the hash as an array of 32-bit dwords
hash = new Array(16);
for(i=0; i<8; i++){
hash[2*i] = H[i].h;
hash[2*i + 1] = H[i].l;
}
return hash;
};
/*
* Convert a raw string to an array of big-endian words
* Characters >255 have their high-byte silently ignored.
*/
rstr2binb = function(input){
var i,l,output = new Array(input.length >> 2);
for(i=0,l=output.length;i<l;i++){
output[i] = 0;
}
for(i=0,l=input.length*8;i<l;i+=8){
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
}
return output;
};
/*
* A constructor for 64-bit numbers
*/
Int64 = function(h,l){
this.h = h;
this.l = l;
};
/*
* Copies src into dst, assuming both are 64-bit numbers
*/
int64copy = function(dst,src){
dst.h = src.h;
dst.l = src.l;
};
/*
* Right-rotates a 64-bit number by shift
* Won't handle cases of shift>=32
* The revrrot() is for that
*/
int64rrot = function(dst,x,shift){
dst.l = (x.l >>> shift) | (x.h << (32-shift));
dst.h = (x.h >>> shift) | (x.l << (32-shift));
};
/*
* Reverses the dwords of the source and then rotates right by shift.
* This is equivalent to rotation by 32+shift
*/
int64revrrot = function(dst,x,shift){
dst.l = (x.h >>> shift) | (x.l << (32-shift));
dst.h = (x.l >>> shift) | (x.h << (32-shift));
};
/*
* Bitwise-shifts right a 64-bit number by shift
* Won't handle shift>=32, but it's never needed in SHA512
*/
int64shr = function(dst,x,shift){
dst.l = (x.l >>> shift) | (x.h << (32-shift));
dst.h = (x.h >>> shift);
};
/*
* Adds two 64-bit numbers
* Like the original implementation, does not rely on 32-bit operations
*/
int64add = function(dst, x, y){
var w0 = (x.l & 0xffff) + (y.l & 0xffff),
w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16),
w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16),
w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
dst.l = (w0 & 0xffff) | (w1 << 16);
dst.h = (w2 & 0xffff) | (w3 << 16);
};
/*
* Same, except with 4 addends. Works faster than adding them one by one.
*/
int64add4 = function(dst, a, b, c, d){
var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff),
w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16),
w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16),
w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
dst.l = (w0 & 0xffff) | (w1 << 16);
dst.h = (w2 & 0xffff) | (w3 << 16);
};
/*
* Same, except with 5 addends
*/
int64add5 = function(dst, a, b, c, d, e){
var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
dst.l = (w0 & 0xffff) | (w1 << 16);
dst.h = (w2 & 0xffff) | (w3 << 16);
};
window[ns] = $;
})('sha512');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment