Skip to content

Instantly share code, notes, and snippets.

@hswolff
Last active January 2, 2016 15:19
Show Gist options
  • Save hswolff/8322978 to your computer and use it in GitHub Desktop.
Save hswolff/8322978 to your computer and use it in GitHub Desktop.
sha_fun
// http://www.movable-type.co.uk/scripts/sha1.html
// based off http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
// minified size: 1320 bytes
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-1 implementation in JavaScript | (c) Chris Veness 2002-2013 | www.movable-type.co.uk */
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var Sha1 = {}; // Sha1 namespace
/**
* Generates SHA-1 hash of string
*
* @param {String} msg String to be hashed
* @param {Boolean} [utf8encode=true] Encode msg as UTF-8 before generating hash
* @returns {String} Hash of msg as hex character string
*/
Sha1.hash = function(msg, utf8encode) {
utf8encode = (typeof utf8encode == 'undefined') ? true : utf8encode;
// convert string to UTF-8, as SHA only deals with byte-streams
if (utf8encode) msg = Utf8.encode(msg);
// constants [§4.2.1]
var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
// PREPROCESSING
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
var M = new Array(N);
for (var i=0; i<N; i++) {
M[i] = new Array(16);
for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
(msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
}
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14])
M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;
// set initial hash value [§5.3.1]
var H0 = 0x67452301;
var H1 = 0xefcdab89;
var H2 = 0x98badcfe;
var H3 = 0x10325476;
var H4 = 0xc3d2e1f0;
// HASH COMPUTATION [§6.1.2]
var W = new Array(80); var a, b, c, d, e;
for (var i=0; i<N; i++) {
// 1 - prepare message schedule 'W'
for (var t=0; t<16; t++) W[t] = M[i][t];
for (var t=16; t<80; t++) W[t] = Sha1.ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
// 2 - initialise five working variables a, b, c, d, e with previous hash value
a = H0; b = H1; c = H2; d = H3; e = H4;
// 3 - main loop
for (var t=0; t<80; t++) {
var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants
var T = (Sha1.ROTL(a,5) + Sha1.f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff;
e = d;
d = c;
c = Sha1.ROTL(b, 30);
b = a;
a = T;
}
// 4 - compute the new intermediate hash value
H0 = (H0+a) & 0xffffffff; // note 'addition modulo 2^32'
H1 = (H1+b) & 0xffffffff;
H2 = (H2+c) & 0xffffffff;
H3 = (H3+d) & 0xffffffff;
H4 = (H4+e) & 0xffffffff;
}
return Sha1.toHexStr(H0) + Sha1.toHexStr(H1) +
Sha1.toHexStr(H2) + Sha1.toHexStr(H3) + Sha1.toHexStr(H4);
}
//
// function 'f' [§4.1.1]
//
Sha1.f = function(s, x, y, z) {
switch (s) {
case 0: return (x & y) ^ (~x & z); // Ch()
case 1: return x ^ y ^ z; // Parity()
case 2: return (x & y) ^ (x & z) ^ (y & z); // Maj()
case 3: return x ^ y ^ z; // Parity()
}
}
//
// rotate left (circular left shift) value x by n positions [§3.2.5]
//
Sha1.ROTL = function(x, n) {
return (x<<n) | (x>>>(32-n));
}
//
// hexadecimal representation of a number
// (note toString(16) is implementation-dependant, and
// in IE returns signed numbers when used on full words)
//
Sha1.toHexStr = function(n) {
var s="", v;
for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
return s;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Utf8 class: encode / decode between multi-byte Unicode characters and UTF-8 multiple */
/* single-byte character encoding (c) Chris Veness 2002-2013 */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var Utf8 = {}; // Utf8 namespace
/**
* Encode multi-byte Unicode string into utf-8 multiple single-byte characters
* (BMP / basic multilingual plane only)
*
* Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
*
* @param {String} strUni Unicode string to be encoded as UTF-8
* @returns {String} encoded string
*/
Utf8.encode = function(strUni) {
// use regular expressions & String.replace callback function for better efficiency
// than procedural approaches
var strUtf = strUni.replace(
/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
);
strUtf = strUtf.replace(
/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
);
return strUtf;
}
/**
* Decode utf-8 encoded string back into multi-byte Unicode characters
*
* @param {String} strUtf UTF-8 string to be decoded back to Unicode
* @returns {String} decoded string
*/
Utf8.decode = function(strUtf) {
// note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
var strUni = strUtf.replace(
/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
function(c) { // (note parentheses for precence)
var cc = ((c.charCodeAt(0)&0x0f)<<12) | ((c.charCodeAt(1)&0x3f)<<6) | ( c.charCodeAt(2)&0x3f);
return String.fromCharCode(cc); }
);
strUni = strUni.replace(
/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
function(c) { // (note parentheses for precence)
var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
return String.fromCharCode(cc); }
);
return strUni;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
module.exports = Sha1;
var crypto = require('crypto'),
shasum = crypto.createHash('sha1');
var shaInput = "The quick brown fox jumps over the lazy dog";
var expectedHash = '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12';
function testHash(input) {
console.log('hash',input);
console.log('equal?', input === expectedHash);
console.log('');
}
shasum.update(shaInput);
testHash(shasum.digest('hex'));
// http://www.webtoolkit.info/javascript-sha1.html#.UssA72RDtGc
/**
*
* Secure Hash Algorithm (SHA1)
* http://www.webtoolkit.info/
*
**/
function SHA1 (msg) {
function rotate_left(n,s) {
var t4 = ( n<<s ) | (n>>>(32-s));
return t4;
}
function lsb_hex(val) {
var str="";
var i;
var vh;
var vl;
for( i=0; i<=6; i+=2 ) {
vh = (val>>>(i*4+4))&0x0f;
vl = (val>>>(i*4))&0x0f;
str += vh.toString(16) + vl.toString(16);
}
return str;
}
function cvt_hex(val) {
var str="";
var i;
var v;
for( i=7; i>=0; i-- ) {
v = (val>>>(i*4))&0x0f;
str += v.toString(16);
}
return str;
}
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 blockstart;
var i, j;
var W = new Array(80);
var H0 = 0x67452301;
var H1 = 0xEFCDAB89;
var H2 = 0x98BADCFE;
var H3 = 0x10325476;
var H4 = 0xC3D2E1F0;
var A, B, C, D, E;
var temp;
msg = Utf8Encode(msg);
var msg_len = msg.length;
var word_array = new Array();
for( i=0; i<msg_len-3; i+=4 ) {
j = msg.charCodeAt(i)<<24 | msg.charCodeAt(i+1)<<16 |
msg.charCodeAt(i+2)<<8 | msg.charCodeAt(i+3);
word_array.push( j );
}
switch( msg_len % 4 ) {
case 0:
i = 0x080000000;
break;
case 1:
i = msg.charCodeAt(msg_len-1)<<24 | 0x0800000;
break;
case 2:
i = msg.charCodeAt(msg_len-2)<<24 | msg.charCodeAt(msg_len-1)<<16 | 0x08000;
break;
case 3:
i = msg.charCodeAt(msg_len-3)<<24 | msg.charCodeAt(msg_len-2)<<16 | msg.charCodeAt(msg_len-1)<<8 | 0x80;
break;
}
word_array.push( i );
while( (word_array.length % 16) != 14 ) word_array.push( 0 );
word_array.push( msg_len>>>29 );
word_array.push( (msg_len<<3)&0x0ffffffff );
for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {
for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i];
for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
A = H0;
B = H1;
C = H2;
D = H3;
E = H4;
for( i= 0; i<=19; i++ ) {
temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
E = D;
D = C;
C = rotate_left(B,30);
B = A;
A = temp;
}
for( i=20; i<=39; i++ ) {
temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
E = D;
D = C;
C = rotate_left(B,30);
B = A;
A = temp;
}
for( i=40; i<=59; i++ ) {
temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
E = D;
D = C;
C = rotate_left(B,30);
B = A;
A = temp;
}
for( i=60; i<=79; i++ ) {
temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
E = D;
D = C;
C = rotate_left(B,30);
B = A;
A = temp;
}
H0 = (H0 + A) & 0x0ffffffff;
H1 = (H1 + B) & 0x0ffffffff;
H2 = (H2 + C) & 0x0ffffffff;
H3 = (H3 + D) & 0x0ffffffff;
H4 = (H4 + E) & 0x0ffffffff;
}
var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
return temp.toLowerCase();
}
testHash(SHA1(shaInput));
// 1677 bytes
function SHA1small(a){function b(a,b){var c=a<<b|a>>>32-b;return c}function d(a){var c,d,b="";for(c=7;c>=0;c--)d=15&a>>>4*c,b+=d.toString(16);return b}function e(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);128>d?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(192|d>>6),b+=String.fromCharCode(128|63&d)):(b+=String.fromCharCode(224|d>>12),b+=String.fromCharCode(128|63&d>>6),b+=String.fromCharCode(128|63&d))}return b}var f,g,h,o,p,q,r,s,t,i=new Array(80),j=1732584193,k=4023233417,l=2562383102,m=271733878,n=3285377520;a=e(a);var u=a.length,v=new Array;for(g=0;u-3>g;g+=4)h=a.charCodeAt(g)<<24|a.charCodeAt(g+1)<<16|a.charCodeAt(g+2)<<8|a.charCodeAt(g+3),v.push(h);switch(u%4){case 0:g=2147483648;break;case 1:g=8388608|a.charCodeAt(u-1)<<24;break;case 2:g=32768|(a.charCodeAt(u-2)<<24|a.charCodeAt(u-1)<<16);break;case 3:g=128|(a.charCodeAt(u-3)<<24|a.charCodeAt(u-2)<<16|a.charCodeAt(u-1)<<8)}for(v.push(g);14!=v.length%16;)v.push(0);for(v.push(u>>>29),v.push(4294967295&u<<3),f=0;f<v.length;f+=16){for(g=0;16>g;g++)i[g]=v[f+g];for(g=16;79>=g;g++)i[g]=b(i[g-3]^i[g-8]^i[g-14]^i[g-16],1);for(o=j,p=k,q=l,r=m,s=n,g=0;19>=g;g++)t=4294967295&b(o,5)+(p&q|~p&r)+s+i[g]+1518500249,s=r,r=q,q=b(p,30),p=o,o=t;for(g=20;39>=g;g++)t=4294967295&b(o,5)+(p^q^r)+s+i[g]+1859775393,s=r,r=q,q=b(p,30),p=o,o=t;for(g=40;59>=g;g++)t=4294967295&b(o,5)+(p&q|p&r|q&r)+s+i[g]+2400959708,s=r,r=q,q=b(p,30),p=o,o=t;for(g=60;79>=g;g++)t=4294967295&b(o,5)+(p^q^r)+s+i[g]+3395469782,s=r,r=q,q=b(p,30),p=o,o=t;j=4294967295&j+o,k=4294967295&k+p,l=4294967295&l+q,m=4294967295&m+r,n=4294967295&n+s}var t=d(j)+d(k)+d(l)+d(m)+d(n);return t.toLowerCase()}
testHash(SHA1small(shaInput));
// 1337 bytes
// uglified goes down to: 1264 bytes
// https://code.google.com/p/tiny-sha1/
function SHA1_2(s){function U(a,b,c){while(0<c--)a.push(b)}function L(a,b){return(a<<b)|(a>>>(32-b))}function P(a,b,c){return a^b^c}function A(a,b){var c=(b&0xFFFF)+(a&0xFFFF),d=(b>>>16)+(a>>>16)+(c>>>16);return((d&0xFFFF)<<16)|(c&0xFFFF)}var B="0123456789abcdef";return(function(a){var c=[],d=a.length*4,e;for(var i=0;i<d;i++){e=a[i>>2]>>((3-(i%4))*8);c.push(B.charAt((e>>4)&0xF)+B.charAt(e&0xF))}return c.join('')}((function(a,b){var c,d,e,f,g,h=a.length,v=0x67452301,w=0xefcdab89,x=0x98badcfe,y=0x10325476,z=0xc3d2e1f0,M=[];U(M,0x5a827999,20);U(M,0x6ed9eba1,20);U(M,0x8f1bbcdc,20);U(M,0xca62c1d6,20);a[b>>5]|=0x80<<(24-(b%32));a[(((b+65)>>9)<<4)+15]=b;for(var i=0;i<h;i+=16){c=v;d=w;e=x;f=y;g=z;for(var j=0,O=[];j<80;j++){O[j]=j<16?a[j+i]:L(O[j-3]^O[j-8]^O[j-14]^O[j-16],1);var k=(function(a,b,c,d,e){var f=(e&0xFFFF)+(a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF),g=(e>>>16)+(a>>>16)+(b>>>16)+(c>>>16)+(d>>>16)+(f>>>16);return((g&0xFFFF)<<16)|(f&0xFFFF)})(j<20?(function(t,a,b){return(t&a)^(~t&b)}(d,e,f)):j<40?P(d,e,f):j<60?(function(t,a,b){return(t&a)^(t&b)^(a&b)}(d,e,f)):P(d,e,f),g,M[j],O[j],L(c,5));g=f;f=e;e=L(d,30);d=c;c=k}v=A(v,c);w=A(w,d);x=A(x,e);y=A(y,f);z=A(z,g)}return[v,w,x,y,z]}((function(t){var a=[],b=255,c=t.length*8;for(var i=0;i<c;i+=8){a[i>>5]|=(t.charCodeAt(i/8)&b)<<(24-(i%32))}return a}(s)).slice(),s.length*8))))}
testHash(SHA1_2(shaInput));
// 1255 bytes
testHash(require('./sha_3').hash(shaInput, false));
(function() {
// bytes 1321
// http://phpjs.org/functions/sha1/
function sha1(r){var t,a,o,e,h,n,f,c,u,S=function(r,t){var a=r<<t|r>>>32-t
return a},i=function(r){var t,a,o=""
for(t=7;t>=0;t--)a=r>>>4*t&15,o+=a.toString(16)
return o},v=Array(80),A=1732584193,s=4023233417,C=2562383102,d=271733878,l=3285377520,g=r.length,H=[]
for(a=0;g-3>a;a+=4)o=r.charCodeAt(a)<<24|r.charCodeAt(a+1)<<16|r.charCodeAt(a+2)<<8|r.charCodeAt(a+3),H.push(o)
switch(g%4){case 0:a=2147483648
break
case 1:a=r.charCodeAt(g-1)<<24|8388608
break
case 2:a=r.charCodeAt(g-2)<<24|r.charCodeAt(g-1)<<16|32768
break
case 3:a=r.charCodeAt(g-3)<<24|r.charCodeAt(g-2)<<16|r.charCodeAt(g-1)<<8|128}for(H.push(a);H.length%16!=14;)H.push(0)
for(H.push(g>>>29),H.push(g<<3&4294967295),t=0;t<H.length;t+=16){for(a=0;16>a;a++)v[a]=H[t+a]
for(a=16;79>=a;a++)v[a]=S(v[a-3]^v[a-8]^v[a-14]^v[a-16],1)
for(e=A,h=s,n=C,f=d,c=l,a=0;19>=a;a++)u=S(e,5)+(h&n|~h&f)+c+v[a]+1518500249&4294967295,c=f,f=n,n=S(h,30),h=e,e=u
for(a=20;39>=a;a++)u=S(e,5)+(h^n^f)+c+v[a]+1859775393&4294967295,c=f,f=n,n=S(h,30),h=e,e=u
for(a=40;59>=a;a++)u=S(e,5)+(h&n|h&f|n&f)+c+v[a]+2400959708&4294967295,c=f,f=n,n=S(h,30),h=e,e=u
for(a=60;79>=a;a++)u=S(e,5)+(h^n^f)+c+v[a]+3395469782&4294967295,c=f,f=n,n=S(h,30),h=e,e=u
A=A+e&4294967295,s=s+h&4294967295,C=C+n&4294967295,d=d+f&4294967295,l=l+c&4294967295}return u=i(A)+i(s)+i(C)+i(d)+i(l),u.toLowerCase()}
testHash(sha1(shaInput));
})();
// another option, seems too big
// 4746 bytes
// https://github.com/Caligatio/jsSHA
console.log('mine');
testHash(require('./sha_3_mine').hash(shaInput));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment