aboutsummaryrefslogtreecommitdiff
path: root/node_modules/keygrip/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/keygrip/index.js')
-rw-r--r--node_modules/keygrip/index.js71
1 files changed, 71 insertions, 0 deletions
diff --git a/node_modules/keygrip/index.js b/node_modules/keygrip/index.js
new file mode 100644
index 00000000..5cdeba53
--- /dev/null
+++ b/node_modules/keygrip/index.js
@@ -0,0 +1,71 @@
+/*!
+ * keygrip
+ * Copyright(c) 2011-2014 Jed Schmidt
+ * MIT Licensed
+ */
+
+'use strict'
+
+var crypto = require("crypto")
+
+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.")
+ }
+
+ function sign(data, key) {
+ return crypto
+ .createHmac(algorithm, key)
+ .update(data).digest(encoding)
+ .replace(/\/|\+|=/g, function(x) {
+ return ({ "/": "_", "+": "-", "=": "" })[x]
+ })
+ }
+
+ this.sign = function(data){ return sign(data, keys[0]) }
+
+ this.verify = function(data, digest) {
+ return this.index(data, digest) > -1
+ }
+
+ this.index = function(data, digest) {
+ for (var i = 0, l = keys.length; i < l; i++) {
+ if (constantTimeCompare(digest, sign(data, keys[i]))) return i
+ }
+
+ return -1
+ }
+}
+
+Keygrip.sign = Keygrip.verify = Keygrip.index = function() {
+ throw new Error("Usage: require('keygrip')(<array-of-keys>)")
+}
+
+//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;
+ }
+
+ if(val1.length !== val2.length){
+ return false;
+ }
+
+ var result = 0;
+
+ for(var i = 0; i < val1.length; i++){
+ result |= val1.charCodeAt(i) ^ val2.charCodeAt(i); //Don't short circuit
+ }
+
+ return result === 0;
+};
+
+module.exports = Keygrip