Skip to content

Commit

Permalink
add keepass csv export; improve hotp
Browse files Browse the repository at this point in the history
- export to dedicated totp and hotp csv files for KeePass
- show Typ as totp/hotp instead of OTP_TOTP/OTP_HOTP
  (BREAKING CHANGE in csv, json and stdout, qr codes or urls are not affected)
- add hotp example
- add hotp tests
- export counter for hotp to csv and json files
- add section on KeePass to README
- increase protobuf to 4.21.10
- show file names of exported csv or json files
  • Loading branch information
scito committed Dec 4, 2022
1 parent eae01a0 commit a77e775
Show file tree
Hide file tree
Showing 14 changed files with 436 additions and 160 deletions.
36 changes: 18 additions & 18 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 52 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
[![CI Status](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci.yml/badge.svg)](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci.yml)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/protobuf)
[![GitHub Pipenv locked Python version](https://img.shields.io/github/pipenv/locked/python-version/scito/extract_otp_secret_keys)](https://github.com/scito/extract_otp_secret_keys/blob/master/Pipfile.lock)
![protobuf version](https://img.shields.io/badge/protobuf-4.21.9-informational)
![protobuf version](https://img.shields.io/badge/protobuf-4.21.10-informational)
[![License](https://img.shields.io/github/license/scito/extract_otp_secret_keys)](https://github.com/scito/extract_otp_secret_keys/blob/master/LICENSE)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/scito/extract_otp_secret_keys?sort=semver&label=version)](https://github.com/scito/extract_otp_secret_keys/tags)
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)

---

Extract two-factor authentication (2FA, TFA) secret keys from export QR codes of "Google Authenticator" app.
Extract two-factor authentication (2FA, TFA, one time passwords, otp) secret keys from export QR codes of "Google Authenticator" app.
The secret and otp values can be printed and exported to json or csv. The QR codes can be printed or saved as PNG images.

## Usage
Expand All @@ -26,19 +26,20 @@ The secret and otp values can be printed and exported to json or csv. The QR cod

## Program help: arguments and options

<pre>usage: extract_otp_secret_keys.py [-h] [--json FILE] [--csv FILE] [--printqr] [--saveqr DIR] [--verbose] [--quiet] infile
<pre>usage: extract_otp_secret_keys.py [-h] [--json FILE] [--csv FILE] [--keepass FILE] [--printqr] [--saveqr DIR] [--verbose] [--quiet] infile

positional arguments:
infile file or - for stdin (default: -) with "otpauth-migration://..." URLs separated by newlines, lines starting with # are ignored
infile file or - for stdin (default: -) with "otpauth-migration://..." URLs separated by newlines, lines starting with # are ignored

options:
-h, --help show this help message and exit
--json FILE, -j FILE export to json file
--csv FILE, -c FILE export to csv file
--printqr, -p print QR code(s) as text to the terminal (requires qrcode module)
--saveqr DIR, -s DIR save QR code(s) as images to the given folder (requires qrcode module)
--verbose, -v verbose output
--quiet, -q no stdout output</pre>
-h, --help show this help message and exit
--json FILE, -j FILE export json file
--csv FILE, -c FILE export csv file
--keepass FILE, -k FILE export totp/hotp csv file(s) for KeePass
--printqr, -p print QR code(s) as text to the terminal (requires qrcode module)
--saveqr DIR, -s DIR save QR code(s) as images to the given folder (requires qrcode module)
--verbose, -v verbose output
--quiet, -q no stdout output</pre>

## Dependencies

Expand All @@ -47,7 +48,7 @@ options:
Known to work with

* Python 3.10.8, protobuf 4.21.9, qrcode 7.3.1, and pillow 9.2
* Python 3.11.0, protobuf 4.21.9, qrcode 7.3.1, and pillow 9.2
* Python 3.11.0, protobuf 4.21.10, qrcode 7.3.1, and pillow 9.2

For protobuf versions 3.14.0 or similar or Python 3.6, use the extract_otp_secret_keys version 1.4.0.

Expand All @@ -57,6 +58,44 @@ For printing QR codes, the qrcode module is required, otherwise it can be omitte

pip install qrcode[pil]

## KeePass

[KeePass 2.51](https://keepass.info/news/n220506_2.51.html) (released in May 2022) and newer [support the generation of OTPs (TOTP and HOTP)](https://keepass.info/help/base/placeholders.html#otp).

KeePass can generate the second factor password (2FA) if the OTP secret is stored in `TimeOtp-Secret-Base32` string field for TOTP or `HmacOtp-Secret-Base32` string field for HOTP. You view or edit them in entry dialog on the 'Advanced' tab page.

KeePass provides menu commands in the main window for generating one-time passwords ('Copy HMAC-Based OTP', 'Show HMAC-Based OTP', 'Copy Time-Based OTP', 'Show Time-Based OTP'). Furthermore, one-time passwords can be generated during auto-type using the {HMACOTP} and {TIMEOTP} placeholders.

In order to simplify the usage of the second factor password generation in KeePass a specific KeePass CSV export is available with option `-keepass` or `-k`. This KeePass CSV file can be imported by the ["Generic CSV Importer" of KeePass](https://keepass.info/help/kb/imp_csv.html).

If TOTP and HOTP entries have to be exported, then two files with an intermediate suffix .totp or .hotp will be added to the KeePass export filename.

Example:
- Only TOTP entries to export and parameter --keepass example_keepass_output.csv<br>
→ example_keepass_output.csv with TOTP entries will be exported
- Only HOTP entries to export and parameter --keepass example_keepass_output.csv<br>
→ example_keepass_output.csv with HOTP entries will be exported
- If both TOTP and HOTP entries to export and parameter --keepass example_keepass_output.csv<br>
→ example_keepass_output.totp.csv with TOTP entries will be exported<br>
→ example_keepass_output.hotp.csv with HOTP entries will be exported

Import CSV with TOTP entries in KeePass as

- Title
- User Name
- String (TimeOtp-Secret-Base32)
- Group (/)

Import CSV with HOTP entries in KeePass as

- Title
- User Name
- String (HmacOtp-Secret-Base32)
- String (HmacOtp-Counter)
- Group (/)

KeePass can be used as a backup for one time passwords (second factor) from the mobile phone.

## Technical background

The export QR code of "Google Authenticator" contains the URL `otpauth-migration://offline?data=...`.
Expand All @@ -66,7 +105,7 @@ Command for regeneration of Python code from proto3 message definition file (onl

protoc --python_out=protobuf_generated_python google_auth.proto

The generated protobuf Python code was generated by protoc 21.9 (https://github.com/protocolbuffers/protobuf/releases/tag/v21.9).
The generated protobuf Python code was generated by protoc 21.10 (https://github.com/protocolbuffers/protobuf/releases/tag/v21.10).

## References

Expand Down
3 changes: 3 additions & 0 deletions example_export.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ otpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXB
# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
# otpauth://totp/pi@raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
otpauth-migration://offline?data=CigKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpIAEoATACCjUKEPqlBekzoNEukL7qlsjBCDYSDnBpQHJhc3BiZXJyeXBpGgtyYXNwYmVycnlwaSABKAEwAhABGAEgACiQ7OOa%2Bf%2F%2F%2F%2F8B

# otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
otpauth-migration://offline?data=CiUKEPqlBekzoNEukL7qlsjBCDYSCWhvdHAgZGVtbyABKAEwATgEEAEYASAAKNuv15j6%2F%2F%2F%2F%2FwE%3D
2 changes: 2 additions & 0 deletions example_keepass_output.hotp.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Title,User Name,HmacOtp-Secret-Base32,HmacOtp-Counter,Group
,hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,4,OTP/HOTP
5 changes: 5 additions & 0 deletions example_keepass_output.totp.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Title,User Name,TimeOtp-Secret-Base32,Group
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
raspberrypi,pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,OTP/TOTP
11 changes: 6 additions & 5 deletions example_output.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
name,secret,issuer,type,url
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,OTP_TOTP,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,OTP_TOTP,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,OTP_TOTP,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,OTP_TOTP,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
name,secret,issuer,type,counter,url
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY
pi@raspberrypi,7KSQL2JTUDIS5EF65KLMRQIIGY,raspberrypi,totp,,otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi
hotp demo,7KSQL2JTUDIS5EF65KLMRQIIGY,,hotp,4,otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4
20 changes: 16 additions & 4 deletions example_output.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,40 @@
"name": "pi@raspberrypi",
"secret": "7KSQL2JTUDIS5EF65KLMRQIIGY",
"issuer": "raspberrypi",
"type": "OTP_TOTP",
"type": "totp",
"counter": null,
"url": "otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi"
},
{
"name": "pi@raspberrypi",
"secret": "7KSQL2JTUDIS5EF65KLMRQIIGY",
"issuer": "",
"type": "OTP_TOTP",
"type": "totp",
"counter": null,
"url": "otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY"
},
{
"name": "pi@raspberrypi",
"secret": "7KSQL2JTUDIS5EF65KLMRQIIGY",
"issuer": "",
"type": "OTP_TOTP",
"type": "totp",
"counter": null,
"url": "otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY"
},
{
"name": "pi@raspberrypi",
"secret": "7KSQL2JTUDIS5EF65KLMRQIIGY",
"issuer": "raspberrypi",
"type": "OTP_TOTP",
"type": "totp",
"counter": null,
"url": "otpauth://totp/pi%40raspberrypi?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&issuer=raspberrypi"
},
{
"name": "hotp demo",
"secret": "7KSQL2JTUDIS5EF65KLMRQIIGY",
"issuer": "",
"type": "hotp",
"counter": 4,
"url": "otpauth://hotp/hotp%20demo?secret=7KSQL2JTUDIS5EF65KLMRQIIGY&counter=4"
}
]
Loading

0 comments on commit a77e775

Please sign in to comment.