[Pkg-javascript-commits] [node-keygrip] 67/68: Imported Upstream version 1.0.1

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Fri Jun 27 22:13:29 UTC 2014


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

andrewrk-guest pushed a commit to branch master
in repository node-keygrip.

commit c6ba194c2911da30e26ca56a556e47605e77e5b4
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Fri Jun 27 21:33:43 2014 +0000

    Imported Upstream version 1.0.1
---
 .gitignore   |   2 -
 .travis.yml  |   4 +-
 History.md   |  10 ----
 LICENSE.txt  |  12 ++---
 README.md    |  83 ++++++++++++++++++++++-----------
 index.js     | 150 ++++++++++++++++++-----------------------------------------
 package.json |  18 ++++---
 test.js      | 147 ++++++++++++---------------------------------------------
 8 files changed, 145 insertions(+), 281 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4662435..92dfc88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,2 @@
 lib/defaultKeys.js
 defaultKeys.js
-node_modules
-.DS_Store*
diff --git a/.travis.yml b/.travis.yml
index 05d299e..895dbd3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
 language: node_js
 node_js:
-  - "0.10"
-  - "0.11"
+  - 0.6
+  - 0.8
diff --git a/History.md b/History.md
deleted file mode 100644
index dfab6d9..0000000
--- a/History.md
+++ /dev/null
@@ -1,10 +0,0 @@
-
-2.0.0 / 2014-06-
-==================
-
- * remove the `[algorithm]` option, use `.hash=` instead
- * remove the `[encoding]` option, `Buffer`s are now always returned
- * no longer returns any URL-safe hashes
- * add `.encrypt()`, `.decrypt()`, and `.cipher=`
- * default hash algorithm is now `sha256`
- * changed `.index()` to `.indexOf()`
diff --git a/LICENSE.txt b/LICENSE.txt
index 02114d7..161dfc3 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,7 +1,5 @@
-
-The MIT License (MIT)
-Copyright (c) 2014 Jed Schmidt, http://jedschmidt.com/
-
+Copyright (c) 2012 Jed Schmidt, http://jedschmidt.com/
+ 
 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
