Google Authenticator and how it works?

Google Authenticator is the application based on two-factor Authentication (2FA) that helps for identifying user identity and the confirmation on what a user claims to be and whether he actually is.

The advantage over using 2FA over SMS based verification is that, your mobile sim can be stolen to a new phone using your social security number or the sms can be intercepted via your network provider because of security breaches. 2FA removes this possibility and totally depends on the device registered on it, irrespective of the network provider.

How Google Authenticator Works?

Google Authenticator is used for two-step verification based on Time-based One Time Password(TOTP) and HMAC-based One Time Password(HOTP) for authenticating users.

TOTP is an algorithm that computes a one-time password from a shared secret key and the current time.

HTOP is an algorithm which uses hmac algorithm to generate one-time password.

A simple pseudo code for generating otp is:

function GoogleAuthenticatorCode(string secret)
key := base32decode(secret)
message := floor(current Unix time / 30)
hash := HMAC-SHA1(key, message)
offset := last nibble of hash
truncatedHash := hash[offset..offset+3] //4 bytes starting at the offset
Set the first bit of truncatedHash to zero //remove the most significant bit
code := truncatedHash mod 1000000
pad code with 0 from the left until length of code is 6
return code
  1. Secret is the 16 digit token, generated by authenticator itself.
  2. Decode it in base32 (Allowing characters form [A-Z] and [0–9])
  3. Time used is the current epoch time and take the quotient when we divide it by 30. (30 is used as we need a new code every 30 seconds)
  4. Generate a hash using both of these. Hashing algorithm is HMAC-SHA1
  5. Choose the offset(last element of hash). Remove most significant bit. Take modulo with one million and append “0” in front, if needed.

Consider an example:

Consider our secret token is “dummySECRETdummy
Since for base32 decoding it requires characters in [A-Z], our key will be: “DUMMYSECRETDUMMY”.
Let’s consider current UNIX time is: 1523822557
Our message is int(1523822297/30): 50794085
Generated hash when encoded to string in base32 is: TEQI4DHFALLWYWX3JAXJAAGQGLLEGGOQ
truncatedHash is: 421563916
Taking modulo with 1000000 : 563916 (no padding needed in this case)
desire otp: 563916

Here is the simple go script to do the job:

func getHOTPToken(secret string, interval int64) string {
//Converts secret to base32 Encoding. Base32 encoding desires a 32-character
//subset of the twenty-six letters A–Z and ten digits 0–9
key, err := base32.StdEncoding.DecodeString(strings.ToUpper(secret))
check(err)
bs := make([]byte, 8)
binary.BigEndian.PutUint64(bs, uint64(interval))
//Signing the value using HMAC-SHA1 Algorithm
hash := hmac.New(sha1.New, key)
hash.Write(bs)
h := hash.Sum(nil)
// We're going to use a subset of the generated hash.
// Using the last nibble (half-byte) to choose the index to start from.
// This number is always appropriate as it's maximum decimal 15, the hash will
// have the maximum index 19 (20 bytes of SHA1) and we need 4 bytes.
o := (h[19] & 15)
var header uint32
//Get 32 bit chunk from hash starting at the o
r := bytes.NewReader(h[o : o+4])
err = binary.Read(r, binary.BigEndian, &header)
check(err)
//Ignore most significant bits as per RFC 4226.
//Takes division from one million to generate a remainder less than < 7 digits
h12 := (int(header) & 0x7fffffff) % 1000000
//Converts number as a string
otp := strconv.Itoa(int(h12))
return prefix0(otp)
}

The method getHOTPToken needs the secret and interval as its arguments.

func getTOTPToken(secret string) string {
//The TOTP token is just a HOTP token seeded with every 30 seconds.
interval := time.Now().Unix() / 30
return getHOTPToken(secret, interval)
}

This completes the script, as it takes the secret as input from a file and calculates interval from current time and generates otp. You can add more commands to copy it your clipboard.

If this generated otp doesn’t works for you you might want to check for your secret token or whether the time is in sync as per network time protocol(ntp).

ntpdate time.nist.gov

Run this command to sync time as per ntp.

You can find complete go program for this here. [https://github.com/tilaklodha/google-authenticator].
Gist here.