Last active
January 27, 2025 00:25
-
-
Save hstr0100/7c06d53f324faf4c1fe1299f7b4aa05e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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