Tilak Lodha
Apr 17, 2018 · 4 min read
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. Decode it in base32 (Allowing characters form [A-Z] and [0–9])
  2. 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)
  3. Generate a hash using both of these. Hashing algorithm is HMAC-SHA1
  4. Choose the offset(last element of hash). Remove most significant bit. Take modulo with one million and append “0” in front, if needed.
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
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))
bs := make([]byte, 8)
binary.BigEndian.PutUint64(bs, uint64(interval))
//Signing the value using HMAC-SHA1 Algorithm
hash := hmac.New(sha1.New, key)
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)
//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)
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)
ntpdate time.nist.gov

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade