index.js
1.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*!
* keygrip
* Copyright(c) 2011-2014 Jed Schmidt
* MIT Licensed
*/
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