DIY 一个 Gnuk Token

Gnuk 是一个开源实现的 GPG token, 它能在 STM32F103 上运行, 并且支持大部分的加解密方式

STM32 在这次疫情之间涨了许多次价格, 真的是理财产品, 所以这次我使用了国产能 Pin-2-Pin 替换的 主控芯片 GD32F103CBT6 来完成这个项目

Gnuk 的固件需要 128K 的 Flash 才能进行烧入, 大部分的 F103C8 都是纸面上 64K 的 Flash 但是实际上能用到最多 128K 的 Flash (ST 直接在硬件上没区分)

如果你使用 F103C8 进行烧入的话, 需要在 OpenOCD 的烧录前加入

set _FLASH_SIZE 0x20000

就能使用到额外的 64K 的 Flash 了

PCB 设定

gnuk-schema

这个是原理图, 因为 TypeC 鬼知道会不会过来一个 20V 的电压 (Bad USB), 所以这里用了一个耐压 24V 的 LOD.

其他的东西差不多就和最小系统差不多了, 因为 Gnuk 在写入固件之后无法直接在跑程序的时候使用 SWD 所以这里加了一个 Boot 选择. 我第一版没有这个选择每次重新刷固件都把芯片拆下来焊在 Bull Pill 上

gnuk-pcb

然后导出 Gerbers 文件交给嘉立创白嫖五元打样.

这里使用了 TypeC 的 SBU1 和 SBU2 来作为 SWD 的下载接口和对电脑的 USB 连接口 TypeC 大法好, 你可以自己造一块把 TypeC 这个线引出来的 PCB 板或者 干脆再加个 2.54mm 的 Pin 进行 SWD 刷写.

这里有点坑的是 STM32F103 的 DP 要加一个 1.5K 的上拉电阻来识别设备.

固件编译

# 安装 ARM gcc 和 git
nix-shell -p gcc-arm-embedded git

# Clone 源代码
git clone --recursive https://salsa.debian.org/gnuk-team/gnuk/gnuk.git

cd gnuk/src
bash configure --vidpid=234b:0000 --target=BLUE_PILL

make

然后固件就会出现在 gnuk/src/build/gnuk.bin 下面, 我们需要使用 OpenOCD 或者其他任意的设备进行固件的刷入

GD32 的坑

Gnuk 的固件会读取芯片的 serial number 并生成智能卡的 ID, 但是 GD32 中这个值是写死的, 读出来一直是一个值, 所以我们需要自己设定 serial number.

编辑 gunk/src/openpgp-do.c 找到 openpgpcard_aid 这一个变量

将最后的六个 uint8 修改位你想要的 serial number

前两位是 id 标识符, 如果是 0x00, 0x00 或者 0xff, 0xff 就会自动读取芯片 ID, 我们直接将前两位也修改掉就可以了

使用 Token

我这里使用 GPG Agent 作为 SSH key 来连接到别的机器上 这样重装系统的时候就不会忘记掉旧的 Key 了

在 Windows 上使用

首先先安装 Gpg4win 然后在设置中打开 SSH 支持

ssh-support-kleopatra

然后下载 rupor-github/wsl-ssh-agent 然后安装就可以使用 gpg 连接到服务器了

在 MacOS 上使用

我们安装 gpg-suite 然后

echo "default-cache-ttl 600
max-cache-ttl 7200
pinentry-program /usr/local/bin/pinentry-mac
enable-ssh-support" > ~/.gnupg/gpg-agent.conf

echo "# Start or re-use a gpg-agent.
gpgconf --launch gpg-agent
# Ensure that GPG Agent is used as the SSH agent
set -xg SSH_AUTH_SOCK ~/.gnupg/S.gpg-agent.ssh" > ~/.config/fish/conf.d/gpg-card.fish

这里是使用了 fish 作为 shell, 主要就是设定 ~/.gnupg/S.gpg-agent.ssh 作为 SSH_AUTH_SOCK

在 NixOS 上使用

programs.ssh.startAgent = false;
# Required for normal user access gpg smartcard
services.pcscd.enable = true;

programs.gnupg.agent = {
    enable = true;
    enableSSHSupport = true;
};

需要启动 pcscd 服务来管理智能卡, 才能让普通用户使用智能卡, 不然智能卡只有 root 用户能使用.