#totp #2fa #hmac #otp #authentication #command-line #command-line-tool

应用 totp-qr

从QR图像、URI或otpauth迁移链接显示optauth URI和TOTP令牌

4个版本

0.2.1 2023年10月21日
0.2.0 2023年10月20日
0.1.1 2023年10月18日
0.1.0 2023年10月18日

919命令行工具 中排名

每月下载 23

MIT 许可

93KB
1K SLoC

totp-qr   Crates.io Crates.io

命令行工具,用于从QR图像中提取otpauth字符串并生成相应的TOTP

为什么?我需要将之前保存的QR图像、截图和Google Authenticator导出图像中的文本SECRET编码导入到其他应用中(例如 KeePassXCProton Pass

这个项目的动机始于密码管理。我对我的密码管理工具很满意,如 KeePassXCpassiTerm2密码管理器(现在不能没有它了),但我缺乏对TOTP参数和密码的可见性和便携性。

此工具使用


项目状态

  • 等待解决 SIGPIPE 的一般CLI Unix工具以避免“broken pipe”。
  • 解决方案是修改stdout并使用 writeln!(stdout)? 而不是 println!(),如下所示
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

在shell函数中使用totp-qr安全地查看令牌

  1. 安装 totp-qr,例如 cargo install totp-qr 或构建 cargo install --path .
  2. 将您的QR图像收集到一个目录中
  3. 运行 scripts/mk-totp-func.sh 目录
  4. 检查、复制并添加到您的 ~/.bashrc

创建shell函数,操作步骤

图像目录包含2个示例二维码

  1. otpauth-totp-qr.jpg 包含1个账户: "otpauth://totp/..."
  2. otpauth-migration-qr.jpg 包含3个账户: "otpauth-migration://offline?data=..."
$> totp-qr --uri images/otpauth-totp-qr.jpg
otpauth://totp/Example:[email protected]?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP

$> totp-qr --uri images/otpauth-migration-qr.jpg
otpauth-migration://offline?data=Ci0KCkhlbGxvId6tvu8SEnRlc3QxQGV4YW1wbGUxLmNvbRoFVGVzdDEgASgBMAIKLQoKSGVsbG8h3q2%2B8BISdGVzdDJAZXhhbXBsZTIuY29tGgVUZXN0MiABKAEwAgotCgpIZWxsbyHerb7xEhJ0ZXN0M0BleGFtcGxlMy5jb20aBVRlc3QzIAEoATACEAIYASAA

otpauth数据应保持私密,可以使用 OpenSSL 加密数据(密码: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 加密URI并输出名为totp()的Bash函数

$> ./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
}


整合所有内容

$> ./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
}

提示:如果您正在使用Mac的 iTerm2,请查看 密码管理器(快捷键:⌥ ⌘ F)以提供密码

totp()按发行者排序显示令牌

$> totp
enter AES-256-CBC decryption password:
757676, Example
757676, Test1
255080, Test2
476239, Test3

使用totp -e查看账户详情作为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查看URI

$> totp -u
enter AES-256-CBC decryption password:
otpauth-migration://offline?data=Ci0KCkhlbGxvId6tvu8SEnRlc3QxQGV4YW1wbGUxLmNvbRoFVGVzdDEgASgBMAIKLQoKSGVsbG8h3q2%2B8BISdGVzdDJAZXhhbXBsZTIuY29tGgVUZXN0MiABKAEwAgotCgpIZWxsbyHerb7xEhJ0ZXN0M0BleGFtcGxlMy5jb20aBVRlc3QzIAEoATACEAIYASAA
otpauth://totp/Example:[email protected]?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP


通用用法

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

详细输出(-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:[email protected]?issuer=Example&period=30&secret=JBSWY3DPEHPK3PXP
237769, Account { secret: "JBSWY3DPEHPK3PXP", issuer: "Example", sha: "SHA1", digits: 6, period: 30 }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$> totp-qr --auth="otpauth://totp/ACME%20Co:[email protected]?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30"
970700, ACME Co

从stdin解码

$> echo 'secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ' | totp-qr
970700,

$> totp-qr < images/otpauth-migration-qr.jpg
237769, Test1
734660, Test2
021109, Test3

导入(-i, --import)/导出(-e, --export)JSON账户

$> 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 }

依赖项

~22MB
~186K SLoC