totp.js
Version:
Two-factor authentication implementation in pure javascript. One-time password generator (HOTP/TOTP) with support for Google Authenticator.
84 lines (71 loc) • 1.99 kB
JavaScript
/*
* @Author: wuyanxin
* @Date: 2018-03-21 22:25:37
* @Last Modified by: wuyanxin
* @Last Modified time: 2018-03-21 22:29:43
*/
const base32 = require('thirty-two');
const jssha = require('jssha');
class HOTP {
/**
*
* @param {string} key secret key
* @param {*} digit lenth of otp code
*/
constructor(key, digit = 6) {
this.key = key;
this.digit = digit;
}
static get base32() {
return base32;
}
/**
* generate a base32 secret key
* @param {int} len
*/
static randomKey(len = 16) {
const str = Math.random().toString(36);
return base32.encode(str).toString().substr(0, len);
}
/**
* generate a OTP base on HMAC-SHA-1
* @param {int} movingFactor counter
*/
genOTP(movingFactor) {
const hmacSha = new jssha('SHA-1', 'BYTES');
hmacSha.setHMACKey(base32.decode(this.key).toString(), 'BYTES');
const factorByte = this._factor2ByteText(movingFactor);
hmacSha.update(factorByte);
const hmac_result = hmacSha.getHMAC('BYTES');
return this._truncat(hmac_result);
}
/**
* verify a OPT code
* @param {string} opt opt code
* @param {int} movingFactor counter
*/
verify(opt, movingFactor) {
return opt === this.genOTP(movingFactor);
}
_truncat(hmac_result) {
const offset = hmac_result[19].charCodeAt() & 0xf;
const bin_code = (hmac_result[offset].charCodeAt() & 0x7f) << 24
| (hmac_result[offset+1].charCodeAt() & 0xff) << 16
| (hmac_result[offset+2].charCodeAt() & 0xff) << 8
| (hmac_result[offset+3].charCodeAt() & 0xff);
let otp = (bin_code % 10 ** this.digit).toString();
while (otp.length < this.digit) {
otp = '0' + otp;
}
return otp;
}
_factor2ByteText(movingFactor) {
const text = new Array(8);
for (let i = text.length - 1; i >= 0; i--) {
text[i] = String.fromCharCode(movingFactor & 0xFF);
movingFactor >>= 8;
}
return text.join('');
}
}
module.exports = HOTP;