1
|
|
|
/* global sjcl */ |
2
|
|
|
|
3
|
|
|
window.OTP = (function () { |
4
|
|
|
function dec2hex(s) { |
5
|
|
|
return (s < 15.5 ? '0' : '') + Math.round(s).toString(16); |
6
|
|
|
} |
7
|
|
|
|
8
|
|
|
function hex2dec(s) { |
9
|
|
|
return parseInt(s, 16); |
10
|
|
|
} |
11
|
|
|
|
12
|
|
|
function base32tohex(base32) { |
13
|
|
|
if (!base32) { |
14
|
|
|
return; |
15
|
|
|
} |
16
|
|
|
var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |
17
|
|
|
var bits = ""; |
18
|
|
|
var hex = ""; |
19
|
|
|
var i; |
20
|
|
|
for (i = 0; i < base32.length; i++) { |
21
|
|
|
var val = base32chars.indexOf(base32.charAt(i).toUpperCase()); |
22
|
|
|
bits += leftpad(val.toString(2), 5, '0'); |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
for (i = 0; i + 4 <= bits.length; i += 4) { |
26
|
|
|
var chunk = bits.substr(i, 4); |
27
|
|
|
hex = hex + parseInt(chunk, 2).toString(16); |
28
|
|
|
} |
29
|
|
|
return hex; |
30
|
|
|
|
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
function leftpad(str, len, pad) { |
34
|
|
|
if (len + 1 >= str.length) { |
35
|
|
|
str = Array(len + 1 - str.length).join(pad) + str; |
36
|
|
|
} |
37
|
|
|
return str; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
|
41
|
|
|
var _OTP = { |
42
|
|
|
secret: '', |
43
|
|
|
getOTP: function () { |
44
|
|
|
if (!this.secret) { |
45
|
|
|
return; |
46
|
|
|
} |
47
|
|
|
var key = base32tohex(this.secret); |
48
|
|
|
var epoch = Math.round(new Date().getTime() / 1000.0); |
49
|
|
|
var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0'); |
50
|
|
|
/** global: jsSHA */ |
51
|
|
|
var hmacObj = new jsSHA(time, 'HEX'); |
|
|
|
|
52
|
|
|
var hmac = hmacObj.getHMAC(key, 'HEX', 'SHA-1', "HEX"); |
53
|
|
|
var offset = hex2dec(hmac.substring(hmac.length - 1)); |
54
|
|
|
var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + ''; |
55
|
|
|
otp = (otp).substr(otp.length - 6, 6); |
56
|
|
|
return otp; |
57
|
|
|
} |
58
|
|
|
}; |
59
|
|
|
return _OTP; |
60
|
|
|
}()); |