diff options
author | Minteck <contact@minteck.org> | 2022-08-10 10:38:44 +0200 |
---|---|---|
committer | Minteck <contact@minteck.org> | 2022-08-10 10:38:44 +0200 |
commit | c6dbf0450566c40efc4a26f4f0717452b6ef95cd (patch) | |
tree | b4be2d508223820d0a77d5a3e35e82684da3b6ec /node_modules/notp/index.js | |
download | hornchat-c6dbf0450566c40efc4a26f4f0717452b6ef95cd.tar.gz hornchat-c6dbf0450566c40efc4a26f4f0717452b6ef95cd.tar.bz2 hornchat-c6dbf0450566c40efc4a26f4f0717452b6ef95cd.zip |
Diffstat (limited to 'node_modules/notp/index.js')
-rw-r--r-- | node_modules/notp/index.js | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/node_modules/notp/index.js b/node_modules/notp/index.js new file mode 100644 index 0000000..de0d91f --- /dev/null +++ b/node_modules/notp/index.js @@ -0,0 +1,221 @@ + +var crypto = require('crypto'); + +var hotp = {}; + +/** + * Generate a counter based One Time Password + * + * @return {String} the one time password + * + * Arguments: + * + * args + * key - Key for the one time password. This should be unique and secret for + * every user as this is the seed that is used to calculate the HMAC + * + * counter - Counter value. This should be stored by the application, must + * be user specific, and be incremented for each request. + * + */ +hotp.gen = function(key, opt) { + key = key || ''; + opt = opt || {}; + var counter = opt.counter || 0; + + var p = 6; + + // Create the byte array + var b = new Buffer(intToBytes(counter)); + + var hmac = crypto.createHmac('sha1', new Buffer(key)); + + // Update the HMAC with the byte array + var digest = hmac.update(b).digest('hex'); + + // Get byte array + var h = hexToBytes(digest); + + // Truncate + var offset = h[19] & 0xf; + var v = (h[offset] & 0x7f) << 24 | + (h[offset + 1] & 0xff) << 16 | + (h[offset + 2] & 0xff) << 8 | + (h[offset + 3] & 0xff); + + v = v + ''; + + return v.substr(v.length - p, p); +}; + +/** + * Check a One Time Password based on a counter. + * + * @return {Object} null if failure, { delta: # } on success + * delta is the time step difference between the client and the server + * + * Arguments: + * + * args + * key - Key for the one time password. This should be unique and secret for + * every user as it is the seed used to calculate the HMAC + * + * token - Passcode to validate. + * + * window - The allowable margin for the counter. The function will check + * 'W' codes in the future against the provided passcode. Note, + * it is the calling applications responsibility to keep track of + * 'W' and increment it for each password check, and also to adjust + * it accordingly in the case where the client and server become + * out of sync (second argument returns non zero). + * E.g. if W = 100, and C = 5, this function will check the passcode + * against all One Time Passcodes between 5 and 105. + * + * Default - 50 + * + * counter - Counter value. This should be stored by the application, must + * be user specific, and be incremented for each request. + * + */ +hotp.verify = function(token, key, opt) { + opt = opt || {}; + var window = opt.window || 50; + var counter = opt.counter || 0; + + // Now loop through from C to C + W to determine if there is + // a correct code + for(var i = counter - window; i <= counter + window; ++i) { + opt.counter = i; + if(this.gen(key, opt) === token) { + // We have found a matching code, trigger callback + // and pass offset + return { delta: i - counter }; + } + } + + // If we get to here then no codes have matched, return null + return null; +}; + +var totp = {}; + +/** + * Generate a time based One Time Password + * + * @return {String} the one time password + * + * Arguments: + * + * args + * key - Key for the one time password. This should be unique and secret for + * every user as it is the seed used to calculate the HMAC + * + * time - The time step of the counter. This must be the same for + * every request and is used to calculat C. + * + * Default - 30 + * + */ +totp.gen = function(key, opt) { + opt = opt || {}; + var time = opt.time || 30; + var _t = new Date().getTime();; + + // Time has been overwritten. + if(opt._t) { + if(process.env.NODE_ENV != 'test') { + throw new Error('cannot overwrite time in non-test environment!'); + } + _t = opt._t; + } + + // Determine the value of the counter, C + // This is the number of time steps in seconds since T0 + opt.counter = Math.floor((_t / 1000) / time); + + return hotp.gen(key, opt); +}; + +/** + * Check a One Time Password based on a timer. + * + * @return {Object} null if failure, { delta: # } on success + * delta is the time step difference between the client and the server + * + * Arguments: + * + * args + * key - Key for the one time password. This should be unique and secret for + * every user as it is the seed used to calculate the HMAC + * + * token - Passcode to validate. + * + * window - The allowable margin for the counter. The function will check + * 'W' codes either side of the provided counter. Note, + * it is the calling applications responsibility to keep track of + * 'W' and increment it for each password check, and also to adjust + * it accordingly in the case where the client and server become + * out of sync (second argument returns non zero). + * E.g. if W = 5, and C = 1000, this function will check the passcode + * against all One Time Passcodes between 995 and 1005. + * + * Default - 6 + * + * time - The time step of the counter. This must be the same for + * every request and is used to calculate C. + * + * Default - 30 + * + */ +totp.verify = function(token, key, opt) { + opt = opt || {}; + var time = opt.time || 30; + var _t = new Date().getTime(); + + // Time has been overwritten. + if(opt._t) { + if(process.env.NODE_ENV != 'test') { + throw new Error('cannot overwrite time in non-test environment!'); + } + _t = opt._t; + } + + // Determine the value of the counter, C + // This is the number of time steps in seconds since T0 + opt.counter = Math.floor((_t / 1000) / time); + + return hotp.verify(token, key, opt); +}; + +module.exports.hotp = hotp; +module.exports.totp = totp; + +/** + * convert an integer to a byte array + * @param {Integer} num + * @return {Array} bytes + */ +var intToBytes = function(num) { + var bytes = []; + + for(var i=7 ; i>=0 ; --i) { + bytes[i] = num & (255); + num = num >> 8; + } + + return bytes; +}; + + +/** + * convert a hex value to a byte array + * @param {String} hex string of hex to convert to a byte array + * @return {Array} bytes + */ +var hexToBytes = function(hex) { + var bytes = []; + for(var c = 0; c < hex.length; c += 2) { + bytes.push(parseInt(hex.substr(c, 2), 16)); + } + return bytes; +}; |