Skip to content

Instantly share code, notes, and snippets.

@rubenhorn
Last active June 23, 2021 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubenhorn/eb07959c162c754533793cd9951e774c to your computer and use it in GitHub Desktop.
Save rubenhorn/eb07959c162c754533793cd9951e774c to your computer and use it in GitHub Desktop.
Simple TOTP implementation using Python
#!/usr/bin/python3
import time, hashlib, hmac, base64
secret = 'q5ma qo4x irgv cm6k auai kjyv ak57 5keu'
T_0 = 0
X = 30
d = 6
K = base64.b32decode(secret.upper().replace(' ', ''))
def HMAC(K, C, block_size=64, output_size=20):
mac = hmac.new(K, C, hashlib.sha1).digest()
return mac
def DT(b):
offset = b[19] & 0xf
return b[offset:offset+4]
def HOTP(K, C):
global d
HS = HMAC(K, C.to_bytes(8, byteorder='big'))
DBC1 = int.from_bytes(DT(HS), byteorder='big')
DBC2 = DBC1 & 0x7fffffff
return DBC2 % (10**d)
def TOTP(K, timestamp):
global T_0, X
T = int((timestamp - T_0) / X)
return HOTP(K, T)
print(TOTP(K, int(time.time())))
#!/usr/bin/python3
import time, hashlib, hmac
secret = 'q5ma qo4x irgv cm6k auai kjyv ak57 5keu'
T_0 = 0
X = 30
d = 6
def b32tob(s):
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
values = [ALPHABET.index(d) for d in secret.upper().replace(' ', '').replace('=', 'A')]
count = int(len(s.replace(' ', '').replace('=', '')) * 5 / 8)
decoded = [0] * count
for i in range(len(values)):
bit_index = i * 5
byte_index = int(bit_index / 8)
byte_bit_index = bit_index - byte_index * 8
if byte_index < count:
decoded[byte_index] |= (values[i] << 3) >> byte_bit_index
if byte_index < count - 1:
decoded[byte_index+1] |= (values[i] << 3 + 8 - byte_bit_index) & 0xff
return bytes(bytearray(decoded))
K = b32tob(secret)
def HMAC(K, C, block_size=64, output_size=20):
mac = hmac.new(K, C, hashlib.sha1).digest()
return mac
def DT(b):
offset = b[19] & 0xf
return b[offset:offset+4]
def HOTP(K, C):
global d
HS = HMAC(K, C.to_bytes(8, byteorder='big'))
DBC1 = int.from_bytes(DT(HS), byteorder='big')
DBC2 = DBC1 & 0x7fffffff
return DBC2 % (10**d)
def TOTP(K, timestamp):
global T_0, X
T = int((timestamp - T_0) / X)
return HOTP(K, T)
def format_OTP(otp):
formatted = ''
for i in range(d):
if i % 3 == 0:
formatted += ' '
formatted += str(int(otp / 10**(d-i-1) % 10))
return formatted.strip()
otp = TOTP(K, int(time.time()))
print(format_OTP(otp))
#!/usr/bin/python3
import time, hashlib
secret = 'q5ma qo4x irgv cm6k auai kjyv ak57 5keu'
T_0 = 0
X = 30
d = 6
def b32tob(s):
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
values = [ALPHABET.index(d) for d in secret.upper().replace(' ', '').replace('=', 'A')]
count = int(len(s.replace(' ', '').replace('=', '')) * 5 / 8)
decoded = [0] * count
for i in range(len(values)):
bit_index = i * 5
byte_index = int(bit_index / 8)
byte_bit_index = bit_index - byte_index * 8
if byte_index < count:
decoded[byte_index] |= (values[i] << 3) >> byte_bit_index
if byte_index < count - 1:
decoded[byte_index+1] |= (values[i] << 3 + 8 - byte_bit_index) & 0xff
return bytes(bytearray(decoded))
K = b32tob(secret)
def sha1(b):
h = hashlib.new('sha1')
h.update(b)
return bytes.fromhex(h.hexdigest())
def HMAC(K, C, block_size=64, output_size=20):
xor = lambda a,b: bytes([_a ^ _b for _a, _b in zip(a, b)])
if len(K) > block_size:
K = sha1(K)
K = K + bytes(block_size - len(K))
opad = xor(K, 0x5C.to_bytes(1, byteorder='big') * block_size)
ipad = xor(K, 0x36.to_bytes(1, byteorder='big') * block_size)
mac= sha1(opad + sha1(ipad + C))
return mac
def DT(b):
offset = b[19] & 0xf
return b[offset:offset+4]
def HOTP(K, C):
global d
HS = HMAC(K, C.to_bytes(8, byteorder='big'))
DBC1 = int.from_bytes(DT(HS), byteorder='big')
DBC2 = DBC1 & 0x7fffffff
return DBC2 % (10**d)
def TOTP(K, timestamp):
global T_0, X
T = int((timestamp - T_0) / X)
return HOTP(K, T)
def format_OTP(otp):
formatted = ''
for i in range(d):
if i % 3 == 0:
formatted += ' '
formatted += str(int(otp / 10**(d-i-1) % 10))
return formatted.strip()
otp = TOTP(K, int(time.time()))
print(format_OTP(otp))
#!/usr/bin/python3
import time, sys
secret = 'q5ma qo4x irgv cm6k auai kjyv ak57 5keu'
T_0 = 0
X = 30
d = 6
SHA1_BLOCK_SIZE = int(512 / 8)
def b32tob(s):
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
values = [ALPHABET.index(d) for d in secret.upper().replace(' ', '').replace('=', 'A')]
count = int(len(s.replace(' ', '').replace('=', '')) * 5 / 8)
decoded = [0] * count
for i in range(len(values)):
bit_index = i * 5
byte_index = int(bit_index / 8)
byte_bit_index = bit_index - byte_index * 8
if byte_index < count:
decoded[byte_index] |= (values[i] << 3) >> byte_bit_index
if byte_index < count - 1:
decoded[byte_index+1] |= (values[i] << 3 + 8 - byte_bit_index) & 0xff
return bytes(bytearray(decoded))
K = b32tob(secret)
def sha1(b):
global SHA1_BLOCK_SIZE
def i_to_b(i, size):
offsets = [i * 8 for i in range(size)]
if sys.byteorder == 'little':
offsets.reverse()
return b''.join([((i >> o) & 0xff).to_bytes(1, byteorder='big') for o in offsets])
b_len = len(b) * 8
b += b'\x80'
while (len(b) + 8) % SHA1_BLOCK_SIZE != 0:
b += b'\0'
b += i_to_b(b_len, 8)
def left_rotate(w, count):
return ((w << count) | (w >> (32 - count))) & 0xffffffff
H = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
M = [b[i * SHA1_BLOCK_SIZE:(i+1) * SHA1_BLOCK_SIZE] for i in range(int(len(b) / SHA1_BLOCK_SIZE))]
def F(t, B, C, D):
if t <= 19:
return (B & C) | (~B & D)
elif t <= 39:
return B ^ C ^ D
elif t <= 59:
return (B & C) | (B & D) | (C & D)
else:
return B ^ C ^ D
def K(t):
if t <= 19:
return 0x5A827999
elif t <= 39:
return 0x6ED9EBA1
elif t <= 59:
return 0x8F1BBCDC
else:
return 0xCA62C1D6
for i in range(len(M)):
W = [0] * 80
for t in range(16):
b = M[i][t*4:(t+1)*4]
w = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0)
W[t] = w
for t in range(16, 80):
W[t] = left_rotate(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1)
(a, b, c, d, e) = H
for t in range(80):
temp = (left_rotate(a, 5) + F(t, b, c, d) + e + K(t) + W[t]) & 0xffffffff
e = d
d = c
c = left_rotate(b, 30)
b = a
a = temp
H = [(_a + _b) & 0xffffffff for _a, _b in zip(H, [a, b, c, d, e])]
return b''.join([_w.to_bytes(4, byteorder='big') for _w in H])
def HMAC(K, C):
global SHA1_BLOCK_SIZE
xor = lambda a,b: bytes([_a ^ _b for _a, _b in zip(a, b)])
if len(K) > SHA1_BLOCK_SIZE:
K = sha1(K)
K = K + bytes(SHA1_BLOCK_SIZE - len(K))
opad = xor(K, 0x5C.to_bytes(1, byteorder='big') * SHA1_BLOCK_SIZE)
ipad = xor(K, 0x36.to_bytes(1, byteorder='big') * SHA1_BLOCK_SIZE)
mac= sha1(opad + sha1(ipad + C))
return mac
def DT(b):
offset = b[19] & 0xf
return b[offset:offset+4]
def HOTP(K, C):
global d
HS = HMAC(K, C.to_bytes(8, byteorder='big'))
DBC1 = int.from_bytes(DT(HS), byteorder='big')
DBC2 = DBC1 & 0x7fffffff
return DBC2 % (10**d)
def TOTP(K, timestamp):
global T_0, X
T = int((timestamp - T_0) / X)
return HOTP(K, T)
def format_OTP(otp):
formatted = ''
for i in range(d):
if i % 3 == 0:
formatted += ' '
formatted += str(int(otp / 10**(d-i-1) % 10))
return formatted.strip()
otp = TOTP(K, int(time.time()))
print(format_OTP(otp))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment