Software TOTP
'''
RFC4226 and RFC6238
otpauth://totp/$LABEL?secret=$SECRET
'''
import base64
import hashlib
import hmac
import time
def counter(timestep=30, epoch=0):
""" RFC6238 aka TOTP: the counter is based on time """
timestamp = int(time.time())
counter = (timestamp - epoch) // timestep
return format(counter, '016x').decode('hex')
def hotp(secret, counter, digits=6, constructor=hashlib.sha1):
""" RFC4226 aka HOTP """
key = base64.b32decode(secret)
hmac_sha1 = hmac.new(key, counter, constructor)
hash_ = hmac_sha1.digest()
offset = ord(hash_[-1]) & 0xf
data = hash_[offset:offset + 4]
otp = int(data.encode('hex'), 16)
result = otp & 0x7fffffff
return '{:06d}'.format(result)[-digits:]
if __name__ == '__main__':
# shared secret
secret = 'JBSWY3DPEHPK3PXP'
print hotp(secret, counter())
secret = 'L7DYDYMB5ZXHGHPJUW77QXXY6AY4ZTW7DZWNPV3YQOVXFX6HN4VNNDJQGIDJFDKY'
print hotp(secret, counter())