-
Notifications
You must be signed in to change notification settings - Fork 0
/
totp.js
217 lines (155 loc) · 4.97 KB
/
totp.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
* RFC 6238 TOTP script
* Andy Thompson
* This work is released in to the public domain.
*/
var mySites = [];
function Site(_siteName,_siteUser,_siteSeed)
{
this.siteName = _siteName;
this.siteUser = _siteUser;
this.siteSeed = _siteSeed;
}
function start()
{
$.ajax({
type: 'GET',
url: 'data.json',
dataType: 'json',
success: function(data) {
$.each( data.sites, function( siteName, val ) {
mySites.push(new Site(val.siteName,val.siteUser,val.seed));
});
},
async: false
});
for(var i1=0;i1<mySites.length;i1++)
{
var divID = "#site" + i1 + "_code";
$("#codeList").append('<div class="col-xs-12 col-md-12"><h3 id="site' + i1 + '_name" class="text-center">' + mySites[i1].siteName + ' - <small>' + mySites[i1].siteUser+ ' </small></h3><h2 class="text-center" id="site' + i1 + '_code"></h2></div>');
var OTP = generateOTP(mySites[i1].siteSeed);
var OTPstring = OTP.toString();
OTPstring = leftpad(OTPstring, 6, '0');
$(divID).text(OTPstring);
}
setInterval(autoUpdate, 1000);
}
function autoUpdate(base32secret)
{
var progressPercent;
var unixTime = Math.round(new Date().getTime() / 1000);
var countDown = 30 - (unixTime % 30);
progressPercent = (3.44827586207 * (30-countDown));
$(".moduloTime").text(countDown);
var progressPercentString = parseInt(progressPercent).toString();
progressPercentString = progressPercentString + "%";
$("#timerBar").width(progressPercentString);
if((unixTime % 30) >= 25)
{
$("#timerBar").addClass("progress-bar-danger");
for(var i1=0;i1<mySites.length;i1++)
{
var divID = "#site" + i1 + "_code";
$(divID).css("color","red");
}
}
if (unixTime % 30 == 0)
{
for(var i1=0;i1<mySites.length;i1++)
{
var divID = "#site" + i1 + "_code";
var OTP = generateOTP(mySites[i1].siteSeed);
var OTPstring = OTP.toString();
OTPstring = leftpad(OTPstring, 6, '0');
$(divID).text(OTPstring);
$(divID).css("color","black");
}
$(timerBar).removeClass("progress-bar-danger");
}
}
/*
* The actual function which processes the steps of obtaining the TOTP
*/
function generateOTP(base32secret)
{
var hexTime = get30Increment();
var hexKey = removeSpaces(base32secret);
hexKey = base32tohex(hexKey);
var keyTime = hasheyHashey(hexTime,hexKey);
return keyTime;
}
/*
* Counts the number of 30 second increments since the Unix Epoch
*/
function get30Increment()
{
var time = Math.round(new Date().getTime() / 1000);
var message = Math.floor(time/30).toString(16);
var hexMessage = '000000000' + message;//harded coded addition of 0s...needs to be dynamic. Deadline some time around year 2300
return hexMessage;
}
/*
* Computes the HMAC-SHA1 of the time and base32 seed. Utilises CryptoJS
*/
function hasheyHashey(messageHex,keyHex)
{
var messageWords = CryptoJS.enc.Hex.parse(messageHex);
var keyWords = CryptoJS.enc.Hex.parse(keyHex);
var hash = CryptoJS.HmacSHA1(messageWords,keyWords);
var hexHash = hash.toString(CryptoJS.enc.Hex);
/*
*GET THE LAST NIBBLE OFFSET VALUE
*/
var lastNibble =hexHash.substring(hexHash.length-1);
lastNibble = "0x" + lastNibble;
lastNibble = parseInt(lastNibble);
/*
* Truncate the HMAC-SHA1 output
*/
var truncation = hexHash.substr((lastNibble)*2,8);
var tempy = truncation;
truncation = "0x" + truncation;
truncation = parseInt(truncation);
truncation = 0x7FFFFFFF &truncation;
var OTP = truncation % 1000000;
return OTP;
}
/*String manipulation functions
* leftpad - padd the 'left side' of a string with a specific character to a specified length.
* base32tohex...exactly as it sounds, converts a base32 secret to hexidecimal
* removeSpaces - removes the spaces between segments of a secret. Spaces are usually added to aid in readability.
*/
function leftpad(str, len, pad)
{
if (len + 1 >= str.length)
{
//make an array of chars with enough pads at the start to make pad + str = len
str = new Array(len + 1 - str.length).join(pad) + str;
}
return str;
}
//I....I stole this from somewhere, don't recall where. If I can remember I will credit.
function base32tohex(base32)
{
var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
var bits = "";
var hex = "";
//convert to uppercase
for (var i = 0; i < base32.length; i++)
{
var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
bits += leftpad(val.toString(2), 5, '0');
}
//convert to hex in 4 character 'chunks'
for ( i = 0; i+4 <= bits.length; i+=4)
{
var chunk = bits.substr(i, 4);
hex = hex + parseInt(chunk, 2).toString(16) ;
}
return hex;
}
function removeSpaces(base32)
{
var str = base32.replace(/\s/g,"");
return str;
}