seansummers
4/6/2017 - 2:49 PM

Software TOTP

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())