Skip to content

Instantly share code, notes, and snippets.

@hstr0100
Last active January 27, 2025 00:25
Show Gist options
  • Save hstr0100/7c06d53f324faf4c1fe1299f7b4aa05e to your computer and use it in GitHub Desktop.
Save hstr0100/7c06d53f324faf4c1fe1299f7b4aa05e to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# Basic HOTP / TOTP Generator using integers or strings as seeds
#
# Requirements:
# * Python 3
# * pyotp library (pip install pyotp)
#
# Usage:
# python token.py
#
# Try entering the seed in 'string' mode if 'integer' fails.
#
import pyotp
import time
import base64
# Function to generate HOTP or TOTP
def generate_otp(secret_seed, choice, counter_or_time=None):
# Convert the secret seed (integer) to a byte string and then encode it in base32
if isinstance(secret_seed, int):
# Endianess might be wrong. If this script fails to generate a valid code for your use case, change the byteorder from 'big' to 'little'.
secret_bytes = secret_seed.to_bytes((secret_seed.bit_length() + 7) // 8, byteorder='big')
else:
# If it's in string mode, simply encode it
secret_bytes = secret_seed.encode('utf-8')
secret_base32 = base64.b32encode(secret_bytes).decode('utf-8').strip('=')
print(f"Base32: {secret_base32}")
if choice == 'HOTP' and counter_or_time is not None:
# HOTP: Requires a counter
totp = pyotp.HOTP(secret_base32)
otp = totp.at(counter_or_time) # For HOTP use counter
print(f"HOTP: {otp}")
elif choice == 'TOTP':
# TOTP: Uses the current time (based on 30-second intervals)
totp = pyotp.TOTP(secret_base32)
otp = totp.now() # For TOTP use the current time
print(f"TOTP: {otp}")
else:
print("Invalid input, please enter 'HOTP' or 'TOTP'.")
# Function to input and validate the seeds
def input_seeds():
while True:
seed_type = input("Would you like to use an integer or a string as the secret key? (Enter 'integer' or 'string'): ").strip().lower()
if seed_type == 'integer':
try:
secret_seed = int(input("Enter the secret key (integer): "))
return secret_seed # Return as integer
except ValueError:
print("Invalid input. Please enter a valid integer.")
elif seed_type == 'string':
secret_seed = str(input("Enter the secret key (string): "))
return secret_seed # Return as string
else:
print("Invalid choice. Please enter 'integer' or 'string'.")
def main():
print("OATH HOTP/TOTP OTP Generator")
# Ask user whether to generate HOTP or TOTP first
choice = input("Would you like to generate HOTP or TOTP? (Enter 'HOTP' or 'TOTP'): ").strip().upper()
if choice == 'HOTP':
secret_seed = input_seeds()
counter = int(input("Enter the counter (integer): ")) # HOTP requires a counter
generate_otp(secret_seed, choice, counter)
elif choice == 'TOTP':
secret_seed = input_seeds()
generate_otp(secret_seed, choice) # TOTP doesn't need a counter
else:
print("Invalid choice. Please enter 'HOTP' or 'TOTP'.")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment