diff --git a/lib/hash.js b/lib/hash.js index f02d570..3044074 100644 --- a/lib/hash.js +++ b/lib/hash.js @@ -10,6 +10,8 @@ Hash.sha256 = function(buf) { return new Buffer(hash); }; +Hash.sha256.blocksize = 512; + Hash.sha256sha256 = function(buf) { try { return Hash.sha256(Hash.sha256(buf)); @@ -39,3 +41,49 @@ Hash.sha512 = function(buf) { var hash = sha512(buf); return new Buffer(hash); }; + +Hash.sha512.blocksize = 1024; + +Hash.hmac = function(hashf, data, key) { + if (!Buffer.isBuffer(data) || !Buffer.isBuffer(key)) + throw new Error('hash: data and key must be buffers'); + + //http://en.wikipedia.org/wiki/Hash-based_message_authentication_code + //http://tools.ietf.org/html/rfc4868#section-2 + if (!hashf.blocksize) + throw new Error('hash: Blocksize for hash function unknown'); + + var blocksize = hashf.blocksize/8; + + if (key.length > blocksize) + key = hashf(key); + else if (key < blocksize) { + var fill = new Buffer(blocksize); + fill.fill(0); + key.copy(fill); + key = fill; + } + + var o_key = new Buffer(blocksize); + o_key.fill(0x5c); + + var i_key = new Buffer(blocksize); + i_key.fill(0x36); + + var o_key_pad = new Buffer(blocksize); + var i_key_pad = new Buffer(blocksize); + for (var i = 0; i < blocksize; i++) { + o_key_pad[i] = o_key[i] ^ key[i]; + i_key_pad[i] = i_key[i] ^ key[i]; + } + + return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); +}; + +Hash.sha256hmac = function(data, key) { + return Hash.hmac(Hash.sha256, data, key); +}; + +Hash.sha512hmac = function(data, key) { + return Hash.hmac(Hash.sha512, data, key); +}; diff --git a/test/test.hash.js b/test/test.hash.js index eea3517..2e8d010 100644 --- a/test/test.hash.js +++ b/test/test.hash.js @@ -20,6 +20,22 @@ describe('hash', function() { }); + describe('#sha256hmac', function() { + + it('should compute this known empty test vector correctly', function() { + var key = new Buffer(''); + var data = new Buffer(''); + Hash.sha256hmac(data, key).toString('hex').should.equal('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad'); + }); + + it('should compute this known non-empty test vector correctly', function() { + var key = new Buffer('key'); + var data = new Buffer('The quick brown fox jumps over the lazy dog'); + Hash.sha256hmac(data, key).toString('hex').should.equal('f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8'); + }); + + }); + describe('#sha256sha256', function() { it('should calculate the hash of this buffer correctly', function() { @@ -80,4 +96,20 @@ describe('hash', function() { }); + describe("#sha512hmac", function() { + + it('should calculate this known empty test vector correctly', function() { + var hex = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47'; + Hash.sha512hmac(new Buffer([]), new Buffer([])).toString('hex').should.equal(hex); + }); + + it('should calculate this known non-empty test vector correctly', function() { + var hex = 'c40bd7c15aa493b309c940e08a73ffbd28b2e4cb729eb94480d727e4df577b13cc403a78e6150d83595f3b17c4cc331f12ca5952691de3735a63c1d4c69a2bac'; + var data = new Buffer("test1"); + var key = new Buffer("test2"); + Hash.sha512hmac(data, key).toString('hex').should.equal(hex); + }); + + }); + });