| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  | (function (exports, TEST) { | 
					
						
							| 
									
										
										
										
											2015-10-07 11:05:12 -07:00
										 |  |  | 'use strict'; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  | var crypto; | 
					
						
							|  |  |  | var sha1Hmac = exports.sha1Hmac || function (key, bytes) { | 
					
						
							|  |  |  |   if (!crypto) { crypto = require('crypto'); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var hmac = crypto.createHmac('sha1', new Buffer(key)); | 
					
						
							|  |  |  |   // Update the HMAC with the byte array
 | 
					
						
							|  |  |  |   return hmac.update(new Buffer(bytes)).digest('hex'); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-07 11:08:13 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * convert an integer to a byte array | 
					
						
							|  |  |  |  * @param {Integer} num | 
					
						
							|  |  |  |  * @return {Array} bytes | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function intToBytes(num) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   var bytes = []; | 
					
						
							| 
									
										
										
										
											2015-10-07 11:08:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   for(var i=7 ; i>=0 ; --i) { | 
					
						
							|  |  |  |     bytes[i] = num & (255); | 
					
						
							|  |  |  |     num = num >> 8; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-10-07 11:08:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   return bytes; | 
					
						
							| 
									
										
										
										
											2015-10-07 11:08:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * convert a hex value to a byte array | 
					
						
							|  |  |  |  * @param {String} hex string of hex to convert to a byte array | 
					
						
							|  |  |  |  * @return {Array} bytes | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function hexToBytes(hex) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   var bytes = []; | 
					
						
							|  |  |  |   for(var c = 0, C = hex.length; c < C; c += 2) { | 
					
						
							|  |  |  |     bytes.push(parseInt(hex.substr(c, 2), 16)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return bytes; | 
					
						
							| 
									
										
										
										
											2015-10-07 11:08:13 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 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 | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         every user as this is the seed that is used to calculate the HMAC | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  *     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) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   key = key || ''; | 
					
						
							|  |  |  |   opt = opt || {}; | 
					
						
							|  |  |  |   var counter = opt.counter || 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create the byte array
 | 
					
						
							|  |  |  |   return sha1Hmac(key, intToBytes(counter)).then(function (digest) { | 
					
						
							|  |  |  |     // 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 % 1000000) + ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return new Array(7-v.length).join('0') + v; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     key - Key for the one time password.  This should be unique and secret for | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         every user as it is the seed used to calculate the HMAC | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     token - Passcode to validate. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     window - The allowable margin for the counter.  The function will check | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         'W' codes in the future against the provided passcode.  Note, | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         it is the calling applications responsibility to keep track of | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         'W' and increment it for each password check, and also to adjust | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         it accordingly in the case where the client and server become | 
					
						
							|  |  |  |  *         out of sync (second argument returns non zero). | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         E.g. if W = 100, and C = 5, this function will check the passcode | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         against all One Time Passcodes between 5 and 105. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *         Default - 50 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     counter - Counter value.  This should be stored by the application, must | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         be user specific, and be incremented for each request. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | hotp.verify = function(token, key, opt) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   opt = opt || {}; | 
					
						
							|  |  |  |   var window = opt.window || 50; | 
					
						
							|  |  |  |   var counter = opt.counter || 0; | 
					
						
							|  |  |  |   var i = counter - window; | 
					
						
							|  |  |  |   var len = counter + window; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Now loop through from C to C + W to determine if there is
 | 
					
						
							|  |  |  |   // a correct code
 | 
					
						
							|  |  |  |   function check(t) { | 
					
						
							|  |  |  |     opt.counter = i + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!t) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (i > len) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(t === token) { | 
					
						
							|  |  |  |       // We have found a matching code, trigger callback
 | 
					
						
							|  |  |  |       // and pass offset
 | 
					
						
							|  |  |  |       return i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO count 0, -1, 1, -2, 2, ... instead of -2, -1, 0, 1, ...
 | 
					
						
							|  |  |  |     i += 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return hotp.gen(key, opt).then(check); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   opt.counter = i; | 
					
						
							|  |  |  |   return hotp.gen(key, opt).then(check).then(function (i) { | 
					
						
							|  |  |  |     if('number' === typeof i) { | 
					
						
							|  |  |  |       return { delta: i - counter }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // If we get to here then no codes have matched, return null
 | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | var totp = {}; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  * Generate a time based One Time Password | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  * @return {String} the one time password | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Arguments: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  args | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     key - Key for the one time password.  This should be unique and secret for | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         every user as it is the seed used to calculate the HMAC | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     time - The time step of the counter.  This must be the same for | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         every request and is used to calculat C. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  *         Default - 30 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | totp.gen = function(key, opt) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   opt = opt || {}; | 
					
						
							|  |  |  |   var time = opt.time || 30; | 
					
						
							|  |  |  |   var _t = Date.now(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Time has been overwritten.
 | 
					
						
							|  |  |  |   if(opt._t) { | 
					
						
							|  |  |  |     if(!TEST) { | 
					
						
							|  |  |  |       console.warn('Overwriting 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); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  * Check a One Time Password based on a timer. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  * @return {Object} null if failure, { delta: # } on success | 
					
						
							|  |  |  |  * delta is the time step difference between the client and the server | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Arguments: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  args | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     key - Key for the one time password.  This should be unique and secret for | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         every user as it is the seed used to calculate the HMAC | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *     token - Passcode to validate. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *     window - The allowable margin for the counter.  The function will check | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         'W' codes either side of the provided counter.  Note, | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         it is the calling applications responsibility to keep track of | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         'W' and increment it for each password check, and also to adjust | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         it accordingly in the case where the client and server become | 
					
						
							|  |  |  |  *         out of sync (second argument returns non zero). | 
					
						
							| 
									
										
										
										
											2013-03-27 17:23:07 -07:00
										 |  |  |  *         E.g. if W = 5, and C = 1000, this function will check the passcode | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         against all One Time Passcodes between 995 and 1005. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         Default - 6 | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  |  *     time - The time step of the counter.  This must be the same for | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  |  *         every request and is used to calculate C. | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  *         Default - 30 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | totp.verify = function(token, key, opt) { | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  |   opt = opt || {}; | 
					
						
							|  |  |  |   var time = opt.time || 30; | 
					
						
							|  |  |  |   var _t = Date.now(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Time has been overwritten.
 | 
					
						
							|  |  |  |   if(opt._t) { | 
					
						
							|  |  |  |     if(!TEST) { | 
					
						
							|  |  |  |       console.warn('Overwriting 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); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 21:22:21 -07:00
										 |  |  | exports.hotp = hotp; | 
					
						
							|  |  |  | exports.totp = totp; | 
					
						
							|  |  |  | }( | 
					
						
							|  |  |  |   'undefined' !== typeof window ? window : module.exports | 
					
						
							|  |  |  | , 'undefined' !== typeof process ? process.env.NODE_ENV : false | 
					
						
							|  |  |  | )); |