some renaming and README updating

This commit is contained in:
scito 2023-01-01 22:47:12 +01:00
parent 8d8b993f12
commit 160a558825
3 changed files with 95 additions and 50 deletions

101
README.md
View File

@ -1,8 +1,8 @@
# Extract TOTP/HOTP secret keys from Google Authenticator # Extract TOTP/HOTP secret keys from Google Authenticator
[![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) [![CI tests](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)
![coverage](https://img.shields.io/badge/coverage-95%25-brightgreen) ![coverage](https://img.shields.io/badge/coverage-95%25-brightgreen)
[![docker](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml/badge.svg)](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml) [![CI docker](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml/badge.svg)](https://github.com/scito/extract_otp_secret_keys/actions/workflows/ci_docker.yml)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/protobuf) ![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) [![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.12-informational) ![protobuf version](https://img.shields.io/badge/protobuf-4.21.12-informational)
@ -16,7 +16,8 @@ TODO add src/
TODO rename extract_otp_secret_keys TODO rename extract_otp_secret_keys
Extract two-factor authentication (2FA, TFA, OTP) secret keys from export QR codes of "Google Authenticator" app. Extract two-factor authentication (2FA, TFA, 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. The QR codes can captured from the camera in a GUI, imported from images or from text files containing the QR code data.
The secret and otp values can be printed and exported to json or csv, as well as printed or saved as PNG images.
## Installation ## Installation
@ -25,7 +26,7 @@ cd extract_otp_secret_keys
## Usage ## Usage
### Capture QR codes from camera ### Capture QR codes from camera (since v2.0.0)
1. Open "Google Authenticator" app on the mobile phone 1. Open "Google Authenticator" app on the mobile phone
2. Export the QR codes from "Google Authenticator" app 2. Export the QR codes from "Google Authenticator" app
@ -36,7 +37,7 @@ cd extract_otp_secret_keys
![CV2 Capture from camera screenshot](cv2_capture_screenshot.png) ![CV2 Capture from camera screenshot](cv2_capture_screenshot.png)
### With builtin QR decoder from image files ### With builtin QR decoder from image files (since v2.0.0)
1. Open "Google Authenticator" app on the mobile phone 1. Open "Google Authenticator" app on the mobile phone
2. Export the QR codes from "Google Authenticator" app 2. Export the QR codes from "Google Authenticator" app
@ -59,7 +60,7 @@ cd extract_otp_secret_keys
## Program help: arguments and options ## Program help: arguments and options
<pre>usage: extract_otp_secrets.py [-h] [--camera NUMBER] [--qr {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT}] [--json FILE] [--csv FILE] [--keepass FILE] [--printqr] [--saveqr DIR] [--no-color] [--verbose | --quiet] [infile ...] <pre>usage: extract_otp_secrets.py [-h] [--camera NUMBER] [--qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}] [--json FILE] [--csv FILE] [--keepass FILE] [--printqr] [--saveqr DIR] [--no-color] [--verbose | --quiet] [infile ...]
Extracts one time password (OTP) secret keys from QR codes, e.g. from Google Authenticator app. Extracts one time password (OTP) secret keys from QR codes, e.g. from Google Authenticator app.
If no infiles are provided, the QR codes are interactively captured from the camera. If no infiles are provided, the QR codes are interactively captured from the camera.
@ -71,7 +72,7 @@ positional arguments:
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
--camera NUMBER, -C NUMBER camera number of system (default camera: 0) --camera NUMBER, -C NUMBER camera number of system (default camera: 0)
--qr {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT}, -Q {QREADER,DEEP_QREADER,ZBAR,CV2,CV2_WECHAT} --qr {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}, -Q {ZBAR,QREADER,QREADER_DEEP,CV2,CV2_WECHAT}
QR reader (default: ZBAR) QR reader (default: ZBAR)
--json FILE, -j FILE export json file or - for stdout --json FILE, -j FILE export json file or - for stdout
--csv FILE, -c FILE export csv file or - for stdout --csv FILE, -c FILE export csv file or - for stdout
@ -102,40 +103,11 @@ For protobuf versions 3.14.0 or similar or Python 3.6, use the extract_otp_secre
### Shared libs installation for reading QR code images ### Shared libs installation for reading QR code images
For reading QR code images the zbar library must be installed. For reading QR code images the zbar library must be installed for `ZBAR` QR reader.
If you do not extract directly from images, you do not need to install the zbar shared library. If you do not extract directly from images or using catpuring from camera, you do not need to install the zbar shared library.
For a detailed installation documentation of [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar#installation). For a detailed installation documentation of [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar#installation).
#### Windows
The zbar DLLs are included with the Windows Python wheels. On other operating systems, you will need to install the zbar shared library.
TODO Write installation, not error message
##### Windows error message
If you see an ugly ImportError when importing [pyzbar](https://pypi.org/project/pyzbar/) on Windows you will most likely need the [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
```
Traceback (most recent call last):
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 58, in load
dependencies, libzbar = load_objects(Path(''))
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 50, in load_objects
deps = [
^
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 51, in <listcomp>
cdll.LoadLibrary(str(directory.joinpath(dep)))
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 454, in LoadLibrary
return self._dlltype(name)
^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 376, in __init__
self._handle = _dlopen(self._name, mode)
^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependencies). Try using the full path with constructor syntax.
```
#### Linux (Debian, Ubuntu, ...) #### Linux (Debian, Ubuntu, ...)
sudo apt-get install libzbar0 sudo apt-get install libzbar0
@ -152,6 +124,10 @@ FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependenc
brew install zbar brew install zbar
#### Windows
The zbar DLLs are included with the Windows Python wheels. However, you might need to install [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
## Examples ## Examples
### Printing otp secrets form text file ### Printing otp secrets form text file
@ -193,7 +169,12 @@ FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependenc
* Free and open source * Free and open source
* Supports Google Authenticator exports (and compatible apps like Aegis Authenticator) * Supports Google Authenticator exports (and compatible apps like Aegis Authenticator)
* Captures the the QR codes directly from the camera using QR code detection (based on OpenCV) * Captures the the QR codes directly from the camera using different QR code readers (based on OpenCV)
* ZBAR: fast and reliable, good for images and video capture (default/recommended) [pyzbar](https://github.com/NaturalHistoryMuseum/pyzbar)
* QREADER: fast [QReader](https://github.com/Eric-Canas/QReader)
* QREADER_DEEP: slow, not good for camera [QReader](https://github.com/Eric-Canas/QReader)
* CV2: fast [QRCodeDetector](https://docs.opencv.org/4.x/de/dc3/classcv_1_1QRCodeDetector.html)
* CV2_WECHAT: fast [WeChatQRCode](https://docs.opencv.org/4.x/dd/d63/group__wechat__qrcode.html)
* Supports TOTP and HOTP * Supports TOTP and HOTP
* Generates QR codes * Generates QR codes
* Exports to various formats: * Exports to various formats:
@ -390,6 +371,8 @@ docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets example_export.txt
docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets example_export.png docker run --rm -v "$(pwd)":/files:ro extract_otp_secrets example_export.png
``` ```
TODO link to docker/github repos
docker run --rm -v "$(pwd)":/files:ro -i extract_otp_secrets = < example_export.png docker run --rm -v "$(pwd)":/files:ro -i extract_otp_secrets = < example_export.png
docker run --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets docker run --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets
docker run --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro scit0/extract_otp_secrets docker run --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro scit0/extract_otp_secrets
@ -410,6 +393,17 @@ docker pull scit0/extract_otp_secrets_only_txt
docker pull ghcr.io/scito/extract_otp_secrets docker pull ghcr.io/scito/extract_otp_secrets
docker pull ghcr.io/scito/extract_otp_secrets_only_txt docker pull ghcr.io/scito/extract_otp_secrets_only_txt
### Docker examples
docker run --pull always --rm -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets example_export.png
docker run --pull always --rm -i -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets_only_txt - < example_export.txt
cat example_export.txt | docker run --pull always --rm -i -v \"$(pwd)\":/files:ro scit0/extract_otp_secrets_only_txt - -c - > example_out.csv
docker run --pull always --rm -v "$(pwd)":/files:ro -i --device="/dev/video0:/dev/video0" --env="DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix:ro scit0/extract_otp_secrets
## Tests ## Tests
### PyTest ### PyTest
@ -484,6 +478,35 @@ pip install -U -r requirements.txt
https://github.com/opencv/opencv/issues/23072 https://github.com/opencv/opencv/issues/23072
## Problems and Troubleshooting
### Windows error message
If you see an ugly ImportError on Windows you will most likely need the [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-US/download/details.aspx?id=40784). Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python.
This library shared library is required by [pyzbar](https://pypi.org/project/pyzbar/).
```
Traceback (most recent call last):
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 58, in load
dependencies, libzbar = load_objects(Path(''))
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 50, in load_objects
deps = [
^
File "C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\pyzbar\zbar_library.py", line 51, in <listcomp>
cdll.LoadLibrary(str(directory.joinpath(dep)))
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 454, in LoadLibrary
return self._dlltype(name)
^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.496.0_x64__qbz5n2kfra8p0\Lib\ctypes\__init__.py", line 376, in __init__
self._handle = _dlopen(self._name, mode)
^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: Could not find module 'libiconv.dll' (or one of its dependencies). Try using the full path with constructor syntax.
```
## Related projects ## Related projects
* [ZBar](https://github.com/mchehab/zbar) is an open source software suite for reading bar codes from various sources, including webcams. * [ZBar](https://github.com/mchehab/zbar) is an open source software suite for reading bar codes from various sources, including webcams.

View File

@ -82,6 +82,7 @@ interactive=true
ignore_version_check=true ignore_version_check=true
clean=false clean=false
build_docker=true build_docker=true
run_gui=true
while test $# -gt 0; do while test $# -gt 0; do
case $1 in case $1 in
@ -94,6 +95,7 @@ while test $# -gt 0; do
echo "-a Automatic mode" echo "-a Automatic mode"
echo "-C Ignore version check" echo "-C Ignore version check"
echo "-D No docker build" echo "-D No docker build"
echo "-G No not run gui"
echo "-c Clean" echo "-c Clean"
echo "-h, --help Help" echo "-h, --help Help"
quit quit
@ -110,6 +112,10 @@ while test $# -gt 0; do
build_docker=false build_docker=false
shift shift
;; ;;
-G)
run_gui=false
shift
;;
-c) -c)
clean=true clean=true
shift shift
@ -204,7 +210,7 @@ fi
# Upgrade pip requirements # Upgrade pip requirements
cmd="sudo pip install --upgrade pip" cmd="sudo pip install -U pip"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
@ -266,7 +272,7 @@ eval "$cmd"
# pip install # pip install
cmd="$PIP install -e ." cmd="$PIP install -U -e ."
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
@ -324,6 +330,7 @@ if $build_docker; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
# Build extract_otp_secrets (Debian) # Build extract_otp_secrets (Debian)
cmd="docker build . -t extract_otp_secrets --pull --build-arg RUN_TESTS=false" cmd="docker build . -t extract_otp_secrets --pull --build-arg RUN_TESTS=false"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
@ -333,7 +340,11 @@ if $build_docker; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
cmd="docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - < example_export.txt" cmd="cat mple_export.txt | docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets - -c - > example_output.csv"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
cmd="docker run --rm -i -v \"$(pwd)\":/files:ro extract_otp_secrets = < example_export.png"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
@ -344,10 +355,20 @@ if $build_docker; then
cmd="docker image prune -f || echo 'No docker image pruned'" cmd="docker image prune -f || echo 'No docker image pruned'"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd" eval "$cmd"
if $run_gui; then
cmd="docker run --pull always --rm -v "$(pwd)":/files:ro --device=\"/dev/video0:/dev/video0\" --env=\"DISPLAY\" -v /tmp/.X11-unix:/tmp/.X11-unix:ro extract_otp_secrets &"
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
fi
eval "$cmd"
fi fi
cmd="$PYTHON src/extract_otp_secrets.py &" if $run_gui; then
if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi cmd="$PYTHON src/extract_otp_secrets.py &"
eval "$cmd" if $interactive ; then askContinueYn "$cmd"; else echo -e "${cyan}$cmd${reset}";fi
eval "$cmd"
fi
echo -e "${greenBold}Sucessful${reset}"
quit quit

View File

@ -1,3 +1,4 @@
# TODO rewrite
# Extract two-factor authentication (2FA, TFA) secret keys from export QR codes of "Google Authenticator" app # Extract two-factor authentication (2FA, TFA) secret keys from export QR codes of "Google Authenticator" app
# #
# Usage: # Usage:
@ -118,7 +119,7 @@ Otps = List[Otp]
# workaround for PYTHON <= 3.9: OtpUrls = list[OtpUrl] # workaround for PYTHON <= 3.9: OtpUrls = list[OtpUrl]
OtpUrls = List[OtpUrl] OtpUrls = List[OtpUrl]
QRMode = Enum('QRMode', ['QREADER', 'DEEP_QREADER', 'ZBAR', 'CV2', 'CV2_WECHAT'], start=0) QRMode = Enum('QRMode', ['ZBAR', 'QREADER', 'QREADER_DEEP', 'CV2', 'CV2_WECHAT'], start=0)
# Constants # Constants
@ -256,9 +257,9 @@ def extract_otps_from_camera(args: Args) -> Otps:
log_error("Failed to capture image from camera") log_error("Failed to capture image from camera")
break break
try: try:
if qr_mode in [QRMode.QREADER, QRMode.DEEP_QREADER]: if qr_mode in [QRMode.QREADER, QRMode.QREADER_DEEP]:
found, bbox = qreader.detect(img) found, bbox = qreader.detect(img)
if qr_mode == QRMode.DEEP_QREADER: if qr_mode == QRMode.QREADER_DEEP:
otp_url = qreader.detect_and_decode(img, True) otp_url = qreader.detect_and_decode(img, True)
elif qr_mode == QRMode.QREADER: elif qr_mode == QRMode.QREADER:
otp_url = qreader.decode(img, bbox) if found else None otp_url = qreader.decode(img, bbox) if found else None
@ -448,8 +449,8 @@ def convert_img_to_otp_url(filename: str, args: Args) -> OtpUrls:
qr_mode = QRMode[args.qr] qr_mode = QRMode[args.qr]
otp_urls: OtpUrls = [] otp_urls: OtpUrls = []
if qr_mode in [QRMode.QREADER, QRMode.DEEP_QREADER]: if qr_mode in [QRMode.QREADER, QRMode.QREADER_DEEP]:
otp_url = QReader().detect_and_decode(img, qr_mode == QRMode.DEEP_QREADER) otp_url = QReader().detect_and_decode(img, qr_mode == QRMode.QREADER_DEEP)
otp_urls.append(otp_url) otp_urls.append(otp_url)
elif qr_mode == QRMode.CV2: elif qr_mode == QRMode.CV2:
otp_url, _, _ = cv2.QRCodeDetector().detectAndDecode(img) otp_url, _, _ = cv2.QRCodeDetector().detectAndDecode(img)