From 1034e9d69e8e1e948a41ff43593a4d770e1f62d8 Mon Sep 17 00:00:00 2001 From: Chen Yi-Cyuan Date: Sun, 5 Jan 2014 11:01:00 +0800 Subject: [PATCH] create project --- CHANGELOG.md | 3 + README.md | 97 ++++++++++++++++++++++++ package.json | 28 +++++++ src/sha256.js | 184 +++++++++++++++++++++++++++++++++++++++++++++ tests/debug.js | 12 +++ tests/index.html | 12 +++ tests/node-test.js | 7 ++ tests/test.js | 6 ++ 8 files changed, 349 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 package.json create mode 100644 src/sha256.js create mode 100644 tests/debug.js create mode 100644 tests/index.html create mode 100644 tests/node-test.js create mode 100644 tests/test.js diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..11b3c13 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# v0.1.0 / 2014-01-05 + +Initial release diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8345bc --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# js-sha256 +This is a simple SHA-256 / SHA-224 hash function for JavaScript supports UTF-8 encoding. + +## Install +For node.js, you can use this command to install: + + npm install js-sha256 + +## Usage +If you use node.js, you should require the module first: +```JavaScript +sha256 = require('js-sha256'); +``` +or +```JavaScript +sha256 = require('js-sha256').sha256; +sha224 = require('js-sha256').sha224; +``` +And you could use like this: +```JavaScript +sha256('Message to hash'); +sha224('Message to hash'); +``` +## Example +Code +```JavaScript +sha256(''); +sha256('The quick brown fox jumps over the lazy dog'); +sha256('The quick brown fox jumps over the lazy dog.'); +sha224(''); +sha224('The quick brown fox jumps over the lazy dog'); +sha224('The quick brown fox jumps over the lazy dog.'); +``` +Output + + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 + ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c + d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f + 730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525 + 619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4c + +It also support UTF-8 encoding: + +Code +```JavaScript +sha256('中文'); +sha224('中文'); +``` +Output + + 72726d8818f693066ceb69afa364218b692e62ea92b385782363780f47529c21 + dfbab71afdf54388af4d55f8bd3de8c9b15e0eb916bf9125f4a959d4 + +## Tests +You can open `tests/index.html` in browser or use node.js to run test + + node tests/node-test.js + +or + + npm test + +## Extensions +### jQuery +If you prefer jQuery style, you can add following code to add a jQuery extension. + +Code +```JavaScript +jQuery.sha256 = sha256 +jQuery.sha224 = sha224 +``` +And then you could use like this: +```JavaScript +$.sha256('message'); +$.sha224('message'); +``` +### Prototype +If you prefer prototype style, you can add following code to add a prototype extension. + +Code +```JavaScript +String.prototype.sha256 = function() { + return sha256(this); +}; +String.prototype.sha224 = function() { + return sha224(this); +}; +``` +And then you could use like this: +```JavaScript +'message'.sha256(); +'message'.sha224(); +``` +## Contact +The project's website is located at https://github.com/emn178/js-sha256 +Author: emn178@gmail.com diff --git a/package.json b/package.json new file mode 100644 index 0000000..930841d --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "js-sha256", + "version": "0.1.0", + "description": "A simple SHA-256 / SHA-224 hash function for JavaScript supports UTF-8 encoding.", + "main": "src/sha256.js", + "scripts": { + "test": "node tests/node-test.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/emn178/js-sha256.git" + }, + "keywords": [ + "sha", + "sha2", + "sha224", + "sha256", + "hash", + "encryption", + "cryptography", + "HMAC" + ], + "author": "emn178 ", + "homepage": "https://github.com/emn178/js-sha256", + "bugs": { + "url": "https://github.com/emn178/js-sha256/issues" + } +} diff --git a/src/sha256.js b/src/sha256.js new file mode 100644 index 0000000..6427746 --- /dev/null +++ b/src/sha256.js @@ -0,0 +1,184 @@ +(function(root, undefined){ + 'use strict'; + + 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 + }; + + var 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 = function(message) { + return sha2(message, true); + }; + + var sha224 = function(message) { + return sha2(message, false); + }; + + var sha2 = function(message, is256) { + if(is256 === undefined) + is256 = true; + + var blocks = hasUTF8(message) ? UTF8toBlocks(message) : ASCIItoBlocks(message); + if(is256) + { + var h0 = 0x6a09e667; + var h1 = 0xbb67ae85; + var h2 = 0x3c6ef372; + var h3 = 0xa54ff53a; + var h4 = 0x510e527f; + var h5 = 0x9b05688c; + var h6 = 0x1f83d9ab; + var h7 = 0x5be0cd19; + } + else // 224 + { + var h0 = 0xc1059ed8; + var h1 = 0x367cd507; + var h2 = 0x3070dd17; + var h3 = 0xf70e5939; + var h4 = 0xffc00b31; + var h5 = 0x68581511; + var h6 = 0x64f98fa7; + var h7 = 0xbefa4fa4; + } + + for(var i = 0, length = blocks.length;i < length;i += 16) + { + var w = [], s0, s1; + for(var j = 0;j < 16;++j) + w[j] = blocks[i + j]; + for(var j = 16;j < 64;++j) + { + s0 = rightrotate(w[j - 15], 7) ^ rightrotate(w[j - 15], 18) ^ (w[j - 15] >>> 3); + s1 = rightrotate(w[j - 2], 17) ^ rightrotate(w[j - 2], 19) ^ (w[j - 2] >>> 10); + w[j] = w[j - 16] + s0 + w[j - 7] + s1; + } + + var a = h0; + var b = h1; + var c = h2; + var d = h3; + var e = h4; + var f = h5; + var g = h6; + var h = h7; + var maj, t1, t2, ch; + + for(var j = 0;j < 64;++j) + { + s0 = rightrotate(a, 2) ^ rightrotate(a, 13) ^ rightrotate(a, 22); + maj = (a & b) ^ (a & c) ^ (b & c); + t2 = s0 + maj; + s1 = rightrotate(e, 6) ^ rightrotate(e, 11) ^ rightrotate(e, 25); + ch = (e & f) ^ ((~ e) & g); + t1 = (h + s1 + ch + K[j] + w[j]) & 0xffffffff; + + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + h5 += f; + h6 += g; + h7 += h; + } + + var hex = toHexString(h0) + toHexString(h1)+ toHexString(h2) + toHexString(h3) + toHexString(h4) + toHexString(h5) + toHexString(h6); + if(is256) + hex += toHexString(h7); + return hex; + }; + + var rightrotate = 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; + }; + + if(typeof(module) != 'undefined') + { + sha256.sha256 = sha256; + sha256.sha224 = sha224; + module.exports = sha256; + } + else if(root) + { + root.sha256 = sha256; + root.sha224 = sha224; + } +}(this)); diff --git a/tests/debug.js b/tests/debug.js new file mode 100644 index 0000000..23900bf --- /dev/null +++ b/tests/debug.js @@ -0,0 +1,12 @@ +(function(root) { + var assert = function (title, expect, actual) { + if(expect == actual) + console.log(title + ': true'); + else + console.log(title + ': false', 'Except:' + expect, 'Actual: ' + actual); + }; + if(typeof(module) != 'undefined') + global.assert = assert; + else if(root) + root.assert = assert; +})(this); diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..43797c4 --- /dev/null +++ b/tests/index.html @@ -0,0 +1,12 @@ + + + + + SHA256 + + + + + + + diff --git a/tests/node-test.js b/tests/node-test.js new file mode 100644 index 0000000..133ff5a --- /dev/null +++ b/tests/node-test.js @@ -0,0 +1,7 @@ +// this also works: +// sha256 = require('../src/sha256.js'); + +sha256 = require('../src/sha256.js').sha256; +sha224 = require('../src/sha256.js').sha224; +require('./debug.js'); +require('./test.js'); diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 0000000..975796f --- /dev/null +++ b/tests/test.js @@ -0,0 +1,6 @@ +assert('sha256 1', 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256('')); +assert('sha256 2', 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592', sha256('The quick brown fox jumps over the lazy dog')); +assert('sha256 3', 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c', sha256('The quick brown fox jumps over the lazy dog.')); +assert('sha224 1', 'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', sha224('')); +assert('sha224 2', '730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525', sha224('The quick brown fox jumps over the lazy dog')); +assert('sha224 3', '619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4c', sha224('The quick brown fox jumps over the lazy dog.'));