从 Yubikey 到 PGP 靓号计算

为什么一个群能从团购 Yubikey 发展到 PGP 靓号计算,是人性的扭曲还是科学的沦丧?请看本篇博客,带你走入科学算号的新天地。一句话总结:使用 CPU/GPU 进行哈希计算,得到具有你想要的 Key ID 的私钥。

我的个人实践结果为使用 AutoDL 提供的一张 Nvidia 3090 显卡计算约 12 小时,得到 29 个后 12 位连号的 Ed25519 私钥,其中包含一个 14 位和三个 13 位连号的私钥。下面详细介绍我的科学算号过程。

为简单起见,本文只介绍使用 GPU 计算的过程,其核心思想是调用 CPU 来生成私钥,之后改变生成时间,使用 GPU 哈希计算得到新的 KeyID,符合指定标准则输出。

配置环境

首先注册 AutoDL 的账号,创建包含一张 Nvidia 3090 显卡的实例,建议选择镜像为 TensorFlow 2.9.0。新账号赠送 10 元代金券,约能白嫖运行 6 小时,实测 ed25519 密钥的计算速度约为 10 G hashes/s。然后通过 SSH 连接或直接使用 JupyterLab 里面的终端来使用。当然你也可以在任意包含 GPU 的机器运行。

安装对应库和算号程序,这里使用的是 comicchang 修改后的 gpg-fingerprint-filter-gpu 程序。

1
2
3
$ apt update && apt install libgcrypt20-dev
$ git clone https://github.com/comicchang/gpg-fingerprint-filter-gpu.git
$ cd gpg-fingerprint-filter-gpu && make

运行脚本

编辑项目中的 generate_batch_keys.sh 脚本,修改匹配条件。其默认为 "x{11}|xxxxxxy{6}|wwwwxxxxyyyyzzzz|xxxxy{8}|xxxxxxxxyyyy|(wxyz){4}|1145141919810|23{10}",具体含义参考 README 内容,可以简单修改为 "x{12}",即任意 12 位连号,也可以自定义其他的匹配条件。

之后运行该脚本,参数分别为 GPU_INDEXKEY_COUNTOUTPUT_FOLDER。只需时间和一点点运气,你就可以得到自己想要的靓号了。鉴于我运行了 12 小时就得到了一个 14 位的靓号,可能运气尚可吧。具体概率没有计算,欢迎留言补充。

1
$ sh generate_batch_keys.sh 0 100 keys

缝合密钥

算号得到的私钥还需要小小处理一下才能正常使用。由于主钥生成时间必须早于子钥,因此要根据私钥的时间戳选择合适的主钥。当然你也可以用一个主密钥同时来签名、认证,但这样就没法填满 Yubikey 的三个插槽不够安全。

首先把生成的私钥导入 GPG,然后查看私钥的时间戳和 Keygrip,pub 行中 keyid 后面的数字就是时间戳。按照时间戳先后选好主钥后,先记录想要添加为子钥的 Keygrip 和时间戳。

1
2
3
4
5
6
7
8
9
10
11
$ gpg --allow-non-selfsigned-uid --import keys/*
$ gpg -k --with-keygrip --with-colons

pub:i:255:22:0AC618A17D75C510:1634712824:::-:::sca:::::ed25519:::0:
fpr:::::::::D11B34303C672C61FD3DC52C0AC618A17D75C510:
grp:::::::::B166ABC702EDA25664261C5269B942CFCF6C1307:
uid:-::::::1E23F740019D67CEA575A8B356807D296C2D0536::NONAME::::::::::0:
pub:i:255:22:5CDC2807F020BF12:1650264519:::-:::sca:::::ed25519:::0:
fpr:::::::::FB5816BC225D252CCE20A8F75CDC2807F020BF12:
grp:::::::::EAA9C15CEA82276F4925346702D211F3C4204ACA:
uid:-::::::1E23F740019D67CEA575A8B356807D296C2D0536::NONAME::::::::::0:

以上面为例,我们选择生成时间较晚的私钥 5CDC2807F020BF12 添加为子钥,其 Keygrip 和时间戳分别为 EAA9C15CEA82276F4925346702D211F3C4204ACA1650264519,首先添加自己的 uid,之后添加子钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ gpg --edit-key --expert --ignore-time-conflict --faked-system-time="1650264519\!" 0AC618A17D75C510

gpg: WARNING: running with faked system time: 2022-04-18 06:48:39
Secret key is available.

sec ed25519/0AC618A17D75C510
created: 2021-10-20 expires: never usage: SCA
trust: unknown validity: unknown
[ unknown] (1). NONAME

# 把 5CDC2807F020BF12 添加为子钥

gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 13
Enter the keygrip: EAA9C15CEA82276F4925346702D211F3C4204ACA

# 后续自行选择即可

注意,时间需要指定成添加的子钥的时间戳,否则你会发现添加后的子钥指纹变成了新的,实际上这正是算号的原理。

基于本次算号结果,我现在使用的 PGP Key ID 是 7C99999999999999,完整公钥见这里。缝合好的密钥使用可以参考我的文章:Canokey 指南:OTP,FIDO2,PGP 与 PIV。祝算号顺利。

参考