用 ST-Link 自制 GnuK

Last updated: 2024-11-14
Table of contents

写得没那么详细,自求多福吧!

本文较老且杂乱,推荐结合阅读其他网友总结的版本。要说有什么特别的就是搞明白了怎么自己添加按钮、如何升级既有key的固件。

展示图

  • 仓库地址: https://salsa.debian.org/gnuk-team/gnuk/gnuk
  • 支持STM32F103,STM32L432
  • 使用文档: https://www.fsij.org/doc-gnuk/index.html
  • 本文基于 GnuK 分支 STABLE-BRANCH-1-2(57fdadf)

介绍

GnuK 是一款开源的 USB PGP 智能卡,可以用来(相对更安全地)在不同的计算机上使用自己的 PGP 私钥。 本文将介绍如何将 ST-Link 的仿品、ST-Dongle 改造成 GnuK,并按原生的方式添加 确认按钮(Acknowledge Button)。

目标

  • 使用 ST-Link V2(主要是仿品)制作 GnuK
  • 原生方法 添加 自定义的确认按钮,而非网上广为流传的补丁
  • 升级既有 GnuK 的固件

环境

  • 操作系统: Manjaro
  • 软件
    • Python 3.9 (PipEnv)
    • GNU Arm Embedded Toolchain (10.3-2021.07)
    • GnuK STABLE-BRANCH-1-2(57fdadf)
  • ST-Link 等基于 STM32F103CxT6 的设备,经测试下列 MCU 可用
    • STM32F103C8T6(ST原版可当 128K Flash 版凑合)
    • STM32F103CBT6(ST原版,足量 128K Flash)
    • STM32F102CBT6(常见 ST-Link V2 仿品所用 MCU 之一,没错就是F102不是F103)
    • STM32GC102CBT6(貌似是中国大陆专供版,ST-Link 仿品候选 MCU 之一)

流程概要

  1. 分析和修改固件、硬件,也就是添加按钮
  2. 为 ST-Link 刷写固件
  3. 编辑 GnuK 信息

修改软硬件以添加自定义按钮

GnuK 较新版本是支持按钮操作的。一开始我不太会用,学习一段时间单片机后,明白了如何修改 GnuK 定义的按钮。

GnuK 通过目标版配置信息提前配置好各个 IO 的模式。其中 ST-Link 所引出的部分引脚可以作为开关信号输入。

选择合适的引脚作为按钮输入

根据网上流传的相关原理图,PA5(CLK)引脚可以作为一个上拉输入,因此我在 PA5 和 GND 之间焊接了一个按钮。

GnuK貌似默认把所有没用上的IO配置为内部上拉了。那么只要修改按键响应逻辑就行。

修改软件

首先得有一份软件吧。

git clone --recursive https://salsa.debian.org/gnuk-team/gnuk/gnuk.git gnuk

若想添加对更多开发板的支持,请分别修改src/configure(添加配置参数),chopstx/board(添加主板IO配置与序列号),chopstx/contrib(添加主板序列号并配置相关功能,如按钮)。我通过此方法简单适配了下WeAct工作室的BluePill Plus。

修改确认按钮的映射,需要对 STM32 的中断线路有一定了解。按钮相关代码在chopstx/contrib/ackbtn-stm32f103.c,我将 PA5 对应的中断线路加入其中的 switch 语句,也就换了个按钮。在文末可以找到我的补丁(适用于 57fdadf)。

Note

在新版(v2.x)上,该补丁在配合git 3-way merge功能时仍可应用。 参考命令:cd chopstx && git am -3 add-button-for-stdongle.patch

编译固件

接下来就基本没什么技术含量了,简单记录一下编译指令

# assuming pwd is gnuk
cd src

# recommended(?) for v1.2.19, for 2.1+, it's required by default
export kdf_do=optional

# configure once
./configure --enable-factory-reset --target=ST_DONGLE --vidpid=234b:0000 --enable-certdo

# then build
make

src/build 文件夹中的 gnuk.bingnuk.hex 就是生成的固件。前者适用于直接适用下载器从对应基地址下载。 后者更适合用于调试器调试。

刷写固件

方法一:使用调试器

STM32F1x 怎么用调试器写入固件我就不说了,很多方法啊。ST-Link、JLink、CMSIS-DAP、BlackMagic Probe、UART DFU,etc.。

我用BlackMagic Probe,可以参考BMP 的 Wiki。总之我很喜欢这个调试器,GDB 深度整合,软件依赖很少,安利一下。

在修改这篇文章时,我发现了这篇文章,对初次接触 GnuK 的朋友有很大参考价值,推荐阅读。

方法二:使用升级软件升级旧的 GnuK

Danger

此步骤会永久性地抹除旧 GnuK 上的密钥,请三思而后行!

Note

