| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | var crypto = require('crypto'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |  *         every user as it is the seed 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) { | 
					
						
							|  |  |  | 	var key = key || ''; | 
					
						
							|  |  |  | 	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 witht he 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); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  |  *         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 psscode | 
					
						
							|  |  |  |  *         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) { | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	var window = opt.window || 50; | 
					
						
							|  |  |  | 	var counter = opt.counter || 0; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Now loop through from C to C + W to determine if there is
 | 
					
						
							|  |  |  | 	// a correct code
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	for(var i = counter; i <=  counter + window; ++i) { | 
					
						
							|  |  |  | 		opt.counter = i; | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 		if(this.gen(key, opt) === token) { | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 			// We have found a matching code, trigger callback
 | 
					
						
							|  |  |  | 			// and pass offset
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 			return { delta: i - counter }; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If we get to here then no codes have matched, return false
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	var time = opt.time || 30; | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 	var _t = new Date().getTime();; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Time has been overwritten.
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	if(opt._t) { | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 		console.log('#####################################'); | 
					
						
							|  |  |  | 		console.log('# NOTE: TOTP TIME VARIABLE HAS BEEN #'); | 
					
						
							|  |  |  | 		console.log('# OVERWRITTEN.  THIS SHOULD ONLY BE #'); | 
					
						
							|  |  |  | 		console.log('# USED FOR TEST PURPOSES.           #'); | 
					
						
							|  |  |  | 		console.log('#####################################'); | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 		_t = opt._t; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Determine the value of the counter, C
 | 
					
						
							|  |  |  | 	// This is the number of time steps in seconds since T0
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	opt.counter = Math.floor((_t / 1000) / time); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 	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 | 
					
						
							|  |  |  |  *         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 psscode | 
					
						
							|  |  |  |  *         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) { | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	var time = opt.time || 30; | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 	var _t = new Date().getTime(); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Time has been overwritten.
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	if(opt._t) { | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 		console.log('#####################################'); | 
					
						
							|  |  |  | 		console.log('# NOTE: TOTP TIME VARIABLE HAS BEEN #'); | 
					
						
							|  |  |  | 		console.log('# OVERWRITTEN.  THIS SHOULD ONLY BE #'); | 
					
						
							|  |  |  | 		console.log('# USED FOR TEST PURPOSES.           #'); | 
					
						
							|  |  |  | 		console.log('#####################################'); | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 		_t = opt._t; | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Determine the value of the counter, C
 | 
					
						
							|  |  |  | 	// This is the number of time steps in seconds since T0
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:04:21 -04:00
										 |  |  | 	opt.counter = Math.floor((_t / 1000) / time); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | 	return hotp.verify(token, key, opt); | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-01 00:33:55 -04:00
										 |  |  | module.exports.hotp = hotp; | 
					
						
							|  |  |  | module.exports.totp = totp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-31 23:51:19 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * 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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 |