Skip to content

Instantly share code, notes, and snippets.

@bbolli
Created August 21, 2014 13:36
Show Gist options
  • Save bbolli/d1ec564f31764326c137 to your computer and use it in GitHub Desktop.
Save bbolli/d1ec564f31764326c137 to your computer and use it in GitHub Desktop.
HOTP/TOTP one time password (RFC 4226/RFC 6238) implementation
"""HOTP/TOTP one time password (RFC 4226/RFC 6238) implementation"""
import hashlib
import hmac
import struct
def hotp(secret, counter, digits=6, alg=hashlib.sha1):
"""Calculate the HOTP value for the given secret and counter.
Secret and test values from appendix D of RFC 4226.
>>> s = '12345678901234567890'
>>> hotp(s, 0)
'755224'
>>> hotp(s, 1)
'287082'
>>> hotp(s, 2)
'359152'
>>> hotp(s, 3)
'969429'
>>> hotp(s, 4)
'338314'
>>> hotp(s, 5)
'254676'
>>> hotp(s, 6)
'287922'
>>> hotp(s, 7)
'162583'
>>> hotp(s, 8)
'399871'
>>> hotp(s, 9)
'520489'
>>> hotp(s, 4, digits=7) # check for leading zeros
'0338314'
"""
c = struct.pack('>Q', counter)
hash = hmac.new(secret, c, alg).digest()
offset = ord(hash[-1]) & 0x0F
result = hash[offset:offset+4]
result = struct.unpack('>L', result)[0] & 0x7FFFFFFF
result = result % 10 ** digits
return '%0*d' % (digits, result)
def _totp_counter(ts, timebase=0, timestep=30):
"""Calculate the TOTP counter for a given timestamp.
>>> ts = 1400000000; ts -= ts % 30 # let it start on a timestep
>>> base = _totp_counter(ts)
>>> base == _totp_counter(ts + 29)
True
>>> base != _totp_counter(ts + 30)
True
>>> base != _totp_counter(ts - 1)
True
>>> base != _totp_counter(ts, timebase=90)
True
>>> base == _totp_counter(ts + 90, timebase=90)
True
>>> base != _totp_counter(ts, timestep=60)
True
>>> base == _totp_counter(ts * 2, timestep=60)
True
"""
return int((ts - timebase) / timestep)
def totp(secret, ts=None, timebase=0, timestep=30, digits=6, alg=hashlib.sha1):
"""Calculate the TOTP value for a given timestamp."""
if ts is None:
import time
ts = time.time()
return hotp(secret, _totp_counter(ts, timebase, timestep), digits, alg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment