Last active
September 9, 2015 13:42
-
-
Save jojonas/af8d29be87aa0f95f123 to your computer and use it in GitHub Desktop.
Revisions
-
jojonas revised this gist
Sep 9, 2015 . 1 changed file with 28 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -43,7 +43,7 @@ def calckey(secret, timestamp): # general steps: # 1. have root access # 2. use adb shell to pull /data/data/com.google.android.apps.authenticator2/databases def from_database(dbfile, enable_plot=False): import sqlite3 now = int(time.time()) @@ -65,10 +65,36 @@ def from_database(dbfile): for name, secret in cursor: key = calckey(secret, now) print("{:>25} {}".format(name, key)) if enable_plot: plot(name, secret) print("-"*width) # plots the QR-code using the matplotlib library: # the QR code contains a URI, but is encoded in the QR-code "text" mode # this can currently not be fixed, it works with the Google Authentificator App though def plot(name, secret): import qrcode import matplotlib.pyplot as plt qr = qrcode.QRCode( version=None, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=1, border=1, ) url = "otpauth://totp/{:s}?secret={:s}".format(name, secret) qr.add_data(url) qr.make(fit=True) img = qr.make_image() plt.clf() plt.imshow(img, cmap="Greys", interpolation="nearest") plt.axis('off') plt.title(name) plt.show() if __name__=="__main__": parser = argparse.ArgumentParser(description="Two-Step-Token generator (RFC 6238)") parser.add_argument("-p", "--plot", action="store_true", help="plot the secrets via the qrcode module and Matplotlib (for transfering to a new device)") parser.add_argument("database", type=str, help="sqlite database (dumped from Android)") args = parser.parse_args() from_database(args.database, args.plot) -
jojonas revised this gist
Feb 24, 2015 . 1 changed file with 18 additions and 19 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,51 +8,51 @@ # pads the string to a multiple of 8 bytes using "=" def pad_base32(string): return string + "=" * (8 - ((len(string)-1) % 8) - 1) # calculates the authentification key for the specified secret and timestamp # more info: https://en.wikipedia.org/wiki/Google_Authenticator def calckey(secret, timestamp): # pad secret to multiple of 8 characters secret = pad_base32(secret) # decode base32 to byte string (ignoring case) key = base64.b32decode(secret, casefold=True) # interpret Unix timestamp / 30sec as 8 byte unsigned long long message = int(timestamp/30).to_bytes(8, byteorder="big", signed=False) # combine message (time) and key (secret) into one authentification code using sha1 code = hmac.new(key, message, hashlib.sha1).digest() # extract offset (last 4 bits of HMAC) offset = code[-1] & 0x0f # extract 4 bytes starting at offset, interpret as 4 byte unsigned int truncatedHash = int.from_bytes(code[offset:offset+4], byteorder="big", signed=False) # unset the first bit truncatedHash &= ~(1 << (8*4-1)) # restrict code to 6 digits and convert to string code = truncatedHash % 1000000 codeStr = "%06d" % code return codeStr # to pull the database from Android, see https://nucleussystems.com/blog/android-backup-google-authenticator/ # general steps: # 1. have root access # 2. use adb shell to pull /data/data/com.google.android.apps.authenticator2/databases def from_database(dbfile): import sqlite3 now = int(time.time()) remaining = 30 - (now % 30) with sqlite3.connect(dbfile) as connection: cursor = connection.cursor() cursor.execute("SELECT email, secret FROM accounts") # output code is a little ugly :/ width = 50 print("="*width) @@ -66,10 +66,9 @@ def from_database(dbfile): key = calckey(secret, now) print("{:>25} {}".format(name, key)) print("-"*width) if __name__=="__main__": parser = argparse.ArgumentParser(description="Two-Step-Token generator (RFC 6238)") parser.add_argument("database", type=str, help="sqlite database (dumped from Android)") args = parser.parse_args() from_database(args.database) -
jojonas renamed this gist
Feb 23, 2015 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
jojonas renamed this gist
Feb 20, 2015 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
jojonas revised this gist
Feb 20, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,7 +9,7 @@ def pad_base32(string): return string + "=" * (8 - ((len(string)-1) % 8) - 1) # calculates the authentification key for the specified secret and timestamp # more info: https://en.wikipedia.org/wiki/Google_Authenticator def calckey(secret, timestamp): # pad secret to multiple of 8 characters -
jojonas created this gist
Feb 20, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,75 @@ import argparse import time import base64 import hmac import hashlib # pads the string to a multiple of 8 bytes using "=" def pad_base32(string): return string + "=" * (8 - ((len(string)-1) % 8) - 1) # calculatess the authentification key for the specified secret and timestamp # more info: https://en.wikipedia.org/wiki/Google_Authenticator def calckey(secret, timestamp): # pad secret to multiple of 8 characters secret = pad_base32(secret) # decode base32 to byte string (ignoring case) key = base64.b32decode(secret, casefold=True) # interpret Unix timestamp / 30sec as 8 byte unsigned long long message = int(timestamp/30).to_bytes(8, byteorder="big", signed=False) # combine message (time) and key (secret) into one authentification code using sha1 hash = hmac.new(key, message, hashlib.sha1).digest() # extract offset (last 4 bits of HMAC) offset = hash[-1] & 0x0f # extract 4 bytes starting at offset, interpret as 4 byte unsigned int truncatedHash = int.from_bytes(hash[offset:offset+4], byteorder="big", signed=False) # unset the first bit truncatedHash &= ~(1 << (8*4-1)) # restrict code to 6 digits and convert to string code = truncatedHash % 1000000 codeStr = "%06d" % code return codeStr # to pull the database from Android, see https://nucleussystems.com/blog/android-backup-google-authenticator/ # general steps: # 1. have root access # 2. use adb shell to pull /data/data/com.google.android.apps.authenticator2/databases def from_database(dbfile): import sqlite3 now = int(time.time()) remaining = 30 - (now % 30) with sqlite3.connect(dbfile) as connection: cursor = connection.cursor() cursor.execute("SELECT email, secret FROM accounts") # output code is a little ugly :/ width = 50 print("="*width) print("Two-Step-Token generator (RFC 6238)".center(width)) print("="*width) print("Loaded from databases file '{:s}'.".format(dbfile).center(width)) print("Remaining time: {:d} sec\n".format(remaining).center(width)) print("{:>25} {}".format("Account", "Key")) print("-"*width) for name, secret in cursor: key = calckey(secret, now) print("{:>25} {}".format(name, key)) print("-"*width) if __name__=="__main__": parser = argparse.ArgumentParser(description="Two-Step-Token generator (RFC 6238)") parser.add_argument("database", type=str, help="sqlite database (dumped from Android)") args = parser.parse_args() from_database(args.database)