Exploring OTP

SecretShared Access to web application is controlled by a Username and password. At times we can see some websites requesting for OTP or one time password. A code in app ,SMS, Email. This works like an additional layer to prove user identity.

In this blog post will be exploring how OTP works. Exploring what standard says about this and few implementations.

Here is what's in rest of the blog,

RFC reference to OTP

10000 feet view

How HOTP and TOTP is implemented as per RFC

Lets implement OTP using pyOTP

YouTube Video


RFC note

Two major OTP implementations are defined in RFC. HOTP as described in RFC4226 and TOTP described in RFC6238. HOTP – HMAC based one time password – Code is generated at server end only – When prompted for OTP, the code is sent to user(SMS/Email). TOTP – Time based one time password – Code is generated at user end and server.Time is used as counter here.
– When prompted for OTP, the code generated at user end is verified against the code generated at server end. Avoids storing mobile numbers at server end to send SMS.


10000 Feet View

OTP overview When someone signs up for OTP, a secret is shared with user, as a barcode or as a text. This text/barcode is added to a authenticator app(Authy, Google Authenticator etc). App generates a unique code which is in sync with code generated at server. When user enters the code, this is validated at server and if its a match, Access granted!!.


Implementation Details

SecretShared Let's explore how HOTP and TOTP is implemented according to RFC's. HOTP uses HMAC -SHA1 algorithm to generate random string. This random string is truncated so that it's suitable for use.

How HOTP validates code, given a secret HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)) C – 8bit counter K – Shared secret between client and server The HOTP value is truncated so that it can be used as one time password. OTP = { HOTP modulo (10^ Digits)} Digits – number of digits in OTP Check this Example code in RFC

How TOTP validates code, The main difference here, is that “Time” is used as counter. Unixtime is used as counter. Idea of using unix time is avoid errors due to timezone. Unixtime is the number of seconds elapsed since midnight UTC of January 1, 1970. Example: Unixtime for 26 July 2020 11:30:30 is 1595763030. Time counter in TOTP changes every 30 seconds. Value '30' is defined in RFC. This is a balance between usuability and security. So that user does not wait too long for a new code or attacker is given enough time to brute force codes.

Counter = T = (Current Unixtime – T0 /X)
T0 is the Unix time to start counting time steps (default value is 0, i.e., the Unix epoch) RFC 6238
X represents the time step in seconds (default value X = 30 seconds)(RFC reference)RFC 6238. This ensures OTP changes every 30 seconds. TOTP uses HOTP algorithm as basic building block,

TOTP = HOTP {K,T}.
K – secret key
T – Counter

OTPFLOW

To summarise,

When a user is prompted to enter OTP, code from authenticator app is entered. This is sent to server. Remember this code is generated with current unixtime on user device and sent to server. Now at server end, the code is generated based on current unixtime at server and compared with code sent by client. There may be some time lag between the time when code is generated at client and time when code is generated at server. This should be within 30 seconds.

Python implementation of OTP

There is a python module which implements OTP as per RFC. pyOTP is a python implementation of OTP according to RFC4226 and RFC6238.

PyOTP

Demo on TOTP ,

Let's explore how we can use pyotp to implement this.

Generate unique code

Below is a sample code which generates secret string, gives an output which can be used to generate barcode and shows how HOTP codes are generated with counter. code1

import pyotp

SecureString = pyotp.random_base32()
#Generate secure string to be shared with user

key = pyotp.TOTP(SecureString)
    
a=pyotp.totp.TOTP(SecureString).provisioning_uri(name='batman@google.com', issuer_name= 'NotesOTP')

#Convert unique string to barcode, output will be used in QRious to generate QR code.

print(" Secure Code is: ", SecureString)
print ("\n For QR Code use this -->: ", a)
print("\n TOTP is : ",key.now())

#Counter based OTP - HOTP
SecureString_H = pyotp.random_base32()
key_hotp = pyotp.HOTP(SecureString)

print("\n HOTP at 0 :", key_hotp.at(0))
print("\n HOTP at 1 :", key_hotp.at(1))
print("\n HOTP at 2 :", key_hotp.at(2))

Output of this code Output

ServerCode to Validate

OTP_code

import pyotp
import time

#Server code to validate
key = pyotp.TOTP('ENXXHOWWQ425QHJZ')
while(True):
    otp = key.now()
    localtime = time.localtime()
    result = time.strftime("%I:%M:%S %p", localtime)
    print(result, otp, end="", flush=True)
    print("\r", end="", flush=True)
    time.sleep(1)

Once we have these two scripts, lets generate QR code , Go ahead and scan this, QRCode

--snip--
a=pyotp.totp.TOTP(SecureString).provisioning_uri(name='batman@google.com', issuer_name= 'NotesOTP')

#Output
>>> print (a)
>>> otpauth://totp/NotesOTP:batman%40google.com secret=ENXXHOWWQ425QHJZ&issuer=NotesOTP

Scan Code with an authenticator app on phone Scan Code

Code Sync Sync_01

Second Code Sync sync_02

Validate code in authenticator app using this script –> Servercode to validate


References

#OTP,#TOTP,#HOTP,


— By Fabian Darius