Understanding OATH TOTP authentications

Bun-Ny TAN
5 min readNov 20, 2020

This article explains how OATH TOTP authentications work by describing the principles and intuitions behind them, and breaking down the TOTP value generation steps. The reader can try the commands in a ludic way using Google Authenticator and Python.

Principles and intuitions

TOTP (Time-based One-Time Password) algorithm is a HOTP (HMAC-based One-Time Password) algorithm extension. See my article dedicated to HOTP here: https://bntan.medium.com/understanding-oath-hotp-authentications-42dc6012c41d.

Like HOTP, TOTP is an OTP (One-Time Password) algorithm based on HMAC (Hash-based Message Authentication Code) but takes the current time as the counter. HMAC algorithm was published in February 1997 (in RFC-2104), HOTP algorithm was published in December 2005 (in RFC-4226), and TOTP algorithm was published in May 2011 (in RFC-6238).

TOTP is one OATH (Open Authentication) cornerstone. OATH is an industry-wide collaboration that aims to promote strong authentication by leveraging existing open standards. TOTP provides an authentication method by symmetrically generating (on user side and on server side) human-readable codes or values, each, based on the current time, can be used only once.

TOTP algorithm key principles

This article does not intent to describe in deep the cryptography operations, algorithms used but gives some intuitions behind them.

TOTP values are calculated by the operation TOTP (K) = HOTP(K,C) = truncate(HMAC(K,C)) mod 10^d where

  • K is the secret key which is kept secret and shared by the user (in a token/mobile) and by the server
  • C is the counter which is based on the current time (see below)
  • d is the TOTP value size

Current time counter

The current time counter is calculated by the operation C = (T - To) / Tx where

  • T is the current time (e.g. unix time)
  • To is the epoch (e.g. unix epoch is 0)
  • Tx is one time duration (time duration between 2 TOTP)

HMAC algorithm

where

  • K is the secret key
  • C is the counter
  • H is a hash algorithm
  • ipad is the block-sized inner padding which corresponds to repeated value 0x36
  • opad is the block-sized outer padding which corresponds to repeated value 0x5c
  • || denotes concatenation
  • + denotes bitwise exclusive or (XOR)

Truncate operation

The truncate operation consists in

  • Taking the HMAC low-order 4 bits
  • Using them as a byte index i
  • Selecting 4 bytes starting at byte index i
  • truncate(HMAC) = HMAC[i:i+4]

Here is a truncate operation example

-------------------------------------------------------------
| HMAC Byte Number |
-------------------------------------------------------------
|00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|
-------------------------------------------------------------
| HMAC Byte Value |
-------------------------------------------------------------
|1f|86|98|69|0e|02|ca|16|61|85|50|ef|7f|19|da|8e|94|5b|55|5a|
-------------------------------***********-----------------+-
  • HMAC low-order 4 bits is 0xa (see + underlining)
  • The byte index i is 10 = 0xa
  • The selected 4 bytes starting at index 10 are 0x50ef7f19 (see * underlining). This is the truncated HMAC

Let’s now generate HOTP values step by step in practice using:

  • Hash algorithm: SHA-1
  • Block size: 64 bytes
  • TOTP value size: 6
  • One time duration: 30 seconds
  • Secret key: ABCDEFGHIJKLMNOP (in base 32)

Prerequisites

Create the TOTP algorithm characteristics

hash_algorithm = "sha1"
block_size = 64
totp_value_size = 6
duration = 30

Create the secret key

secret_key = 'ABCDEFGHIJKLMNOP'

TOTP value generation with Google Authenticator

Google Authenticator is a 2FA (Two-Factor Authentication) application published by Google. It implements open standard TOTP.

Register the secret key (manually or by scanning QR code)

Generate the TOTP values during 2 minutes every 30 seconds

TOTP value generation with Python

The Python PyOTP library implements open standard TOTP. It can be used to generate registration QR codes, generate and validate TOTP values.

Generate the TOTP values during 2 minutes every 30 seconds

! pip install pyotp
import pyotp
import time
totp = pyotp.TOTP(secret_key)
for i in (range(4)):
totp_value = totp.now()
print('TOTP value corresponding to time ' + str(int(time.time())) + ' is ' + str(totp_value))
if (i < 3):
print(' Waiting '+ str(duration) + ' seconds ', end = '')
for j in range (duration):
print('.', end = '')
time.sleep(1)
print()
TOTP value corresponding to time 1604931390 is 389698
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931420 is 505916
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931450 is 262714
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931480 is 092212

The TOTP values are the same as the ones generated with Google Authenticator

Breaking down the TOTP value generation steps

import base64
import hashlib

Implement HMAC algorithm

def hmac(secret_key, counter):
i_pad = bytes((x ^ 0x36) for x in range(256))
o_pad = bytes((x ^ 0x5C) for x in range(256))
key_pad = secret_key.ljust(block_size, b'\0')
i_key_pad = key_pad.translate(i_pad)
o_key_pad = key_pad.translate(o_pad)
hash_sum_1 = hashlib.new(hash_algorithm, i_key_pad + counter).digest()
hash_sum_2 = hashlib.new(hash_algorithm, o_key_pad + hash_sum_1).digest()
hash = hash_sum_2
return hash

Implement truncation

def truncate(hash):
i = hash[-1] % 16
truncated = int.from_bytes(hash[i:i + 4], byteorder = 'big', signed = False) % 2 ** 31
return truncated

Implement TOTP algorithm

def totp():
hash = hmac(base64.b32decode(secret_key), int(time.time()/duration).to_bytes(8, byteorder = 'big'))
truncated = truncate(hash)
totp_value = truncated % 10 ** totp_value_size
return totp_value

Generate the TOTP values during 2 minutes every 30 seconds

for i in (range(4)):
totp_value = totp()
print('TOTP value corresponding to time ' + str(int(time.time())) + ' is ' + str(totp_value))
if (i < 3):
print(' Waiting '+ str(duration) + ' seconds ', end = '')
for j in range (duration):
print('.', end = '')
time.sleep(1)
print()
TOTP value corresponding to time 1604931390 is 389698
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931420 is 505916
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931450 is 262714
Waiting 30 seconds ..............................
TOTP value corresponding to time 1604931480 is 092212

The TOTP values are the same as the ones generated with Google Authenticator and Python PyOTP

--

--