Skip to content

Instantly share code, notes, and snippets.

@acoster
Created November 20, 2012 22:45
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save acoster/4121786 to your computer and use it in GitHub Desktop.
Save acoster/4121786 to your computer and use it in GitHub Desktop.
TOTP module for Python.
#!/usr/bin/env python
"""Implementation of RFC 4226: HMAC-Based One-Time Password Algorithm (HTOP),
and RFC 6238: Time-Based One-Time Password Algorithm (TOTP).
"""
__author__ = 'acoster'
__copyright__ = 'Copyright 2012, Alexandre Coster'
import hmac
import time
import base64
import struct
import hashlib
def get_hotp(secret, counter):
"""Return the HMAC-Based One-Time Password for the the given secret (base32 encoded) and the counter.
>>> [get_hotp('GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ', i) for i in xrange(10)]
[755224, 287082, 359152, 969429, 338314, 254676, 287922, 162583, 399871, 520489]
"""
secret = base64.b32decode(secret)
counter = struct.pack('>Q', counter)
hash = hmac.new(secret, counter, hashlib.sha1).digest()
offset = ord(hash[19]) & 0xF
return (struct.unpack(">I", hash[offset:offset + 4])[0] & 0x7FFFFFFF) % 1000000
def get_totp(secret):
"""Return the Time-Based One-Time Password for the current time, and the provided secret (base32 encoded)
For obvious reasons, no unit-test is provided for this function.
"""
return get_hotp(secret, int(time.time()) // 30)
if __name__ == '__main__':
import doctest
doctest.testmod()
Copy link

ghost commented Nov 28, 2014

Thanks so much for sharing this - was about to write it - and saw you'd done the work for me!

@adamb70
Copy link

adamb70 commented Feb 11, 2016

Thanks for this, you saved me a good hour or two!

@kgupta786
Copy link

whenever i run this, it shows incorrect padding..

@dennislwy
Copy link

how to modify this code to take in 'digits' as parameter instead of now fixed at 6 digits

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