Recovering Google Authenticator Keys from iOS Backups

6 minute read

Update 2017-12-31: As reported on the comments, this is no longer working under iOS 10/11 due to the inability of the iphone-dataprotection code to decrypt keychains from these newer versions.

Keep an eye on this reported issue, in case it’s ever fixed.

There are also reported issues with installing m2crypto, see this stackoverflow page.

Update 2015-10-11: I’ve updated the results based on great infro from Jay Zhuang in the comments about how to decode the final data element. This was previously entitled “Trying to Extract Google Authenticator Keys from iOS Backups” but has now been updated to reflect successful key recovery.

Update 2015-12-07: As pointed out in the comments, it looks like newer versions of Google Authenticator store keys in a way that can’t be retrieved from iOS Backups (only restored to the same device). This only affects new keys added to the app - older keys are still able to be retrieved.

Verified on:

  • OS X 10.10
  • Python 2.7
  • iOS 9.0.2

A mess-up from Google that had an iOS update of Google Authenticator in 2013 wipe out previously stored accounts, as well as some problems restoring backups onto a new iOS device recently got me thinking that there has to be a way to get the account keys out of iOS backups. I’ve previously written an article on how to do the same thing on Android. Google Accounts now pretty easily let you switch devices, but as using Google Authenticator for 2 factor authentication gets more and more popular there are still cases where you need to be able to get at those keys.

Google Authenticator uses a time based one-time-password system that relies on a “shared key”. This is all you really need, since the rest is purely algorithmic. Details: https://github.com/google/google-authenticator If you have that key, you can easily get a new Google Autheenticator app installation (or various other apps that support the Time-based One-time Password TOTP Algorithm in RFC 6238) configured to generate codes for your account.

iOS backups contain all the data from your apps. Google Authenticator stores your Google Authenticator keys in the iOS Keychain rather than as application level data. iOS backups have the Keychain encrypted with a key which you can’t get from your iOS device (the UID-Key) without jail-breaking. I’m not going down that path here. However, IF you’re smart and had iTunes encrypt your backups, then Apple decides to use that password to encrypt not only your various application data files, but your Keychain data too. This makes it easier if you want to restore onto another device, like a new phone. That means if we have an encrypted iOS backup we can get at the Keychain location where Google Authenticator stores the keys.

Note - if you’re using iCloud Backups this won’t work for you. It doesn’t store the protected keychain info.

Requirements

  • Encrypted backup of iOS device (if you didn’t encrypt your local iTunes backups, or you’re using iCloud backup, you are out of luck)
  • Mac running OS X 10.10 Yosemite (you can do this in another OS or version, but you’re on your own)
  • Python with pip

Step 1 - Finding your backup

Backups are stored in

/Users/YOUR_USER_NAME/Library/Application\ Support/MobileSync/Backup/

One of the long hex string directories contained there will be the backup you want. How to determine which one (if you have multiple iOS devices)? Open up iTunes, go into Preferences -> Devices then you should see the names of each of your devices, and the date of latest backup. That date/time should correspond to the modified date of one of the directories in your backups directory listed above.

Step 2 - Decrypting your backup

Download the tools referenced here: https://github.com/dinosec/iphone-dataprotection. These used to live on Google Code, but that is being discontinued.

In order to do this you’ll need to get some dependencies installed. I use Homebrew to install python, then pip to manage the dependencies. If you don’t have pip please lookup some python tutorials.

pip install M2crypto construct progressbar pycrypto

In the iphone-dataprotection package, you’ll find a python_scripts directory.

Since these scripts are referencing /usr/bin/python in the first line, it’s helpful to run them explicitly with “python scriptname.py” to ensure your updated homebrew python (and the dependencies which you just used pip to install dependencies) is used.

Use the script “backup_tool.py” to decrypt your backup. Use the hex directory of your backup as the only argument. You’ll need the password you set up when first setting iTunes to encrypt your iOS backups.

python ./backup_tool.py PATH_TO_BACKUP

If it works, you’ll now have an _extract directory which contains the decrypted backup files.

References: http://www.securitylearn.net/tag/decrypt-iphone-backup-keychain/

Step 3 - Decrypt your Keychain

Take a look in your _extract directory at ‘KeychainDomain/keychain-backup.plist’. This file contains all the encrypted elements from your iOS keychain. If you do a text search on the reference value you found in the previous step’s plist file, it should appear in this file too.

Use another script from the iphone-dataprotection toolkit called ‘keychain_tool.py’. This one takes 2 arguments. First is your ‘xxx_extract/KeychainDomain/keychain-bakup.plist’ the second is your ‘xxx_extract/Manifest.plist’ file. Use the -d option to have it display your keychain data.

python keychain_tool.py -d "PATH_TO_extract/KeychainDomain/keychain-backup.plist" "PATH_TO_extract/Manifest.plist"

Look at that! There’s a lot of decrypted data on your screen now. Pipe it out to a file so you can inspect it properly. Search for “com.google.otp.authentication”. That’s in the first column “Service” - and you’ll see in the Account column the name of your account. Look in the Data column. This is where the magic is. Wait a sec - the value is truncated. How come?

Well it looks like for purposes of making the output easy to read, the utility libraries truncate that field at position 20. Let’s fix that.

Find and open the keychain.py file, go down to line 148 (may change if the source is updated) and change

self.sanitize(p.get("data","?"))[:20],

to

self.sanitize(p.get("data","?"))[:200],

That should give us enough space to see the full value. Run it again, and indeed, now it shows a longer value.

You should see a value like this:

>38ec20dfd3e65e8c14d5cac9a313b15991a3c6b7.

Step 4 - Convert your key into base32

(taken from comments below, thanks again Jay Zhuang)

You will need to convert your shared key value into base32 for entry into the Google Authenticator app. I used this online javascript converter to go from hex to ASCII: http://tomeko.net/online_tools/hex_to_base32.php?lang=en

Determine whether you have a hex or ASCII code - and convert it to base32

  • If the data column started with ‘>’, the key is represented in hex, convert it to base32. ex. >9123aabbccdd81925566 => SER2VO6M3WAZEVLG

  • Otherwise, the seed is represented in ASCII, convert it to binary then base32. ex. AQ67YYR488 => 41513637595952343838 => IFITMN2ZLFJDIOBY

Notes - I haven’t seen one of these ASCII keys in looking through mine in order to verify, only the hex style keys

Step 5 - Transfer the key into a new Google Authenticator installation

Once you have your key converted to base32, you can enter this value straight into Google Authenticator by choosing the “Manual entry” option, or get a new QR code generated to scan into the app.

If you want to generate a new QR code and scan it into your app, you can use a generator such as http://dan.hersam.com/tools/gen-qr-code.html or try and create one manually from an OTP URI.

Whichever method you choose, I highly recommend you change your shared key with whatever accounts you are using. The step of using a conversion tool, or generating a new QR code, as well as just having an unencrypted file on your machine with all the keychain data from your phone all represent ways you could be giving away your key data.

Leave a Comment