v2.1 开始,RSA支持被移除,也因此从旧版(v1.2.x)升级至2.x需要使用旧版的脚本(旧版升级时用到了RSA验证)。经测试仍然可以使用新版的编译产物(gnuk.bin,regnual.bin)。不过保险起见,建议确保升级脚本、regnual.bin、当前固件三者版本相同。 参考报错内容(从v1.2.20升级至v2.2):

$ python upgrade_by_passwd.py 
Admin password: 
Device: 
Configuration: 1
Interface: 0
../regnual/regnual.bin: 4728
../src/build/gnuk.bin: 96256
CRC32: e7b26341

Device: 
Configuration: 1
Interface: 0
Traceback (most recent call last):
File "/gnuk-build/gnuk/tool/upgrade_by_passwd.py", line 171, in <module>
    main(wait_e, passwd, data_regnual, data_upgrade[4096:])
File "/gnuk-build/gnuk/tool/upgrade_by_passwd.py", line 66, in main
    gnuk.cmd_external_authenticate()
File "/gnuk-build/gnuk/tool/gnuk_token.py", line 477, in cmd_external_authenticate
    raise ValueError("%02x%02x" % (sw[0], sw[1]))
ValueError: 6985

这需要用到随 GnuK 一起分发的 regnual(reGNUal,real+GNU)。由于相关升级程序使用到了 Python,请自行补足依赖。对于使用 Pipenv 的用户,可以使用文末附件中的 Pipfile 重建环境。这里记录一下升级操作。当然也可以参考这两篇我参考的原始材料:official docRemy’s tutorial

cd gnuk
cd regnual
# 在此之前需确保执行过一遍src里的configure
make
cd ../tool
# 先把 pgp agent 干掉,避免冲突
gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
# 运行升级脚本
python upgrade_by_passwd.py
# 根据提示完成接下来的操作
# 可能需要输入管理员密码,然后等待更新结束
# 若key为出厂设置,可以用 -f 避免输入密码
# python upgrade_by_passwd.py -f
# 如果平台名称发生了变化(主要在适配新平台时),需要改用下面这句,具体看脚本源码
# python upgrade_by_passwd.py -s

regnual 的固件小 Bug

对于 v1.2.19,你可能需要注释掉 regnual/regnual.c:29 以消除一个类型定义冲突。 v1.2.20 修好了这个 Bug。

配置 GnuK 以启用确认按钮

默认情况下确认按钮是不启用的。需要进行配置。

生成或导入密钥

必须先有密钥,才能改密码、启用确认按钮、修改其它信息等等。

先参考官方使用文档,配置智能卡信息,生成密钥对,并写入相关信息。

一些步骤: + 在 GnuK 上生成密钥或将私钥转移到 GnuK 上; + 配置Gnuk信息(名称,称谓,语言偏好,公钥地址,密码,管理员密码,恢复密码); + 其它进阶配置;

生成密钥部分教程原本的讲得并不清楚,如果用了默认配置快速生成密钥对,则需要进入密钥编辑模式进一步修改,也就是gpg --expert --edit-key [fingerprint]

实际上教程里都是在修改原来的Key,同样也是gpg --expert --edit-key [fingerprint]

懒了,部分细节可以参考本文对应的英文文章(outdated)

启用确认按钮

要装 GnuPG v2.3 或更新版本,否则没这个功能。archlinux/pacman 用户可以使用 aur/gnupg23 现在最新版本都2.4+了,没啥限制。

然后按下面的步骤启用对应的确认按钮。

gpg --card-edit  # 编辑卡信息
gpg/card> admin  # 进入管理员模式
gpg/card> uif    # 查看相关帮助
gpg/card> uif 1 on  # 开启签名确认
gpg/card> uif 2 on  # 开启解密确认
gpg/card> uif 3 on  # 开启身份验证确认
gpg/card> q  # quit

我个人就开了前两个确认,其它的感觉有点麻烦,开启确认是为了避免误操作和后台操作罢了。

其它说明

  • 想使用全部最新功能(比如开启确认按钮),必须使用最新的开发板gnupg(2.3),下载地址在此
  • ST_DONGLE编译平台有bug,不仅用不了 Button,make clean 也清不干净,需要删除src重新构建待定问题根源,可能 flash 一定要擦除一遍才能正常使用 GnuK。
  • 本条写给超级小白(包括曾经的我):对于新的板子,button 可以用 AFIO_EXTICR1_EXTI0_PA,这里用到的是外部中断,线路/中断号/管脚要匹配。有些中断号是复用的,注意一下。
  • 如果 MCU 的 Flash 不够用,可以关闭部分功能、删除对部分算法的支持。有的时候 64K Flash 也可以刷 GnuK,但 reGNUal 升级程序会出现运行错误,也就不能用原生方法升级,务必注意。
  • 对于 oh-my-zsh 用户,想启用 PGP+SSH,可以直接启用 gnupg 插件。
  • 拆 ST-Link 针脚,可以先把胶座去掉,然后一根根将针焊下来,最后配合不锈钢刮板趁热将焊盘上的锡刮干净。

文件分享