mirror of
https://github.com/adulau/hotp-js.git
synced 2024-12-22 08:46:10 +00:00
A quick-and-dirty implementation of HOTP (RFC 4226) in Javascript.
This commit is contained in:
commit
df149b65f6
2 changed files with 134 additions and 0 deletions
33
example.html
Normal file
33
example.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="http://crypto-js.googlecode.com/files/2.0.0-crypto-sha1.js"></script>
|
||||||
|
<script type="text/javascript" src="http://crypto-js.googlecode.com/files/2.0.0-hmac-min.js"></script>
|
||||||
|
<script type="text/javascript" src="http://www.foo.be/hotp/hotp/hotp.js"></script>
|
||||||
|
<title>HOTP Sample Test Page in Javascript</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>HOTP Sample Test Page in Javascript</h1>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
//document.write(hotp("505FAB31EDDE28AAC73F3531771758A2C5CF9730","4008","hex40"));
|
||||||
|
//document.write(" ");
|
||||||
|
//document.write(hotp("505FAB31EDDE28AAC73F3531771758A2C5CF9730","4008","dec6"));
|
||||||
|
|
||||||
|
document.write("test vector from RFC 4226 for token key : 0x3132333435363738393031323334353637383930<br/>");
|
||||||
|
for (var i=0; i<10; i++) {
|
||||||
|
document.write("count: "+i);
|
||||||
|
document.write(" hex40 (used in ootp): ");
|
||||||
|
document.write(hotp("3132333435363738393031323334353637383930",i,"hex40"));
|
||||||
|
document.write(" HOTP value: ");
|
||||||
|
document.write(hotp("3132333435363738393031323334353637383930",i,"dec6"));
|
||||||
|
document.write("<br />");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<a href="http://www.gitorious.org/hotp-js">demo of hotp-js - source code available at http://www.gitorious.org/hotp-js</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
101
hotp/hotp.js
Normal file
101
hotp/hotp.js
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
A simple Javascript HOTP implementation (HMAC-Based One-Time Password Algorithm) as described in RFC 4226.
|
||||||
|
|
||||||
|
The library is relying on crypto-js (http://code.google.com/p/crypto-js/) for the javascript HMAC-SHA1 implementation.
|
||||||
|
|
||||||
|
The library can be used to create software token (don't forget to protect the key of the token...).
|
||||||
|
|
||||||
|
If you want to use the library, you'll need to load the crypto-js (sha1 and hmac) and hotp.js.
|
||||||
|
|
||||||
|
Calling the library is easy, you just have to set the hex key of the token, the counter plus the output format.
|
||||||
|
|
||||||
|
otp = hotp("3132333435363738393031323334353637383930","4","dec6");
|
||||||
|
|
||||||
|
Current output formats are : hex40 (format used by ootp, a free software library) and dec6 (the 6 decimal digit as described in the RFC 4226).
|
||||||
|
|
||||||
|
A demo page with the test vector of the RFC 4226 : http://www.foo.be/hotp/example.html*
|
||||||
|
|
||||||
|
http://www.gitorious.org/hotp-js/
|
||||||
|
|
||||||
|
Copyright (C) 2009 Alexandre Dulaunoy
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function hotp(key, counter, format) {
|
||||||
|
|
||||||
|
function hotp_hexkeytobytestream(s) {
|
||||||
|
// s is the key to be converted in bytes
|
||||||
|
var b = new Array();
|
||||||
|
var last = s.length;
|
||||||
|
for (var i = 0; i < last; i = i + 2) {
|
||||||
|
var x = s[i] + s[i + 1];
|
||||||
|
x.toUpperCase();
|
||||||
|
x = "0x" + x;
|
||||||
|
x = parseInt(x);
|
||||||
|
b[i] = String.fromCharCode(x);
|
||||||
|
}
|
||||||
|
var ret = new String();
|
||||||
|
ret = b.join('');
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
function hotp_movingfactortohex(count) {
|
||||||
|
// count is the moving factor in OTP to be converted in bytes
|
||||||
|
v = decimaltohex(count, 16);
|
||||||
|
var decb = new Array();
|
||||||
|
lhex = Crypto.util.hexToBytes(v);
|
||||||
|
for (var i = 0; i < lhex.length; i++) {
|
||||||
|
decb[i] = String.fromCharCode(lhex[i]);
|
||||||
|
}
|
||||||
|
var retval = new String();
|
||||||
|
retval = decb.join('');
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decimaltohex(d, padding) {
|
||||||
|
// d is the decimal value
|
||||||
|
// padding is the padding to apply (O pad)
|
||||||
|
var hex = Number(d).toString(16);
|
||||||
|
padding = typeof(padding) === "undefined" || padding === null ? padding = 2 : padding;
|
||||||
|
while (hex.length < padding) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function truncatedvalue(h, p) {
|
||||||
|
// h is the hash value
|
||||||
|
// p is precision
|
||||||
|
offset = h[19] & 0xf;
|
||||||
|
v = (h[offset] & 0x7f) << 24 | (h[offset + 1] & 0xff) << 16 | (h[offset + 2] & 0xff) << 8 | (h[offset + 3] & 0xff);
|
||||||
|
v = "" + v;
|
||||||
|
v = v.substr(v.length - p, p);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hmacBytes = Crypto.HMAC(Crypto.SHA1, Crypto.charenc.Binary.stringToBytes((hotp_movingfactortohex(counter))), Crypto.charenc.Binary.stringToBytes(hotp_hexkeytobytestream(key)));
|
||||||
|
|
||||||
|
if (format == "hex40") {
|
||||||
|
return hmacBytes.substring(0, 10);
|
||||||
|
} else if (format == "dec6") {
|
||||||
|
return truncatedvalue(Crypto.util.hexToBytes(hmacBytes), 6);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "unknown format";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue