def base32_decode(key, casefold=True): padlen = len(key) % 8 if isinstance(key, str): key = hmac.str2unicode(key) if (padlen > 0): key += b'=' * (8 - padlen) return base64.b32decode(key, casefold=casefold)
def HOTP(key, interval, digest=hashlib.sha1, token_len=6): # encode interval in unicode if needed interval = hmac.str2unicode(interval) # encode interval as unsigned int interval = interval if (isinstance(interval, bytes)) else struct.pack( ">Q", interval) # compute HMAC-SHA-1 digest (20 bytes) hmac_hash = hmac.HMAC(key, interval, digest_function=digest) # compute Dynamic Truncation on the hmac value try: hotp = DT(hmac_hash) except RuntimeError as dt_exe: raise dt_exe # return hotp value return modulo(hotp, token_len=token_len)
def TOTP(key, timecounter=0, digest=hashlib.sha1, timestep=TS, timebase=EPOCH, encode_base32=True, casefold=True, token_len=6): # normalize and convert key in proper format key = normalize(key) # convert to unicode bytestring key = hmac.str2unicode(key) # google wants the key to be base32 encoded... if (encode_base32): key = base32_decode(key, casefold=casefold) # compute timestamp and convert value in unsigned 64 bit integer T0 = timebase # unix epoch in RFC if timecounter == 0: now = floor(float(time() - T0) / timestep) else: now = floor(timecounter / timestep) # encode TC as unsigned 64bit integer tc = struct.pack(">Q", now) # compute HOTP(key, TC) totp_value = hotp.HOTP(key, tc, digest=digest, token_len=token_len) # HOTP result is an integer resulting from a modulo operation: check for result length # if less than 'token_len', left-pad with zeroes l = len(str(totp_value)) if (l < token_len): totp_value = '0' * (token_len - l) + str(totp_value) # return totp value return totp_value