Sunday, January 5, 2020

qrencode, you won't make scannable OTP codes, so who the heck QR you?

I previously wrote about my adventure backing up all data on my ZTE before sending it to ewaste recycling. Part of that backup was preserving my OTP MFA codes.  This blog entry is limited to a tiny bit of historical information and how I made viable OTP MFA codes with qrencode for Microsoft Authenticator.

I learned the importance of having a backup plan years ago after I had established my first OTP account on the ZTE. The ZTE was running slowly and I proceeded to wipe it. I forgot about that MFA registration until the next time I was prompted for the MFA code.  At that point I began to register MFA OTP on a second device.

In November 2017 I picked up a Verizon PAYG LG VS810PP to help activate a BYOD hotspot. I kept the LG in service as a backup MFA device. When adding a new MFA OTP accounts on the ZTE, I captured the QR code and later scanned it in to Microsoft Authenticator on the LG.

Having lost the original LG box, and within that box, the plastic backing to keep the battery in place, the LG needed to go away. 

Keeping the QR codes can be handy in case you lose your only OTP device or in the event you want to migrate to a newer device.  The issue is how to store QR codes.  Surely QR codes can be encrypted, but they are the result of the OTP URI metadata. An easier approach I found is to retain metadata containing the issuer, secret, and account and keep all OTP entries in a comma-separated values (CSV) file and encrypt that file.

In December I obtained the Microsoft Authenticator database from /data/com.azure.authenticator/databases/PhoneFactor.

The challenge I ran into in early December was the inability to generate viable QR codes for use with Microsoft Authenticator.  I rummaged through documentation like https://github.com/google/google-authenticator/wiki/Key-Uri-Format and https://stefansundin.github.io/2fa-qr/, of which the latter is rather nice because it allowed me to compare a 2fa-qr generated QR with the output of qrencode. No matter why I tried, I was unable to create an exact QR of that which 2fa-qr creates, but I did get a QR to work.

You might be thinking "why don't you use 2fa-qr."  My answer is "because I do not know the provenance or insides of 2fa-qr and for all I know, it could be logging user input data to a server."

To make a short story shorter, this is the command line that finally generated a QR code that Microsoft Authenticator would accept:

qrencode -8 -c -l L -o /tmp/qr.png -v 3 "otpauth://totp/zanzamar@earthling.net?secret=FFFFFFFFFFFFFFFF"

The above works great for a single code.  However, I have a handful of services that either require or permit MFA. I was seeking a routine to generate all the OTP QR codes for bulk repeat scanning in Microsoft Authenticator.  The above is not an actual OTP account, but rather what I fabricated to compare between 2fa-qr and qrencode.

The Microsoft Authenticator app uses an SQLite database named PhoneFactor and sqlitebrowser opens it.  In sqlitebrowser I invoked a query of "select * from accounts;"

The query output was displayed and I selected all the content. I copied and pasted in to a text editor (geany), performed a search and replace on " " (in the actual file, it is a tab character in between the quotes)  with a comma (,) and conveniently provided a .csv extension.

With a usable data source, I came up with the one liner loop. IIRC there are shell variable extraction methods I could have substituted in place of cut.  For now, I'll use cut.

NUM=1; cat ./otp.csv | sed -e 's/"//g' -e 's/ /%20/g' -e 's/@/%40/g' | while read LINE; do ACCOUNT=$(echo $LINE | cut -d, -f4); SECRET=$(echo $LINE | cut -d, -f7); ISSUER=$(echo $LINE | cut -d, -f3); qrencode -v 3 -8 -c -l -L L -o /tmp/qr-${NUM}.png "otpauth://totp/${ACCOUNT}?secret=${SECRET}&issuer=${ISSUER}; NUM=$((NUM+1)); done

With the QR codes visible in a file browser with image preview, I  scanned my OTP secrets in to Microsoft Autheticator.

After all eight OTP secrets were imported, I double-checked the OTP codes against my LG phone.  Only after confirming that all the OTP codes were identical, between the new phone with Microsoft Authenticator and the LG, did I factory wipe the LG.

I hope others find this useful.

EDIT 2020-01-05

While setting up a secondary device for MFA, I forced myself to learn the bash method of breaking the CSV lines in to tokens.
The format of the SQLite database has columns:

ms_mfa_entry_number, big_zeros_number, OTP_ISSUER,OTP_ACCOUNT,empty,1,OTP_SECRET,empty

ADDR[3] = OTP_ISSUER
ADDR[4] = OTP_ACCOUNT
ADDR[6] = OTP_SECRET - perhaps because the actual 6th column is empty so 7 assumes the place of 6?

IFS=',';NUM=1; cat ./otp.csv | sed -e 's/"//g' -e 's/ /%20/g' -e 's/@/%40/g' | while read -ra ADDR; do qrencode -v 3 -8 -c -l -L L -o /tmp/qr-${NUM}.png "otpauth://totp/${ADDR[3]}?secret=${ADDR[6]}&issuer=${ADDR[2]}; NUM=$((NUM+1)); done