Skip to content

Instantly share code, notes, and snippets.

@livingstonetech
Created April 29, 2019 07:16
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save livingstonetech/32ec98d94e809bbf1150a71d6210fe19 to your computer and use it in GitHub Desktop.
Save livingstonetech/32ec98d94e809bbf1150a71d6210fe19 to your computer and use it in GitHub Desktop.
Reference code to calculate TOTP, given a base32 secret.
#!/usr/bin/env python3
"""
Gist to calculate Time-based One Time Password (TOTP).
This function is designed to be used in two modes:
- Current Mode
No timestamp supplied, and the current timestamp is considered.
This mode gives the totp at the present moment in time.
- Historic Mode
Here an explicit timestamp is supplied. This is to calculate a TOTP
that had occured at a moment in history.
"""
import hashlib
import hmac
import time
import base64
import math
def calculate_totp(secret, unix_ts=None, power=6):
"""
The main function to calculate TOTP.
Parameters:
secret (str): Base32 secret for TOTP as string
unix_ts (int): Current or arbitrary unix timestamp as integer
power (int): Power of modulus. Essentially, the number of digits the
TOTP must have
Returns:
final_totp (int): Final calculated OTP as an integer.
Returns None if fails
"""
print("[+] Checking secret...")
if secret is None or secret == "":
print("---> [!] Secret is None or empty")
print("---> [!] Exiting...")
return None
try:
print("[+] Trying to convert secret to bytes")
secret_bytes = base64.b32decode(secret)
except Exception as e:
print("---> [!] Something unforeseen happened.")
print("---> [!] Error: {}".format(e))
print("---> [!] Exiting...")
return None
print("[+] Verified secret.")
if unix_ts is None:
print("[+] Mode:\tCurrent Mode")
unix_ts = int(time.time())
else:
print("[+] Mode:\tHistoric Mode")
print("[+] Using time:\t{}".format(int(unix_ts)))
current_time = math.floor(int(unix_ts) / 30)
print("[+] Calculating HMAC-SHA1 sum...")
try:
current_time_bytes = str(current_time).encode()
hmac_sha1_sum = hmac.new(secret_bytes,
msg=current_time_bytes,
digestmod=hashlib.sha1)
print("---> [+] HMAC-SHA1 sum:\t{}".format(hmac_sha1_sum.hexdigest()))
except Exception as e:
print("---> [!] Something unforeseen happened.")
print("---> [!] Error: {}".format(e))
print("---> [!] Exiting...")
return None
hmac_sha1_sum_int = int(hmac_sha1_sum.hexdigest(), 16)
print("---> [+] HMAC-SHA1 sum (int):\t{}".format(hmac_sha1_sum_int))
mod_power = 10 ** power
print("[+] Calculating TOTP with power:\t{}".format(mod_power))
temp_totp = hmac_sha1_sum_int % mod_power
print("[+] Checking if padding is required")
if temp_totp < (mod_power / 10):
print("---> [+] Padding OTP")
while temp_totp < (mod_power / 10):
temp_totp = temp_totp * 10
else:
print("---> [+] No padding required...")
final_otp = temp_totp
return final_otp
if __name__ == "__main__":
print("\n\n-------TESTS-------\n\n")
CURRENT_TIME_TOTP = calculate_totp("RPFYC5FREUVZ22I7")
print("[+] Current Time TOTP: {}".format(CURRENT_TIME_TOTP))
ARBITRARY_TIME_TOTP = calculate_totp("RPFYC5FREUVZ22I7",
unix_ts=829974000)
print("[+] Arbitrary Time TOTP: {}".format(ARBITRARY_TIME_TOTP))
# Output = 719686
ARBITRARY_POWER_TOTP = calculate_totp("RPFYC5FREUVZ22I7",
power=8)
print("[+] Arbitrary Time TOTP: {}".format(ARBITRARY_POWER_TOTP))
# Output = 25683649
ARBITRARY_ALL_TOTP = calculate_totp("RPFYC5FREUVZ22I7",
unix_ts=829974000,
power=4)
print("[+] Arbitrary All TOTP: {}".format(ARBITRARY_ALL_TOTP))
# Output = 9686
@livingstonetech
Copy link
Author

Sample Output

-------TESTS-------


[+] Checking secret...
[+] Trying to convert secret to bytes
[+] Verified secret.
[+] Mode:	Current Mode
[+] Using time:	1556530685
[+] Calculating HMAC-SHA1 sum...
---> [+] HMAC-SHA1 sum:	af36e8501ed3ffd5265b1f4d9b755fb47381fdad
---> [+] HMAC-SHA1 sum (int):	1000297862448795695855358663194777220994000092589
[+] Calculating TOTP with power:	1000000
[+] Checking if padding is required
---> [+] Padding OTP
[+] Current Time TOTP: 925890
[+] Checking secret...
[+] Trying to convert secret to bytes
[+] Verified secret.
[+] Mode:	Historic Mode
[+] Using time:	829974000
[+] Calculating HMAC-SHA1 sum...
---> [+] HMAC-SHA1 sum:	e94e53eec2130b7add2d08a4ac5baf8247231cc6
---> [+] HMAC-SHA1 sum (int):	1331941619292344778698566221244933340152790719686
[+] Calculating TOTP with power:	1000000
[+] Checking if padding is required
---> [+] No padding required...
[+] Arbitrary Time TOTP: 719686
[+] Checking secret...
[+] Trying to convert secret to bytes
[+] Verified secret.
[+] Mode:	Current Mode
[+] Using time:	1556530685
[+] Calculating HMAC-SHA1 sum...
---> [+] HMAC-SHA1 sum:	af36e8501ed3ffd5265b1f4d9b755fb47381fdad
---> [+] HMAC-SHA1 sum (int):	1000297862448795695855358663194777220994000092589
[+] Calculating TOTP with power:	100000000
[+] Checking if padding is required
---> [+] Padding OTP
[+] Arbitrary Time TOTP: 92589000
[+] Checking secret...
[+] Trying to convert secret to bytes
[+] Verified secret.
[+] Mode:	Historic Mode
[+] Using time:	829974000
[+] Calculating HMAC-SHA1 sum...
---> [+] HMAC-SHA1 sum:	e94e53eec2130b7add2d08a4ac5baf8247231cc6
---> [+] HMAC-SHA1 sum (int):	1331941619292344778698566221244933340152790719686
[+] Calculating TOTP with power:	10000
[+] Checking if padding is required
---> [+] No padding required...
[+] Arbitrary All TOTP: 9686

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