Skip to content

Instantly share code, notes, and snippets.

@shellfly
Forked from mtigas/README.mdown
Last active August 29, 2015 14:22
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 shellfly/30d3f41edce68e023225 to your computer and use it in GitHub Desktop.
Save shellfly/30d3f41edce68e023225 to your computer and use it in GitHub Desktop.
TOTP (Google Authenticator) two-factor auth proof of concept.

Depends on http://github.com/bdauvergne/python-oath

pip install -e "git://github.com/bdauvergne/python-oath.git#egg=oath-dev"

1: Generate key, install key

Generate a secret key (and for fun, the QR code URL that can be imported by the Google Authenticator scanner) with gen_google_code.py.

See http://www.google.com/support/accounts/bin/answer.py?answer=1066447 for what to do with this.

2: Attempt to authenticate

Then, use check_auth.py like this:

check_auth.py [secret] [code_from_authenticator]

Example

$ python gen_google_code.py
Hex secret: 229249c943c32afca61b
...base32:  EKJETSKDYMVPZJQ3

===== Google URL =====
Scan this with Google Authenticator or enter the base32
value above as 'key' when manually adding.
    https://chart.googleapis.com/chart?chl=otpauth%3A%2F%2Ftotp%2FPC1168-miket.local%3Fsecret%3DEKJETSKDYMVPZJQ3&chs=200x200&cht=qr&chld=M%7C0

(See http://www.google.com/support/accounts/bin/answer.py?answer=1066447 )

Example of a valid auth:

$ python check_auth.py 229249c943c32afca61b 123456
(True, 0)

Example of an invalid auth:

$ python check_auth.py 229249c943c32afca61b 987654
(False, 0)
from oath import totp, accept_totp
import sys
if __name__ == "__main__":
if len(sys.argv) < 3:
print "Usage:"
print "check_auth.py [secret] [code_from_authenticator]"
sys.exit(1)
secret = sys.argv[1]
code = sys.argv[2]
print accept_totp(secret, code, "dec6")
from base64 import b32encode
from binascii import hexlify, unhexlify
import socket
import sys
from urllib import urlencode
# Secure random generators
import random
try:
random = random.SystemRandom()
except:
pass
try:
from os import urandom
except:
urandom = None
##########
def random_seed(rawsize=10):
""" Generates a random seed, which is hex encoded. """
if urandom:
randstr = urandom(rawsize)
else:
randstr = ''.join([ chr(random.randint(0, 255)) for i in range(rawsize) ])
return hexlify(randstr)
def get_google_url(hex_secret, hostname=None):
# Note: Google uses base32 for it's encoding rather than hex.
b32secret = b32encode( unhexlify(hex_secret) )
if not hostname:
hostname = socket.gethostname()
data = "otpauth://totp/%(hostname)s?secret=%(secret)s" % {
"hostname":hostname,
"secret":b32secret,
}
url = "https://chart.googleapis.com/chart?" + urlencode({
"chs":"200x200",
"chld":"M|0",
"cht":"qr",
"chl":data
})
return b32secret, url
##########
if __name__ == "__main__":
secret = random_seed()
b32secret, url = get_google_url(secret, )
print "Hex secret: %s" % secret
print "...base32: %s" % b32secret
print
print "===== Google URL ====="
print "Scan this with Google Authenticator or enter the base32"
print "value above as 'key' when manually adding.\n %s" % url
print
print "(See http://www.google.com/support/accounts/bin/answer.py?answer=1066447 )"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment