Google Authenticator Soft Token Generator
Problem this snippet solves:
iRule to generate Google Authenticator soft tokens for use with the Google Authenticator iRule For Two-Factor Auth With LDAP. Add to pool-less HTTP virtual server and access from browser.
Code :
when HTTP_REQUEST {
set account [URI::query [HTTP::uri] "account"]
set domain [URI::query [HTTP::uri] "domain"]
set secret [URI::query [HTTP::uri] "secret"]
set qr_code [URI::query [HTTP::uri] "qr_code"]
if { ([HTTP::path] starts_with "/ga_secret_generator") && ($account ne "") && ($domain ne "") } {
if { [string length $secret] <= 10 } {
set secret [b64encode [md5 [expr rand()]]]
}
set secret [string range $secret 0 9]
array set b32_alphabet_inv {
0 A 1 B 2 C 3 D
4 E 5 F 6 G 7 H
8 I 9 J 10 K 11 L
12 M 13 N 14 O 15 P
16 Q 17 R 18 S 19 T
20 U 21 V 22 W 23 X
24 Y 25 Z 26 2 27 3
28 4 29 5 30 6 31 7
}
set secret_b32 ""
set l [string length $secret]
set n 0
set j 0
# encode loop is outlined in RFC 4648 (http://tools.ietf.org/html/rfc4648#page-8)
for { set i 0 } { $i < $l } { incr i } {
set n [expr $n << 8]
set n [expr $n + [scan [string index $secret $i] %c]]
set j [incr j 8]
while { $j >= 5 } {
set j [incr j -5]
append secret_b32 $b32_alphabet_inv([expr ($n & (0x1F << $j)) >> $j])
}
}
# pad final input group with zeros to form an integral number of 5-bit groups, then encode
if { $j > 0 } { append secret_b32 $b32_alphabet_inv([expr $n << (5 - $j) & 0x1F]) }
# if the final quantum is not an integral multiple of 40, append "=" padding
set pad [expr 8 - [string length $secret_b32] % 8]
if { ($pad > 0) && ($pad < 8) } { append secret_b32 [string repeat = $pad] }
set ga_qr_code_link "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/"
append ga_qr_code_link "$account@$domain"
append ga_qr_code_link "%3Fsecret%3D"
append ga_qr_code_link $secret_b32
set ga_secret_http_resp {
}
if { $qr_code eq "yes" } {
append ga_secret_http_resp "
\n"
}
append ga_secret_http_resp " account: $account@$domain"
append ga_secret_http_resp "key (secret): $secret_b32
\n \n \n"
HTTP::respond 200 content $ga_secret_http_resp
} else {
HTTP::respond 200 content {
Google Authenticator key (shared secret) generator
}
}
}6 Comments
- Bill_Chipman_10
Nimbostratus
I don't see where you store the secret so it can be inserted in the datagroup or other wise used on the F5 after the secret is generated. - Simon_Waters_13
Cirrostratus
We were reviewing the code for this as we think:
set secret [b64encode [md5 [expr rand()]]] set secret [string range $secret 0 9]
Is suspect, as base 64 is 6 bits a character, and 10 lots of 6 bits is 60bits, when Google Authenticator uses 80 bits of entropy (16 x base 32 = 80 bits), and the RFC recommends 160 bits as minimum.
Not sure this undermines Google Authenticator quite, but it must make brute force and similar attacks at least a million times more feasible.
- Simon_Waters_13
Cirrostratus
We are looking at something like:
set secret [ CRYPTO::keygen -alg random -len 256 ]
set secret [ call base32encode $secret ]
set secret [ string range $secret 0 31 ]
- lcpWidgit
Nimbostratus
FYI Warning: This API is deprecated.
https://developers.google.com/chart/infographics/docs/qr_codes
https://chart.googleapis.com/chart?
Hi Folks,
I recommend to adopt the approach outlined here...
https://dan.hersam.com/tools/gen-qr-code.html
... it does not depend on external APIs to generate a given QR code.
Minimalistic version with inline JScripts:
Your TOTP QR Code is:Cheers, Kai
- Vikrant_17
Nimbostratus
how can we generate a QR locally instead of using the google APIs ?