commit 9d80e2d7f01a1eb45629835048cfb258f93ca3e1 Author: Chen Yi-Cyuan Date: Sat Jan 4 10:47:37 2014 +0800 Create project diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdd4853 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# js-sha1 +This is a simple SHA1 hash function for JavaScript supports UTF-8 encoding. + +## Usage + sha1('Message to hash'); + +## Example +Code + + sha1(''); + sha1('The quick brown fox jumps over the lazy dog'); + sha1('The quick brown fox jumps over the lazy dog.'); +Output + + da39a3ee5e6b4b0d3255bfef95601890afd80709 + 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 + 408d94384216f890ff7a0c3528e8bed1e0b01621 + +It also support UTF-8 encoding: + +Code + + sha1('中文'); +Output + + 7be2d2d20c106eee0836c9bc2b939890a78e8fb3 + +## Run Tests +You can open `tests/index.html` in browser or use node.js to run `node tests/node-test.js` for test. + +## Extensions +### jQuery +If you prefer jQuery style, you can add following code to add a jQuery extension. + +Code + + jQuery.sha1 = sha1 +And then you could use like this: + + $.sha1('message'); +### Prototype +If you prefer prototype style, you can add following code to add a prototype extension. + +Code + + String.prototype.sha1 = function() { + return sha1(this); + }; +And then you could use like this: + + 'message'.sha1(); diff --git a/build/sha1.min.js b/build/sha1.min.js new file mode 100644 index 0000000..41a5dd4 --- /dev/null +++ b/build/sha1.min.js @@ -0,0 +1,3 @@ +(function(w,x){var t="0123456789abcdef".split(""),v={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:11,c:12,d:13,e:14,f:15,A:10,B:11,C:12,D:13,E:14,F:15};w.sha1=function(e){var a;a:{for(a=e.length;a--;)if(255>2]=37==r?e[a>>2]|(v[c.charAt(++d)]<<4|v[c.charAt(++d)])<<(3-a%4<<3):e[a>>2]|r<<(3-a%4<<3);++a}c=(a+8>>6)+1<<4;d=a>>2;e[d]|=128<<(3-a%4<<3);for(d+=1;d>6)+1<<4;c=[];for(f=0;f>2]|=e.charCodeAt(f)<<(3-f%4<<3);c[f>>2]|=128<<(3-f%4<<3);c[d-1]=a<<3;e=c}a=1732584193;for(var d=4023233417,c=2562383102,f=271733878,r=3285377520,u=0,t=e.length;ub;++b)n[b]=e[u+b];for(b=16;80>b;++b)n[b]=p(n[b-3]^n[b-8]^n[b-14]^n[b-16],1);for(var m=a,h=d,k=c,l=f,q=r,g,b=0;20>b;++b)g=h&k|~h&l,g=p(m,5)+g+q+1518500249+n[b],q=l,l=k,k=p(h,30),h=m,m=g;for(;40>b;++b)g=h^k^l,g=p(m,5)+ +g+q+1859775393+n[b],q=l,l=k,k=p(h,30),h=m,m=g;for(;60>b;++b)g=h&k|h&l|k&l,g=p(m,5)+g+q+2400959708+n[b],q=l,l=k,k=p(h,30),h=m,m=g;for(;80>b;++b)g=h^k^l,g=p(m,5)+g+q+3395469782+n[b],q=l,l=k,k=p(h,30),h=m,m=g;a+=m;d+=h;c+=k;f+=l;r+=q}return s(a)+s(d)+s(c)+s(f)+s(r)};var p=function(e,a){return e<>>32-a},s=function(e){for(var a="",c=0;4>c;c++)var d=3-c<<3,a=a+(t[e>>d+4&15]+t[e>>d&15]);return a}})(window); diff --git a/src/sha1.js b/src/sha1.js new file mode 100644 index 0000000..019d477 --- /dev/null +++ b/src/sha1.js @@ -0,0 +1,149 @@ +(function(window, undefined){ + var HEX_CHARS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + var HEX_TABLE = { + '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, + 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15, + 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15 + }; + + window.sha1 = function(message) { + var blocks = hasUTF8(message) ? UTF8toBlocks(message) : ASCIItoBlocks(message); + var h0 = 0x67452301; + var h1 = 0xEFCDAB89; + var h2 = 0x98BADCFE; + var h3 = 0x10325476; + var h4 = 0xC3D2E1F0; + + for(var i = 0, length = blocks.length;i < length;i += 16) + { + var w = []; + for(var j = 0;j < 16;++j) + w[j] = blocks[i + j]; + for(var j = 16;j < 80;++j) + { + var x = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16]; + w[j] = leftrotate(x, 1); + } + + var a = h0; + var b = h1; + var c = h2; + var d = h3; + var e = h4; + var f, k, tmp; + + for(var j = 0;j < 20;++j) + { + f = (b & c) | ((~b) & d); + tmp = leftrotate(a, 5) + f + e + 0x5A827999 + w[j]; + e = d; + d = c; + c = leftrotate(b, 30); + b = a; + a = tmp; + } + + for(;j < 40;++j) + { + f = b ^ c ^ d; + tmp = leftrotate(a, 5) + f + e + 0x6ED9EBA1 + w[j]; + e = d; + d = c; + c = leftrotate(b, 30); + b = a; + a = tmp; + } + + // k = 0x8F1BBCDC; + for(;j < 60;++j) + { + f = (b & c) | (b & d) | (c & d); + tmp = leftrotate(a, 5) + f + e + 0x8F1BBCDC + w[j]; + e = d; + d = c; + c = leftrotate(b, 30); + b = a; + a = tmp; + } + + for(;j < 80;++j) + { + f = b ^ c ^ d; + tmp = leftrotate(a, 5) + f + e + 0xCA62C1D6 + w[j]; + e = d; + d = c; + c = leftrotate(b, 30); + b = a; + a = tmp; + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + } + + return toHexString(h0) + toHexString(h1)+ toHexString(h2) + toHexString(h3) + toHexString(h4); + }; + + var leftrotate = function(x, c) { + return (x << c) | (x >>> (32 - c)); + }; + + var toHexString = function(num) { + var hex = ""; + for(var i = 0; i < 4; i++) + { + var offset = 3 - i << 3; + hex += HEX_CHARS[(num >> (offset + 4)) & 0x0F] + HEX_CHARS[(num >> offset) & 0x0F]; + } + return hex; + }; + + var hasUTF8 = function(message) { + var i = message.length; + while(i--) + if(message.charCodeAt(i) > 255) + return true; + return false; + }; + + var ASCIItoBlocks = function(message) { + // a block is 32 bits(4 bytes), a chunk is 512 bits(64 bytes) + var length = message.length; + var chunkCount = ((length + 8) >> 6) + 1; + var blockCount = chunkCount << 4; // chunkCount * 16 + var blocks = []; + var i; + for(i = 0;i < blockCount;++i) + blocks[i] = 0; + for(i = 0;i < length;++i) + blocks[i >> 2] |= message.charCodeAt(i) << (3 - (i % 4) << 3); + blocks[i >> 2] |= 0x80 << (3 - (i % 4) << 3); + blocks[blockCount - 1] = length << 3; // length * 8 + return blocks; + }; + + var UTF8toBlocks = function(message) { + var uri = encodeURIComponent(message); + var blocks = []; + for(var i = 0, bytes = 0, length = uri.length;i < length;++i) + { + var c = uri.charCodeAt(i); + if(c == 37) // % + blocks[bytes >> 2] |= ((HEX_TABLE[uri.charAt(++i)] << 4) | HEX_TABLE[uri.charAt(++i)]) << (3 - (bytes % 4) << 3); + else + blocks[bytes >> 2] |= c << (3 - (bytes % 4) << 3); + ++bytes; + } + var chunkCount = ((bytes + 8) >> 6) + 1; + var blockCount = chunkCount << 4; // chunkCount * 16 + var index = bytes >> 2; + blocks[index] |= 0x80 << (3 - (bytes % 4) << 3); + for(var i = index + 1;i < blockCount;++i) + blocks[i] = 0; + blocks[blockCount - 1] = bytes << 3; // bytes * 8 + return blocks; + }; +}(window)); diff --git a/tests/debug.js b/tests/debug.js new file mode 100644 index 0000000..a9460b7 --- /dev/null +++ b/tests/debug.js @@ -0,0 +1,35 @@ +(function(window){ + //console.time implementation for IE + if(window.console && typeof(window.console.time) == "undefined") { + console.time = function(name, reset){ + if(!name) { return; } + var time = new Date().getTime(); + if(!console.timeCounters) { console.timeCounters = {} }; + var key = "KEY" + name.toString(); + if(!reset && console.timeCounters[key]) { return; } + console.timeCounters[key] = time; + }; + + console.timeEnd = function(name){ + var time = new Date().getTime(); + if(!console.timeCounters) { return; } + var key = "KEY" + name.toString(); + var timeCounter = console.timeCounters[key]; + if(timeCounter) { + var diff = time - timeCounter; + var label = name + ": " + diff + "ms"; + console.info(label); + delete console.timeCounters[key]; + } + return diff; + }; + } + + var assert = function (title, expect, actual) { + if(expect == actual) + console.log(title + ': true'); + else + console.log(title + ': false', 'Except:' + expect, 'Actual: ' + actual); + }; + window.assert = assert; +})(window); diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..f05a0d7 --- /dev/null +++ b/tests/index.html @@ -0,0 +1,12 @@ + + + + + SHA1 + + + + + + + diff --git a/tests/node-test.js b/tests/node-test.js new file mode 100644 index 0000000..b3fd5e4 --- /dev/null +++ b/tests/node-test.js @@ -0,0 +1,4 @@ +window = global; +require('../src/sha1.js'); +require('./debug.js'); +require('./test.js'); diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 0000000..4fb7e06 --- /dev/null +++ b/tests/test.js @@ -0,0 +1,3 @@ +assert('sha1 1', 'da39a3ee5e6b4b0d3255bfef95601890afd80709', sha1('')); +assert('sha1 2', '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12', sha1('The quick brown fox jumps over the lazy dog')); +assert('sha1 3', '408d94384216f890ff7a0c3528e8bed1e0b01621', sha1('The quick brown fox jumps over the lazy dog.'));