Skip to content

Instantly share code, notes, and snippets.

@omerucel
Created October 20, 2023 16:00
Show Gist options
  • Save omerucel/e4254bd169445acb8ae3eef11eba694f to your computer and use it in GitHub Desktop.
Save omerucel/e4254bd169445acb8ae3eef11eba694f to your computer and use it in GitHub Desktop.
RFC 6238 TOTP: Time-Based One-Time Password Algorithm
"""
It is based on java implementation: https://datatracker.ietf.org/doc/html/rfc6238#appendix-A
"""
import datetime
import hashlib
import hmac
from typing import Callable
def main():
password = generate_password(seed="TEST", digest_mode=hashlib.sha512)
print(password)
def generate_password(seed: str, digest_mode: Callable, lifetime_sec: int = 30, size: int = 8):
seed = seed.encode("utf-8").hex()
T0 = 0
time_value = int(datetime.datetime.now().timestamp())
T = (time_value - T0) // lifetime_sec
steps = format(T, '016x').upper()
return generate_totp(seed, steps, size, digest_mode)
def generate_totp(seed: str, steps: str, return_digits: int, digest_mod: Callable):
while len(steps) < 16:
steps = "0" + steps
msg = bytes.fromhex(steps)
k = bytes.fromhex(seed)
hash_result = hmac.new(k, msg, digest_mod).digest()
offset = hash_result[-1] & 0xf
binary = (hash_result[offset] & 0x7f) << 24 | (hash_result[offset + 1] & 0xff) << 16 | (hash_result[offset + 2] & 0xff) << 8 | (hash_result[offset + 3] & 0xff)
otp = binary % 10 ** return_digits
return str(otp).zfill(return_digits)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment