This repository has been archived on 2025-05-08. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
python-oneliners/TOTP/totp.py
2018-10-22 21:15:06 +02:00

38 lines
1.3 KiB
Python

import base64
import hashlib
import hmac
import random
import time
class TOTP:
def __init__(self, secret: str):
self.secret = secret
def now(self) -> str:
return self.at(int(time.time() / 30))
def at(self, for_time: int) -> str:
secret = base64.b32decode(self.secret)
hmac_hash = hmac.HMAC(secret, for_time.to_bytes(8, 'big'), hashlib.sha1).digest()
offset = hmac_hash[-1] & 0xf
code = ((hmac_hash[offset] & 0x7f) << 24 |
(hmac_hash[offset + 1] & 0xff) << 16 |
(hmac_hash[offset + 2] & 0xff) << 8 |
(hmac_hash[offset + 3] & 0xff))
out = str(code % 10 ** 6)
return "0" * (6 - len(out)) + out
def verify(self, code: str, valid_window: int = 0) -> bool:
for_time = int(time.time() / 30)
for i in range(-valid_window, valid_window + 1):
if self.at(for_time + i) == code.replace(" ", ""):
return True
return False
def generate_uri(self, user: str, issuer: str) -> str:
return "otpauth://totp/%s?secret=%s&issuer=%s" % (user, self.secret.lower(), issuer)
@staticmethod
def generate_random():
return TOTP("".join([random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") for _ in range(16)]))