4 releases
0.2.1 | Oct 21, 2023 |
---|---|
0.2.0 | Oct 20, 2023 |
0.1.1 | Oct 18, 2023 |
0.1.0 | Oct 18, 2023 |
#1456 in Command line utilities
23 downloads per month
93KB
1K
SLoC
totp-qr
Command line utility to extract otpauth strings from QR-images and generate their respective TOTP
Why? I need the text SECRET encoded in previously saved QR images, screenshots, and Google Authenticator Export images for import into other apps KeePassXC, Proton Pass
The motivation for this project was initiated by password housekeeping. I'm content with the tools I use for password management such as KeePassXC, pass, iTerm2 Password Manager (can't live without now), but I lacked visibility and portability of my TOTP parameters and passwords.
This tool uses:
- The excellent rqrr crate for digging out otpauth data from most image types
- The reverse engineered protobuf
- The file-format crate for classifying stdin
- Shout out to totp-rs for its succinct byte slicing and Algorithm Enum; derivations of both were used. MIT LICENSE
Project Status:
- Waiting for resolution on SIGPIPE for general CLI Unix tools to avoid "broken pipe".
- The remedy is to modify stdout and use writeln!(stdout)? instead of println!() as shown below
pub fn reset_sigpipe() -> Result<(), Box<dyn std::error::Error>> {
#[cfg(target_family = "unix")]
{
use nix::sys::signal;
unsafe {
signal::signal(signal::Signal::SIGPIPE, signal::SigHandler::SigDfl)?;
}
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// behave like a typical unix utility
general::reset_sigpipe()?;
let mut stdout = io::stdout().lock();
...
TOTP-QR
Using totp-qr in a shell function to securely view tokens
- Install
totp-qr
e.g.cargo install totp-qr
or buildcargo install --path .
- Gather your QR-images into a directory
- Run
scripts/mk-totp-func.sh directory
- Inspect, copy, and add to your ~/.bashrc
Creating the shell function, walk-through
The images directory contains 2 example QRs
- otpauth-totp-qr.jpg holds 1 account: "otpauth://totp/..."
- otpauth-migration-qr.jpg holds 3 accounts: "otpauth-migration://offline?data=..."
$> totp-qr --uri images/otpauth-totp-qr.jpg
otpauth://totp/Example:alice@google.com?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP
$> totp-qr --uri images/otpauth-migration-qr.jpg
otpauth-migration://offline?data=Ci0KCkhlbGxvId6tvu8SEnRlc3QxQGV4YW1wbGUxLmNvbRoFVGVzdDEgASgBMAIKLQoKSGVsbG8h3q2%2B8BISdGVzdDJAZXhhbXBsZTIuY29tGgVUZXN0MiABKAEwAgotCgpIZWxsbyHerb7xEhJ0ZXN0M0BleGFtcGxlMy5jb20aBVRlc3QzIAEoATACEAIYASAA
otpauth data should be kept PRIVATE, OpenSSL can be used to encrypt the data (password: foo)
$> totp-qr --uri images/* | openssl aes-256-cbc -e -pbkdf2 -a
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
U2FsdGVkX18lfKZ20uQn/AcAWa85hUmcJzQ8mvS9JX0BJb7qVDddrCjbjPxagIw6
hwHeLBPWx1U0GbA7zszAYKNa6FB2I53ldNET/tnutUBNmQeuxqbiVH8A0or9Ni8+
Lj8onivfmaGzcBGGGMtz3wliD/LL+iUhkG+A2FZpIE2mIf9QdwofI9jSAhDhAW3y
d+AXZWWsHRRVs5MvIA++CcchKLG+FOza3fcBIt7RtqkdISQYDw+TgMGLN8NS5/ak
tk8PcuO+QfjmtNXh0/96mn5jYCGdD1NvioeDkwBu7883q2ChHXcOLRuPqqlJAR/2
T+DwgtEyCO5ZhQPn3nj9E1Gy1xXAm+4Yt8CueXvuBS5SJJLQd94Q+HT1SsyMhYB0
FGVb6YifAjV3Snsk3UO/60quJ8cfQxjDW5Pef/a0LjtMZL2d+jaYImFcLEMUrnlI
FRGDcbHR1oAmdonyuSNJBQ==
scripts/mk-totp-func.sh encrypts URI's and outputs a Bash function named totp()
$> ./scripts/mk-totp-func.sh images/
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
totp() {
openssl aes-256-cbc -d -pbkdf2 -a << EOF | totp-qr $1 | sort -t, -k2
U2FsdGVkX1+gVAFEnnQVFQVmzDUU47Sl6NIqFOAQaM85dspvn8gt2hueK272RRi4
vdWDBLsFeKM4qp7Jq2TSV2Lca2/29cwPcZtAVnaz02VbxO2m/e3b4RjB9AxjRk1R
iTPdTzG+BO2GYHjdz515Dc/N4+HD5UMVJr7yAsypdJ/ThRN3CWCjUYd3mAGx9/g7
0GCwTJ6psw4CtwbgL3hg66cZq9w43Wwj0P+S3eL87ueZRHHfr10hEtLTsJQLuRDl
479WZpzFFPTyrr3jVQFMqmhgEXKXf2VnFp4aLvCk6OKP93iQU3fE5aRWTEpQytYF
+F/AvpAQUnEOvAAivFFa2SBXZPHDscENzG16P0O8i3hWoyJizoAJIOMOPsA3HgMZ
1kxCFBnME1Pd1dlrSTsfhFNpjfbaURWxI5pwMS/fAKMIoRLWydeGJOukNIv+zPmI
PPJXNNa5fQP647srICuCnw==
EOF
}
Putting it all together
$> ./scripts/mk-totp-func.sh images/ >> ~/.bashrc
$> . ~/.bashrc
$> type -a totp
totp is a function
totp ()
{
openssl aes-256-cbc -d -pbkdf2 -a <<EOF |
...
EOF
totp-qr $1 | sort -t, -k2
}
Tip: If you're on a Mac using iTerm2 check out password manager (shortcut: ⌥ ⌘ F) for supplying passwords
totp() displays tokens sorted by issuer
$> totp
enter AES-256-CBC decryption password:
757676, Example
757676, Test1
255080, Test2
476239, Test3
totp -e to view account details as JSON
$> totp -e | jq
enter AES-256-CBC decryption password:
[
{
"secret": "JBSWY3DPEHPK3PXP",
"issuer": "Test1",
"sha": "SHA1",
"digits": 6,
"period": 30
},
{
"secret": "JBSWY3DPEHPK3PXQ",
"issuer": "Test2",
"sha": "SHA1",
"digits": 6,
"period": 30
},
{
"secret": "JBSWY3DPEHPK3PXR",
"issuer": "Test3",
"sha": "SHA1",
"digits": 6,
"period": 30
},
{
"secret": "JBSWY3DPEHPK3PXP",
"issuer": "Example",
"sha": "SHA1",
"digits": 6,
"period": 30
}
]
totp -u to view URI's
$> totp -u
enter AES-256-CBC decryption password:
otpauth-migration://offline?data=Ci0KCkhlbGxvId6tvu8SEnRlc3QxQGV4YW1wbGUxLmNvbRoFVGVzdDEgASgBMAIKLQoKSGVsbG8h3q2%2B8BISdGVzdDJAZXhhbXBsZTIuY29tGgVUZXN0MiABKAEwAgotCgpIZWxsbyHerb7xEhJ0ZXN0M0BleGFtcGxlMy5jb20aBVRlc3QzIAEoATACEAIYASAA
otpauth://totp/Example:alice@google.com?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP
General Usage
Usage: totp-qr [OPTIONS] [FILES]...
Arguments:
[FILES]... image-file|stdin, filename of "-" implies stdin
Options:
-a, --auth <AUTH> "otpauth-migration://offline?data=..." or "otpauth://totp/...?secret=SECRET"
-v, --verbose Verbose output
-e, --export Export account information as JSON
-i, --import Import JSON accounts
-u, --uri Output extracted URI's
-h, --help Print help
-V, --version Print version
Verbose Output (-v, --verbose)
$> totp-qr -v images/*.jpg
otpauth = otpauth-migration://offline?data=Ci0KCkhlbGxvId6tvu8SEnRlc3QxQGV4YW1wbGUxLmNvbRoFVGVzdDEgASgBMAIKLQoKSGVsbG8h3q2%2B8BISdGVzdDJAZXhhbXBsZTIuY29tGgVUZXN0MiABKAEwAgotCgpIZWxsbyHerb7xEhJ0ZXN0M0BleGFtcGxlMy5jb20aBVRlc3QzIAEoATACEAIYASAA
237769, Account { secret: "JBSWY3DPEHPK3PXP", issuer: "Test1", sha: "SHA1", digits: 6, period: 30 }
734660, Account { secret: "JBSWY3DPEHPK3PXQ", issuer: "Test2", sha: "SHA1", digits: 6, period: 30 }
021109, Account { secret: "JBSWY3DPEHPK3PXR", issuer: "Test3", sha: "SHA1", digits: 6, period: 30 }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
otpauth = otpauth://totp/Example:alice@google.com?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP
237769, Account { secret: "JBSWY3DPEHPK3PXP", issuer: "Example", sha: "SHA1", digits: 6, period: 30 }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Auth link (-a, --auth)
$> totp-qr --auth="otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30"
970700, ACME Co
Decode from stdin
$> echo 'secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ' | totp-qr
970700,
$> totp-qr < images/otpauth-migration-qr.jpg
237769, Test1
734660, Test2
021109, Test3
Import (-i, --import) / export (-e, --export) JSON Accounts
$> totp-qr -e images/*.jpg | totp-qr -iv
939954, Account { secret: "JBSWY3DPEHPK3PXP", issuer: "Test1", sha: "SHA1", digits: 6, period: 30 }
561818, Account { secret: "JBSWY3DPEHPK3PXQ", issuer: "Test2", sha: "SHA1", digits: 6, period: 30 }
787732, Account { secret: "JBSWY3DPEHPK3PXR", issuer: "Test3", sha: "SHA1", digits: 6, period: 30 }
939954, Account { secret: "JBSWY3DPEHPK3PXP", issuer: "Example", sha: "SHA1", digits: 6, period: 30 }
Dependencies
~15MB
~189K SLoC