For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

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

account: @
secret: *optional 10 character key (additional chars truncated), random secret used if blank
generate QR code? *a request will be made to Google to generate QR code
} } }
Published Mar 17, 2015
Version 1.0

6 Comments

  • 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.
  • 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.

     

  • 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 ]

     

  • how can we generate a QR locally instead of using the google APIs ?