[Pkg-javascript-commits] [node-hash.js] 01/29: initial

Bastien Roucariès rouca at moszumanska.debian.org
Thu Apr 20 19:30:36 UTC 2017


This is an automated email from the git hooks/post-receive script.

rouca pushed a commit to branch master
in repository node-hash.js.

commit 8596aa44e6c573a8631499c58ca6837e3a21c985
Author: Fedor Indutny <fedor at indutny.com>
Date:   Sat Apr 26 01:12:00 2014 +0400

    initial
---
 .gitignore        |   2 +
 .travis.yml       |   8 ++
 README.md         |  28 +++++++
 lib/hash.js       |  10 +++
 lib/hash/hash.js  | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/hash/hmac.js  |  47 ++++++++++++
 lib/hash/utils.js | 106 ++++++++++++++++++++++++++
 package.json      |  28 +++++++
 test/hash-test.js |  64 ++++++++++++++++
 test/hmac-test.js |  59 +++++++++++++++
 10 files changed, 574 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1ca9571
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules/
+npm-debug.log
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8fe40db
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"
+  - "0.11"
+branches:
+  only:
+    - master
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..63107cb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# hash.js [![Build Status](https://secure.travis-ci.org/indutny/hash.js.png)](http://travis-ci.org/indutny/hash.js)
+
+Just a bike-shed.
+
+#### LICENSE
+
+This software is licensed under the MIT License.
+
+Copyright Fedor Indutny, 2014.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lib/hash.js b/lib/hash.js
new file mode 100644
index 0000000..b2479f8
--- /dev/null
+++ b/lib/hash.js
@@ -0,0 +1,10 @@
+var hash = exports;
+
+hash.utils = require('./hash/utils');
+hash.hash = require('./hash/hash');
+hash.hmac = require('./hash/hmac');
+
+// Proxy hash functions to the main object
+Object.keys(hash.hash).forEach(function(name) {
+  hash[name] = hash.hash[name];
+});
diff --git a/lib/hash/hash.js b/lib/hash/hash.js
new file mode 100644
index 0000000..e616f88
--- /dev/null
+++ b/lib/hash/hash.js
@@ -0,0 +1,222 @@
+var assert = require('assert');
+var util = require('util');
+var hash = require('../hash');
+var utils = hash.utils;
+
+var sha256_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
+];
+
+function SHA256() {
+  if (!(this instanceof SHA256))
+    return new SHA256();
+
+  this.h = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+             0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ];
+  this.k = sha256_K;
+  this.pending = null;
+  this.pendingTotal = 0;
+
+  this.blockSize = this.constructor.blockSize;
+  this.outSize = this.constructor.outSize;
+  this.hmacStrength = this.constructor.hmacStrength;
+}
+exports.sha256 = SHA256;
+
+SHA256.blockSize = 512;
+SHA256.outSize = 256;
+SHA256.hmacStrength = 192;
+
+SHA256.prototype.update = function update(msg, enc) {
+  // Convert message to array, pad it, and join into 32bit blocks
+  msg = utils.toArray(msg, enc);
+  if (!this.pending)
+    this.pending = msg;
+  else
+    this.pending = this.pending.concat(msg);
+  this.pendingTotal += msg.length;
+
+  // Try updating
+  this._update();
+
+  return this;
+};
+
+SHA256.prototype._update = function _update() {
+  var msg = this.pending;
+  if (msg.length < this.blockSize / 8)
+    return;
+
+  // Process pending data in blocks
+  var r = msg.length % (this.blockSize / 8);
+  this.pending = msg.slice(msg.length - r, msg.length);
+  if (this.pending.length === 0)
+    this.pending = null;
+
+  msg = utils.join32(msg.slice(0, msg.length - r));
+  assert.equal(msg.length % 16, 0);
+
+  var W = new Array(64);
+  for (var off = 0; off < msg.length; off += 16) {
+    for (var i = 0; i < 16; i++)
+      W[i] = msg[i + off];
+    for (; i < W.length; i++)
+      W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]);
+
+    var a = this.h[0];
+    var b = this.h[1];
+    var c = this.h[2];
+    var d = this.h[3];
+    var e = this.h[4];
+    var f = this.h[5];
+    var g = this.h[6];
+    var h = this.h[7];
+
+    assert.equal(this.k.length, W.length);
+    for (var i = 0; i < W.length; i++) {
+      var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]);
+      var T2 = sum32(s0_256(a), maj32(a, b, c));
+      h = g;
+      g = f;
+      f = e;
+      e = sum32(d, T1);
+      d = c;
+      c = b;
+      b = a;
+      a = sum32(T1, T2);
+    }
+
+    this.h[0] = sum32(this.h[0], a);
+    this.h[1] = sum32(this.h[1], b);
+    this.h[2] = sum32(this.h[2], c);
+    this.h[3] = sum32(this.h[3], d);
+    this.h[4] = sum32(this.h[4], e);
+    this.h[5] = sum32(this.h[5], f);
+    this.h[6] = sum32(this.h[6], g);
+    this.h[7] = sum32(this.h[7], h);
+  }
+};
+
+SHA256.prototype.digest = function digest(enc) {
+  if (this.pending !== null)
+    this.update(pad(this.pendingTotal, this.blockSize / 8));
+  assert(this.pending === null);
+
+  return this._digest(enc);
+};
+
+SHA256.prototype._digest = function digest(enc) {
+  if (enc === 'hex')
+    return utils.toHex32(this.h);
+  else
+    return utils.split32(this.h);
+};
+
+function SHA224() {
+  if (!(this instanceof SHA224))
+    return new SHA224();
+
+  SHA256.call(this);
+  this.h = [ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+             0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ];
+}
+util.inherits(SHA224, SHA256);
+exports.sha224 = SHA224;
+
+SHA224.blockSize = 512;
+SHA224.outSize = 224;
+SHA224.hmacStrength = 192;
+
+SHA224.prototype._digest = function digest(enc) {
+  // Just truncate output
+  if (enc === 'hex')
+    return utils.toHex32(this.h.slice(0, 7));
+  else
+    return utils.split32(this.h.slice(0, 7));
+};
+
+function pad(len, bytes) {
+  var k = bytes - ((len + 8) % bytes);
+  var res = new Array(k + 8);
+  res[0] = 0x80;
+  for (var i = 1; i < k + 4; i++)
+    res[i] = 0;
+
+  // Append big-endian length
+  len <<= 3;
+  res[i++] = (len >>> 24) & 0xff;
+  res[i++] = (len >>> 16) & 0xff;
+  res[i++] = (len >>> 8) & 0xff;
+  res[i++] = len & 0xff;
+
+  return res;
+}
+
+
+function rotr32(w, b) {
+  return (w >>> b) | (w << (32 - b));
+}
+
+function rotl32(w, b) {
+  return (w << b) | (w >>> (32 - b));
+}
+
+function sum32(a, b) {
+  var r = (a + b) & 0xffffffff;
+  if (r < 0)
+    r += 0x100000000;
+  return r;
+}
+
+function sum32_4(a, b, c, d) {
+  var r = (a + b + c + d) & 0xffffffff;
+  if (r < 0)
+    r += 0x100000000;
+  return r;
+}
+
+function sum32_5(a, b, c, d, e) {
+  var r = (a + b + c + d + e) & 0xffffffff;
+  if (r < 0)
+    r += 0x100000000;
+  return r;
+}
+
+function ch32(x, y, z) {
+  return (x & y) ^ ((~x) & z);
+}
+
+function maj32(x, y, z) {
+  return (x & y) ^ (x & z) ^ (y & z);
+}
+
+function s0_256(x) {
+  return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22);
+}
+
+function s1_256(x) {
+  return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25);
+}
+
+function g0_256(x) {
+  return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3);
+}
+
+function g1_256(x) {
+  return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10);
+}
diff --git a/lib/hash/hmac.js b/lib/hash/hmac.js
new file mode 100644
index 0000000..ebffd3f
--- /dev/null
+++ b/lib/hash/hmac.js
@@ -0,0 +1,47 @@
+var hmac = exports;
+
+var assert = require('assert');
+var hash = require('../hash');
+var utils = hash.utils;
+
+function Hmac(hash, key, enc) {
+  if (!(this instanceof Hmac))
+    return new Hmac(hash, key, enc);
+  this.Hash = hash;
+  this.blockSize = hash.blockSize / 8;
+  this.outSize = hash.outSize / 8;
+  this._init(utils.toArray(key, enc));
+}
+module.exports = Hmac;
+
+Hmac.prototype._init = function init(key) {
+  // Shorten key, if needed
+  if (key.length > this.blockSize)
+    key = new this.Hash().update(key).digest();
+  assert(key.length <= this.blockSize);
+
+  // Add padding to key
+  for (var i = key.length; i < this.blockSize; i++)
+    key.push(0);
+
+  var okey = key.slice();
+  for (var i = 0; i < key.length; i++) {
+    key[i] ^= 0x36;
+    okey[i] ^= 0x5c;
+  }
+
+  this.hash = {
+    inner: new this.Hash().update(key),
+    outer: new this.Hash().update(okey)
+  };
+};
+
+Hmac.prototype.update = function update(msg, enc) {
+  this.hash.inner.update(msg, enc);
+  return this;
+};
+
+Hmac.prototype.digest = function digest(enc) {
+  this.hash.outer.update(this.hash.inner.digest());
+  return this.hash.outer.digest(enc);
+};
diff --git a/lib/hash/utils.js b/lib/hash/utils.js
new file mode 100644
index 0000000..bcf49f9
--- /dev/null
+++ b/lib/hash/utils.js
@@ -0,0 +1,106 @@
+var assert = require('assert');
+
+var utils = exports;
+
+function toArray(msg, enc) {
+  if (Array.isArray(msg))
+    return msg.slice();
+  if (!msg)
+    return [];
+  var res = [];
+  if (typeof msg === 'string') {
+    if (!enc) {
+      for (var i = 0; i < msg.length; i++) {
+        var c = msg.charCodeAt(i);
+        var hi = c >> 8;
+        var lo = c & 0xff;
+        if (hi)
+          res.push(hi, lo);
+        else
+          res.push(lo);
+      }
+    } else if (enc === 'hex') {
+      msg = msg.replace(/[^a-z0-9]+/ig, '');
+      if (msg.length % 2 != 0)
+        msg = '0' + msg;
+      for (var i = 0; i < msg.length; i += 2)
+        res.push(parseInt(msg[i] + msg[i + 1], 16));
+    }
+  } else {
+    for (var i = 0; i < msg.length; i++)
+      res[i] = msg[i] | 0;
+  }
+  return res;
+}
+utils.toArray = toArray;
+
+function toHex(msg) {
+  var res = '';
+  for (var i = 0; i < msg.length; i++)
+    res += zero2(msg[i].toString(16));
+  return res;
+}
+utils.toHex = toHex;
+
+function toHex32(msg) {
+  var res = '';
+  for (var i = 0; i < msg.length; i++)
+    res += zero8(msg[i].toString(16));
+  return res;
+}
+utils.toHex32 = toHex32;
+
+function zero2(word) {
+  if (word.length === 1)
+    return '0' + word;
+  else
+    return word;
+}
+utils.zero2 = zero2;
+
+function zero8(word) {
+  if (word.length === 7)
+    return '0' + word;
+  else if (word.length === 6)
+    return '00' + word;
+  else if (word.length === 5)
+    return '000' + word;
+  else if (word.length === 4)
+    return '0000' + word;
+  else if (word.length === 3)
+    return '00000' + word;
+  else if (word.length === 2)
+    return '000000' + word;
+  else if (word.length === 1)
+    return '0000000' + word;
+  else
+    return word;
+}
+utils.zero8 = zero8;
+
+function join32(msg) {
+  assert.equal(msg.length % 4, 0);
+  var res = new Array(msg.length / 4);
+  for (var i = 0, k = 0; i < res.length; i++, k += 4) {
+    var w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) |
+            msg[k + 3];
+    if (w < 0)
+      w += 0x100000000;
+    res[i] = w;
+  }
+  return res;
+}
+utils.join32 = join32;
+
+function split32(msg) {
+  var res = new Array(msg.length * 4);
+  for (var i = 0, k = 0; i < msg.length; i++, k += 4) {
+    var m = msg[i];
+    res[k] = m >>> 24;
+    res[k + 1] = (m >>> 16) & 0xff;
+    res[k + 2] = (m >>> 8) & 0xff;
+    res[k + 3] = m & 0xff;
+  }
+  return res;
+}
+utils.split32 = split32;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..756f85d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "hash.js",
+  "version": "0.0.0",
+  "description": "Various hash functions that could be run by both browser and node",
+  "main": "lib/hash.js",
+  "scripts": {
+    "test": "mocha --reporter=spec test/*-test.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git at github.com:indutny/hash.js"
+  },
+  "keywords": [
+    "hash",
+    "sha256",
+    "sha224",
+    "hmac"
+  ],
+  "author": "Fedor Indutny <fedor at indutny.com>",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/indutny/hash.js/issues"
+  },
+  "homepage": "https://github.com/indutny/hash.js",
+  "devDependencies": {
+    "mocha": "^1.18.2"
+  }
+}
diff --git a/test/hash-test.js b/test/hash-test.js
new file mode 100644
index 0000000..77da2a6
--- /dev/null
+++ b/test/hash-test.js
@@ -0,0 +1,64 @@
+var assert = require('assert');
+var hash = require('../');
+
+describe('Hash', function() {
+  it('should support sha256', function() {
+    assert.equal(hash.sha256.blockSize, 512);
+    assert.equal(hash.sha256.outSize, 256);
+
+    var test = [
+      [ 'abc',
+        'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' ],
+      [ 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
+        '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1' ],
+      [ 'deadbeef',
+        '5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953',
+        'hex' ],
+    ];
+    for (var i = 0; i < test.length; i++) {
+      var msg = test[i][0];
+      var res = test[i][1];
+      var enc = test[i][2];
+
+      var dgst = hash.sha256().update(msg, enc).digest('hex');
+      assert.equal(dgst, res);
+
+      // Split message
+      var dgst = hash.sha256()
+                     .update(msg.slice(0, 2), enc)
+                     .update(msg.slice(2), enc)
+                     .digest('hex');
+      assert.equal(dgst, res);
+    }
+  });
+
+  it('should support sha224', function() {
+    assert.equal(hash.sha224.blockSize, 512);
+    assert.equal(hash.sha224.outSize, 224);
+
+    var test = [
+      [ 'abc',
+        '23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7' ],
+      [ 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
+        '75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525' ],
+      [ 'deadbeef',
+        '55b9eee5f60cc362ddc07676f620372611e22272f60fdbec94f243f8',
+        'hex' ],
+    ];
+    for (var i = 0; i < test.length; i++) {
+      var msg = test[i][0];
+      var res = test[i][1];
+      var enc = test[i][2];
+
+      var dgst = hash.sha224().update(msg, enc).digest('hex');
+      assert.equal(dgst, res);
+
+      // Split message
+      var dgst = hash.sha224()
+                     .update(msg.slice(0, 2), enc)
+                     .update(msg.slice(2), enc)
+                     .digest('hex');
+      assert.equal(dgst, res);
+    }
+  });
+});
diff --git a/test/hmac-test.js b/test/hmac-test.js
new file mode 100644
index 0000000..0a9647e
--- /dev/null
+++ b/test/hmac-test.js
@@ -0,0 +1,59 @@
+var assert = require('assert');
+var hash = require('../');
+var utils = hash.utils;
+
+describe('Hmac', function() {
+  describe('mixed test vector', function() {
+    test({
+      name: 'nist 1',
+      key: '00010203 04050607 08090A0B 0C0D0E0F' +
+           '10111213 14151617 18191A1B 1C1D1E1F 20212223 24252627' +
+           '28292A2B 2C2D2E2F 30313233 34353637 38393A3B 3C3D3E3F',
+      msg: 'Sample message for keylen=blocklen',
+      res: '8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62'
+    });
+    test({
+      name: 'nist 2',
+      key: '00010203 04050607' +
+           '08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F',
+      msg: 'Sample message for keylen<blocklen',
+      res: 'a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790'
+    });
+    test({
+      name: 'nist 3',
+      key: '00010203' +
+           '04050607 08090A0B 0C0D0E0F 10111213 14151617 18191A1B' +
+           '1C1D1E1F 20212223 24252627 28292A2B 2C2D2E2F 30313233' +
+           '34353637 38393A3B 3C3D3E3F 40414243 44454647 48494A4B' +
+           '4C4D4E4F 50515253 54555657 58595A5B 5C5D5E5F 60616263',
+      msg: 'Sample message for keylen=blocklen',
+      res: 'bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d'
+    });
+    test({
+      name: 'nist 4',
+      key: '00' +
+           '01020304 05060708 090A0B0C 0D0E0F10 11121314 15161718' +
+           '191A1B1C 1D1E1F20 21222324 25262728 292A2B2C 2D2E2F30',
+      msg: 'Sample message for keylen<blocklen, with truncated tag',
+      res: '27a8b157839efeac98df070b331d593618ddb985d403c0c786d23b5d132e57c7'
+    });
+    test({
+      name: 'regression 1',
+      key: '48f38d0c6a344959cc94502b7b5e8dffb6a5f41795d9066fc9a649557167ee2f',
+      msg: '1d495eef7761b65dccd0a983d2d7204fea28b5c81f1758046e062eb043755ea1',
+      msgEnc: 'hex',
+      res: 'cf5ad5984f9e43917aa9087380dac46e410ddc8a7731859c84e9d0f31bd43655'
+    });
+
+    function test(opt) {
+      it('should not fail at ' + opt.name, function() {
+        var h = hash.hmac(hash.sha256, opt.key, 'hex');
+        assert.equal(h.update(opt.msg, opt.msgEnc).digest('hex'), opt.res);
+        var h = hash.hmac(hash.sha256, opt.key, 'hex');
+        assert.equal(h.update(opt.msg.slice(0, 10), opt.msgEnc)
+                      .update(opt.msg.slice(10), opt.msgEnc)
+                      .digest('hex'), opt.res);
+      });
+    }
+  });
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-hash.js.git



More information about the Pkg-javascript-commits mailing list