Skip to content

Instantly share code, notes, and snippets.

@rcoh
Last active August 17, 2023 08:03
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save rcoh/c4dc45825a322881a9c1b300d70c3941 to your computer and use it in GitHub Desktop.
Save rcoh/c4dc45825a322881a9c1b300d70c3941 to your computer and use it in GitHub Desktop.
An implementation of Google Authenticator Compatible 2-factor Codes
"""
An implementation of TOTP as described in https://tools.ietf.org/html/rfc6238#section-4 aka Google Authenticator Style 2-factor Auth
"""
import base64
import datetime
import hashlib
import hmac
import sys
import struct
import time
from tqdm import tqdm
key_b32 = raw_input('Enter the secret (base32)')
key = base64.b32decode(key_b32.strip().upper())
# The time interval (TI) which defines the size of the chunks
T_INTERVAL = 30
def unixtime():
return int(time.time())
def code(now):
# TC is the the time chunk that we're a part of
time_chunk = int(now / T_INTERVAL)
# Per the spec, the time is represented as an 8-byte string in
# big endian. >q == big endian unsigned long
time_bytes = struct.pack('>q', time_chunk)
# The default hmac algorithm is md5!
hm = hmac.new(key, time_bytes, hashlib.sha1)
hex_digest = hm.hexdigest()
assert len(hex_digest) == 40
# Take the last 4 bits. These become the offset into the array
offset = int(hex_digest[-1:], 16)
# Take 4 bytes starting from the offset (in bytes). Our array is half-bytes
relevant_bytes = int(hex_digest[offset*2:offset*2+8], 16)
# Drop the highest order bit to work around platform issues
masked = relevant_bytes & 0x7FFFFFFF
num_digits = 6
final = masked % (10 ** num_digits)
final_str = str(final).zfill(6)
return final_str
if raw_input('Your current code is {}. Would you like a vanity code? y/n\n'.format(code(unixtime()))) == 'n':
sys.exit(0)
goal = raw_input('What do you want your two factor code to be?')
assert len(goal) == 6
start = unixtime()
num_tried = 0
# probably need to try about 1 million
pbar = tqdm(total=1000000)
while code(start) != goal:
pbar.update(1)
start += 30
pbar.close()
print('Your vanity 2-factor code will be available on: ')
print(
datetime.datetime.fromtimestamp(
start
).strftime('%Y-%m-%d %H:%M:%S')
)
@rcoh
Copy link
Author

rcoh commented Jan 8, 2018

note: tqdm (progress bar library is a dependency). pip install tqdm

@nosahama
Copy link

Cool, but the assert statements don't provide any form of feedback, what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment