Skip to content

Commit a52f3f0

Browse files
committedFeb 25, 2020
first commit
0 parents  commit a52f3f0

File tree

6 files changed

+244
-0
lines changed

6 files changed

+244
-0
lines changed
 

‎.gitignore

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.dub
2+
docs.json
3+
__dummy.html
4+
docs/
5+
/gauthenticator
6+
gauthenticator.so
7+
gauthenticator.dylib
8+
gauthenticator.dll
9+
gauthenticator.a
10+
gauthenticator.lib
11+
gauthenticator-test-*
12+
*.exe
13+
*.o
14+
*.obj
15+
*.lst
16+
secret.pem

‎dub.sdl

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name "gauthenticator"
2+
description "Act as google authenticator device"
3+
authors "Andrea Manzini"
4+
copyright "Copyright © 2020, Andrea Manzini"
5+
license "mit"
6+
targetType "library"
7+

‎dub.selections.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"fileVersion": 1,
3+
"versions": {
4+
}
5+
}

‎readme.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Google Authenticator
2+
A small D program to generate the google authenticator code.
3+
4+
inspired from https://github.com/tilaklodha/google-authenticator
5+
6+
- Install D Language https://dlang.org/
7+
- Install Dub package manager
8+
- On OSX run `brew install dub`.
9+
- Follow instructions on https://code.dlang.org/ for other OSes.
10+
11+
- Provide your 16-digit secret token in secrets.pem file
12+
13+
The auth code works on the secret token and the current time. The time on your local machine should be in sync according to NTP.
14+
15+
- Run `sudo ntpdate time.nist.gov` to sync time
16+
- Run `rdmd example\runme.d`.
17+

‎source/base32_test.d

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
module base32_test;
2+
3+
import std.stdio;
4+
5+
6+
public int[] base32decode(const string message)
7+
{
8+
int buffer = 0;
9+
int bitsLeft = 0;
10+
int[] result;
11+
for (int i = 0; i < message.length; i++)
12+
{
13+
int ch = message[i];
14+
writeln(ch);
15+
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-')
16+
{
17+
continue;
18+
}
19+
buffer <<= 5;
20+
21+
// Deal with commonly mistyped characters
22+
if (ch == '0')
23+
{
24+
ch = 'O';
25+
}
26+
else if (ch == '1')
27+
{
28+
ch = 'L';
29+
}
30+
else if (ch == '8')
31+
{
32+
ch = 'B';
33+
}
34+
35+
// Look up one base32 digit
36+
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
37+
{
38+
ch = (ch & 0x1F) - 1;
39+
}
40+
else if (ch >= '2' && ch <= '7')
41+
{
42+
ch -= '2' - 26;
43+
}
44+
45+
buffer |= ch;
46+
bitsLeft += 5;
47+
if (bitsLeft >= 8)
48+
{
49+
result ~= (buffer >> (bitsLeft - 8));
50+
bitsLeft -= 8;
51+
}
52+
53+
}
54+
return result;
55+
56+
}
57+
58+
void main() {
59+
writeln("ciao");
60+
61+
62+
auto expected = cast(int[]) "FOOBAR";
63+
writeln(base32decode("IZHU6QSBKIFA===="));
64+
writeln(expected);
65+
}

‎source/gauthenticator.d

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/+
2+
MIT License
3+
Copyright (c) 2020 Andrea Manzini
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18+
SOFTWARE.
19+
+/
20+
21+
module gauthenticator;
22+
23+
import std.stdio;
24+
25+
class GAuthenticator
26+
{
27+
28+
// HMAC-based One Time Password(HOTP)
29+
public string getHOTPToken(const string secret, const ulong interval)
30+
{
31+
/*
32+
auto key=base32decode(secret);
33+
hash = HMAC-SHA1(key)
34+
offset = last nibble of hash
35+
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
36+
Set the first bit of truncatedHash to zero //remove the most significant bit
37+
code := truncatedHash mod 1000000
38+
pad code with 0 from the left until length of code is 6
39+
return code */
40+
41+
return "000000";
42+
}
43+
44+
//Time-based One Time Password(TOTP)
45+
public string getTOTPToken(const string secret)
46+
{
47+
//The TOTP token is just a HOTP token seeded with every 30 seconds.
48+
import std.datetime : Clock;
49+
50+
immutable ulong interval = Clock.currTime().toUnixTime() / 30;
51+
return getHOTPToken(secret, interval);
52+
}
53+
54+
//RFC 4648
55+
public int[] base32decode(const string message)
56+
{
57+
int buffer = 0;
58+
int bitsLeft = 0;
59+
int[] result;
60+
for (int i = 0; i < message.length; i++)
61+
{
62+
int ch = message[i];
63+
writeln(ch);
64+
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-')
65+
{
66+
continue;
67+
}
68+
buffer <<= 5;
69+
70+
// Deal with commonly mistyped characters
71+
if (ch == '0')
72+
{
73+
ch = 'O';
74+
}
75+
else if (ch == '1')
76+
{
77+
ch = 'L';
78+
}
79+
else if (ch == '8')
80+
{
81+
ch = 'B';
82+
}
83+
84+
// Look up one base32 digit
85+
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
86+
{
87+
ch = (ch & 0x1F) - 1;
88+
}
89+
else if (ch >= '2' && ch <= '7')
90+
{
91+
ch -= '2' - 26;
92+
}
93+
94+
buffer |= ch;
95+
bitsLeft += 5;
96+
if (bitsLeft >= 8)
97+
{
98+
result ~= (buffer >> (bitsLeft - 8));
99+
bitsLeft -= 8;
100+
}
101+
102+
}
103+
return result;
104+
105+
}
106+
107+
unittest
108+
{
109+
const base32 = "gr6d 5br7 25s6 vnck v4vl hlao re======";
110+
111+
}
112+
113+
/*
114+
unittest
115+
{
116+
auto ga = new GAuthenticator;
117+
auto secret = "dummySECRETdummy";
118+
auto interval = ulong(50780342);
119+
auto otp = "971294";
120+
assert(otp == ga.getHOTPToken(secret, interval));
121+
}
122+
*/
123+
124+
}
125+
126+
unittest
127+
{
128+
writeln("ciao");
129+
130+
auto ga = new GAuthenticator();
131+
auto expected = cast(int[]) "FOOBAR";
132+
writeln(ga.base32decode("IZHU6QSBKIFA===="));
133+
writeln(expected);
134+
}

0 commit comments

Comments
 (0)
Please sign in to comment.