@@ -9,14 +7,14 @@ 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.
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 5a509ab..4a32c1c 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Keygrip
 
 [![Build Status](https://secure.travis-ci.org/expressjs/keygrip.png)](http://travis-ci.org/expressjs/keygrip)
 
-Keygrip is a [node.js](http://nodejs.org/) module for signing and verifying data through a rotating credential system, in which new server keys can be added and old ones removed regularly, without invalidating client credentials.
+Keygrip is a [node.js](http://nodejs.org/) module for signing and verifying data (such as cookies or URLs) through a rotating credential system, in which new server keys can be added and old ones removed regularly, without invalidating client credentials.
 
 ## Install
 
@@ -11,13 +11,19 @@ Keygrip is a [node.js](http://nodejs.org/) module for signing and verifying data
 
 ## API
 
-### keys = Keygrip(keylist)
+### keys = new Keygrip([keylist], [hmacAlgorithm], [encoding])
 
-This creates a new Keygrip based on the provided `keylist`.
+This creates a new Keygrip based on the provided keylist, an array of secret keys used for SHA1 HMAC digests. `keylist` is obligatory. `hmacAlgorithm` defaults to `'sha1'` and `encoding` defaults to `'base64'`.
+
+Note that the `new` operator is also optional, so all of the following will work when `Keygrip = require("keygrip")`:
 
 ```javascript
-var Keygrip = require('keygrip')
+keys = new Keygrip(["SEKRIT2", "SEKRIT1"])
 keys = Keygrip(["SEKRIT2", "SEKRIT1"])
+keys = require("keygrip")()
+keys = Keygrip(["SEKRIT2", "SEKRIT1"], 'sha256', 'hex')
+keys = Keygrip(["SEKRIT2", "SEKRIT1"], 'sha256')
+keys = Keygrip(["SEKRIT2", "SEKRIT1"], undefined, 'hex')
 ```
 
 The keylist is an array of all valid keys for signing, in descending order of freshness; new keys should be `unshift`ed into the array and old keys should be `pop`ped.
@@ -26,42 +32,65 @@ The tradeoff here is that adding more keys to the keylist allows for more granul
 
 Keygrip keeps a reference to this array to automatically reflect any changes. This reference is stored using a closure to prevent external access.
 
-When using `Keygrip` to encrypt and decrypt data, each `key`'s length is important.
-
-### var buf = keys.sign(data)
+### keys.sign(data)
 
-This creates a HMAC based on the _first_ key in the keylist, and outputs it as a buffer.
+This creates a SHA1 HMAC based on the _first_ key in the keylist, and outputs it as a 27-byte url-safe base64 digest (base64 without padding, replacing `+` with `-` and `/` with `_`).
 
-Uses `.hash=` as the underlying algorithm.
-
-### var index = keys.indexOf(data)
+### keys.index(data, digest)
 
 This loops through all of the keys currently in the keylist until the digest of the current key matches the given digest, at which point the current index is returned. If no key is matched, `-1` is returned.
 
 The idea is that if the index returned is greater than `0`, the data should be re-signed to prevent premature credential invalidation, and enable better performance for subsequent challenges.
 
-### var bool = keys.verify(data)
+### keys.verify(data, digest)
 
 This uses `index` to return `true` if the digest matches any existing keys, and `false` otherwise.
 
-### var buf = keys.encrypt(message, [iv])
-
-Creates an encrypted message as a buffer based on the _first_ key in the keylist and optionally based on an initialization vector.
+## Example
 
-Uses `.cipher=` as the underlying algorithm.
-Note that `iv` length is important.
-
-### var [buf, i] = keys.decrypt(message, [iv])
+```javascript
+// ./test.js
+var assert = require("assert")
+  , Keygrip = require("keygrip")
+  , keylist, keys, hash, index
+
+// but we're going to use our list.
+// (note that the 'new' operator is optional)
+keylist = ["SEKRIT3", "SEKRIT2", "SEKRIT1"]
+keys = Keygrip(keylist)
+// .sign returns the hash for the first key
+// all hashes are SHA1 HMACs in url-safe base64
+hash = keys.sign("bieberschnitzel")
+assert.ok(/^[\w\-]{27}$/.test(hash))
+
+// .index returns the index of the first matching key
+index = keys.index("bieberschnitzel", hash)
+assert.equal(index, 0)
+
+// .verify returns the a boolean indicating a matched key
+matched = keys.verify("bieberschnitzel", hash)
+assert.ok(matched)
+
+index = keys.index("bieberschnitzel", "o_O")
+assert.equal(index, -1)
+
+// rotate a new key in, and an old key out
+keylist.unshift("SEKRIT4")
+keylist.pop()
+
+// if index > 0, it's time to re-sign
+index = keys.index("bieberschnitzel", hash)
+assert.equal(index, 1)
+hash = keys.sign("bieberschnitzel")
+```
 
-Decrypts a message, optionally with an initialization vector.
-Returns a buffer as `buf`.
-Also returns `i`, the index of the `key` used.
-If `i !== 0`, you may want to re-encrypt the message to use the latest key.
+## TODO
 
-### keys.hash=
+* Write a library for URL signing
 
-Set the hashing algorithm for signing, defaulting to `sha256`.
+Copyright
+---------
 
-### .cipher=
+Copyright (c) 2012 Jed Schmidt. See LICENSE.txt for details.
 
-Set the algorithm used for message encryption, defaulting to `aes-256-cbc`.
+Send any questions or comments [here](http://twitter.com/jedschmidt).
diff --git a/index.js b/index.js
index e122d8d..2e9ae8b 100644
--- a/index.js
+++ b/index.js
@@ -1,123 +1,63 @@
-
 var crypto = require("crypto")
-var constantTimeCompare = require('scmp')
-var debug = require('debug')('keygrip')
-
-module.exports = Keygrip
-
-function Keygrip(keys) {
-  if (arguments.length > 1) {
-    console.warn('as of v2, keygrip() only accepts a single argument.')
-    console.warn('set keygrip().hash= instead.')
-    console.warn('keygrip() also now only supports buffers.')
+  
+function Keygrip(keys, algorithm, encoding) {
+  if (!algorithm) algorithm = "sha1";
+  if (!encoding) encoding = "base64";
+  if (!(this instanceof Keygrip)) return new Keygrip(keys, algorithm, encoding)
+
+  if (!keys || !(0 in keys)) {
+    throw new Error("Keys must be provided.")
   }
 
-  if (!Array.isArray(keys) || !keys.length) throw new Error("Keys must be provided.")
-  if (!(this instanceof Keygrip)) return new Keygrip(keys)
-
-  this.keys = keys
-}
-
-/**
- * Allow setting `keygrip.hash = 'sha1'`
- * or `keygrip.cipher = 'aes256'`
- * with validation instead of always doing `keygrip([], alg, enc)`.
- * This also allows for easier defaults.
- */
-
-Keygrip.prototype = {
-  constructor: Keygrip,
-
-  get hash() {
-    return this._hash
-  },
-
-  set hash(val) {
-    if (!~crypto.getHashes().indexOf(val))
-      throw new Error('unsupported hash algorithm: ' + val)
-    this._hash = val
-  },
-
-  get cipher() {
-    return this._cipher
-  },
-
-  set cipher(val) {
-    if (!~crypto.getCiphers().indexOf(val))
-      throw new Error('unsupported cipher: ' + val)
-    this._cipher = val
-  },
-
-  // defaults
-  _hash: 'sha256',
-  _cipher: 'aes-256-cbc',
-}
+  function sign(data, key) {
+    return crypto
+      .createHmac(algorithm, key)
+      .update(data).digest(encoding)
+      .replace(/\/|\+|=/g, function(x) {
+        return ({ "/": "_", "+": "-", "=": "" })[x]
+      })
+  }
 
-// encrypt a message
-Keygrip.prototype.encrypt = function Keygrip$_encrypt(data, iv, key) {
-  key = key || this.keys[0]
+  this.sign = function(data){ return sign(data, keys[0]) }
 
-  var cipher = iv
-    ? crypto.createCipheriv(this.cipher, key, iv)
-    : crypto.createCipher(this.cipher, key)
-  return Buffer.concat([cipher.update(data), cipher.final()])
-}
+  this.verify = function(data, digest) {
+    return this.index(data, digest) > -1
+  }
 
-// decrypt a single message
-// returns false on bad decrypts
-Keygrip.prototype.decrypt = function Keygrip$__decrypt(data, iv, key) {
-  if (!key) {
-    // decrypt every key
-    var keys = this.keys
+  this.index = function(data, digest) {
     for (var i = 0, l = keys.length; i < l; i++) {
-      var message = this.decrypt(data, iv, keys[i])
-      if (message !== false) return [message, i]
+      if (constantTimeCompare(digest, sign(data, keys[i]))) return i
     }
 
-    return false
+    return -1
   }
+}
 
-  try {
-    var cipher = iv
-      ? crypto.createDecipheriv(this.cipher, key, iv)
-      : crypto.createDecipher(this.cipher, key)
-    return Buffer.concat([cipher.update(data), cipher.final()])
-  } catch (err) {
-    debug(err.stack)
-    return false
-  }
+Keygrip.sign = Keygrip.verify = Keygrip.index = function() {
+  throw new Error("Usage: require('keygrip')(<array-of-keys>)")
 }
 
-// message signing
-Keygrip.prototype.sign = function Keygrip$_sign(data, key) {
-  // default to the first key
-  key = key || this.keys[0]
+//http://codahale.com/a-lesson-in-timing-attacks/
+var constantTimeCompare = function(val1, val2){
+    if(val1 == null && val2 != null){
+        return false;
+    } else if(val2 == null && val1 != null){
+        return false;
+    } else if(val1 == null && val2 == null){
+        return true;
+    }
 
-  return crypto
-    .createHmac(this.hash, key)
-    .update(data)
-    .digest()
-}
+    if(val1.length !== val2.length){
+        return false;
+    }
 
-Keygrip.prototype.verify = function Keygrip$_verify(data, digest) {
-  return this.indexOf(data, digest) > -1
-}
+    var matches = 1;
 
-Keygrip.prototype.index =
-Keygrip.prototype.indexOf = function Keygrip$_index(data, digest) {
-  var keys = this.keys
-  for (var i = 0, l = keys.length; i < l; i++) {
-    if (constantTimeCompare(digest, this.sign(data, keys[i]))) return i
-  }
+    for(var i = 0; i < val1.length; i++){
+        matches &= (val1.charAt(i) === val2.charAt(i) ? 1 : 0); //Don't short circuit
+    }
 
-  return -1
-}
+    return matches === 1;
+};
 
-Keygrip.encrypt =
-Keygrip.decrypt =
-Keygrip.sign =
-Keygrip.verify =
-Keygrip.index =
-Keygrip.indexOf = function() {
-  throw new Error("Usage: require('keygrip')(<array-of-keys>)")
-}
+module.exports = Keygrip
diff --git a/package.json b/package.json
index fddd369..73ff755 100644
--- a/package.json
+++ b/package.json
@@ -1,19 +1,17 @@
 {
   "name": "keygrip",
-  "version": "1.0.0",
+  "version": "1.0.1",
   "description": "Key signing and verification for rotated credentials",
   "scripts": {
-    "test": "mocha --reporter spec --bail"
+    "test": "node test.js"
   },
-  "repository": "expressjs/keygrip",
-  "dependencies": {
-    "debug": "*",
-    "scmp": "0.0.3"
-  },
-  "devDependencies": {
-    "mocha": "1"
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/expressjs/keygrip.git"
   },
+  "dependencies": {},
+  "devDependencies": {},
   "engines": {
-    "node": ">= 0.10"
+    "node": "*"
   }
 }
diff --git a/test.js b/test.js
index 1bc9268..7fe7352 100644
--- a/test.js
+++ b/test.js
@@ -1,147 +1,58 @@
 "use strict";
 
 // ./test.js
-var crypto = require('crypto')
 var assert = require("assert")
   , Keygrip = require("./")
   , keylist, keys, hash, index
 
-describe('keygrip(keys)', function () {
-  it('should throw if keys are missing or empty', function () {
-    // keygrip takes an array of keys. If missing or empty, it will throw.
-    assert.throws(function() {
-      keys = new Keygrip(/* empty list */);
-    }, /must be provided/);
-  })
+// keygrip takes an array of keys. If missing or empty, it will throw.
+assert.throws(function() {
+	keys = new Keygrip(/* empty list */);
+}, /must be provided/);
 
-  it('should throw when setting an invalid hash algorithm', function () {
-    var keys = new Keygrip(['a', 'b'])
-    assert.throws(function () {
-      keys.hash = 'asdf'
-    }, /unsupported/)
-  })
+// Randomly generated key - don't use this for something real. Don't be that person.
+keys = new Keygrip(['06ae66fdc6c2faf5a401b70e0bf885cb']);  
 
-  it('should throw when setting an invalid cipher', function () {
-    var keys = new Keygrip(['a', 'b'])
-    assert.throws(function () {
-      keys.cipher = 'asdf'
-    }, /unsupported/)
-  })
-})
+// .sign returns the hash for the first key
+// all hashes are SHA1 HMACs in url-safe base64
+hash = keys.sign("bieberschnitzel")
+assert.ok(/^[\w\-]{27}$/.test(hash))
 
-describe('keygrip([key])', function () {
-  it('should sign a string', function () {
-    // Randomly generated key - don't use this for something real. Don't be that person.
-    keys = new Keygrip(['06ae66fdc6c2faf5a401b70e0bf885cb']);
 
-    // .sign returns the hash for the first key
-    // all hashes are SHA1 HMACs in url-safe base64
-    hash = keys.sign("bieberschnitzel")
-    assert.ok(/^[\w\+=]{44}$/.test(hash.toString('base64')))
-  })
+// but we're going to use our list.
+// (note that the 'new' operator is optional)
+keylist = ["SEKRIT3", "SEKRIT2", "SEKRIT1"] // keylist will be modified in place, so don't reuse
+keys = Keygrip(keylist)
+testKeygripInstance(keys);
 
-  it('should encrypt a message', function () {
-    hash = keys.encrypt('lol')
-    assert.equal('lol', keys.decrypt(hash)[0].toString('utf8'))
-  })
 
-  it('should return false on bad decryptions', function () {
-    var keys2 = new Keygrip(['lkjasdf'])
-    assert.equal(false, keys2.decrypt(hash))
-  })
+// now pass in a different hmac algorithm and encoding
+keylist = ["Newest", "AnotherKey", "Oldest"]
+keys = Keygrip(keylist, "sha256", "hex")
+testKeygripInstance(keys);
 
-  it('should return false on bad inputs', function () {
-    assert.equal(false, keys.decrypt(hash + 'asdf'))
-  })
-})
 
-describe('keygrip([keys...])', function () {
-  it('should sign a string', function () {
-    // but we're going to use our list.
-    // (note that the 'new' operator is optional)
-    keylist = ["SEKRIT3", "SEKRIT2", "SEKRIT1"] // keylist will be modified in place, so don't reuse
-    keys = Keygrip(keylist)
-    testKeygripInstance(keys);
-  })
-
-  it('should sign a string with a different algorithm and encoding', function () {
-    // now pass in a different hmac algorithm and encoding
-    keylist = ["Newest", "AnotherKey", "Oldest"]
-    keys = Keygrip(keylist)
-    testKeygripInstance(keys);
-  })
-})
-
-describe('Message encryption', function () {
-  var length = 16
-  var key = crypto.randomBytes(32)
-  var keygrip = new Keygrip([key])
-
-  describe('with iv', function () {
-    var iv = crypto.randomBytes(length)
-    var message = keygrip.encrypt('lol', iv)
-
-    it('should encrypt and decrypt', function () {
-      assert.equal('lol', keygrip.decrypt(message, iv)[0].toString('utf8'))
-    })
-
-    it('should return false on invalid key', function () {
-      assert.equal(false, new Keygrip([crypto.randomBytes(32)])
-        .decrypt(message, iv))
-    })
-
-    it('should return false on missing iv', function () {
-      assert.equal(false, keygrip.decrypt(message))
-    })
-
-    it('should return false on invalid iv', function () {
-      assert.equal(false, keygrip.decrypt(message, crypto.randomBytes(length)))
-    })
-  })
-
-  describe('without iv', function () {
-    var message = keygrip.encrypt('lol')
-
-    it('should encrypt and decrypt', function () {
-      assert.equal('lol', keygrip.decrypt(message)[0].toString('utf8'))
-    })
-
-    it('should return false on invalid key', function () {
-      assert.equal(false, new Keygrip([crypto.randomBytes(32)])
-        .decrypt(message))
-    })
-
-    it('should work on really long strings', function () {
-      var string = ''
-      for (var i = 0; i < 10000; i++) {
-        string += 'a'
-      }
-      var msg = keygrip.encrypt(new Buffer(string))
-      assert.equal(string, keygrip.decrypt(msg)[0].toString('utf8'))
-    })
-  })
-})
 
 function testKeygripInstance(keys) {
 	hash = keys.sign("bieberschnitzel")
-
+	
 	// .index returns the index of the first matching key
-	index = keys.indexOf("bieberschnitzel", hash)
+	index = keys.index("bieberschnitzel", hash)
 	assert.equal(index, 0)
-
+	
 	// .verify returns the a boolean indicating a matched key
 	var matched = keys.verify("bieberschnitzel", hash)
 	assert.ok(matched)
-
-	index = keys.indexOf("bieberschnitzel", "o_O")
+	
+	index = keys.index("bieberschnitzel", "o_O")
 	assert.equal(index, -1)
-
+	
 	// rotate a new key in, and an old key out
 	keylist.unshift("SEKRIT4")
 	keylist.pop()
-
+	
 	// if index > 0, it's time to re-sign
-	index = keys.indexOf("bieberschnitzel", hash)
+	index = keys.index("bieberschnitzel", hash)
 	assert.equal(index, 1)
-	hash = keys.sign("bieberschnitzel")
-}
+	hash = keys.sign("bieberschnitzel")	
+}
\ No newline at end of file

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



More information about the Pkg-javascript-commits mailing list