因为最近项目需要蓝牙Dongle来抓包,所以就买了个nrf52840开发板,顺便发现还可以捣鼓一下U2F、FIDO密钥,所以就有了本文,基于Github上的nRF52-U2F项目,这个项目支持的设备是基于nrf52840的mdk开发板(nRF52840 DK)和Makerdiary nRF52840 Micro Dev Kit USB Dongle(注意:不是Nordic官方的nRF52840 Dongle),某宝也有售,就是价格有些稍贵。如果你使用的是Nordic官方的nRF52840 Dongle或者相同电路的平替产品,最好是使用google/OpenSK: OpenSK is an open-source implementation for security keys written in Rust that supports both FIDO U2F and FIDO2 standards. (github.com)项目,在文末的小节里有描述。

nRF52 FIDO U2F Security Key

nRF52840 - Bluetooth 5.2 SoC - nordicsemi.com

引用一下官方的Soc介绍:

主要功能特点:多协议蓝牙5.2 SoC,支持低功耗蓝牙、蓝牙Mesh、NFC、Thread和Zigbee

nRF52840 SoC是nRF52系列中最先进的一员。它可以满足需要协议并发性、丰富外围设备和复杂应用所面临的挑战。它为闪存和RAM提供了充足的内存,而这些正是高要求应用的必备条件。

nRF52840是具有完全协议并发能力的多协议SoC。它支持低功耗蓝牙、蓝牙Mesh、Thread、Zigbee、802.15.4、ANT和2.4 GHz专有协议栈。

nRF52840基于带有浮点单元的32位ARM® Cortex™-M4 CPU,主频为64 MHz。内置NFC-A标签用于简化的配对和支付解决方案。本芯片内置ARM TrustZone® CryptoCell密码算法单元,可独立于CPU高效执行密码算法任务。它有许多数字外设和接口,如高速SPI和QSPI接口,用于连接到外部闪存和显示器,PDM和I2S连接数字麦克风和音频;还有一个全速USB设备,用于数据传输和作为电源为电池充电。

通过精密的片上自适应电源管理系统,实现了极低的功耗。

只能说我确实觉得很好用,就是最近价格太高了。

image-20220526000615262.webp

nrf52840-mdk-usb-dongle-pinout.webp

编译固件

我使用的是Ubuntu来编译固件,如果是其他系统可以看Building the Firmware - nRF52 FIDO U2F Security Key (makerdiary.com)

1.安装所需依赖

# On Ubuntu
$ sudo apt-get install build-essential checkinstall openssl git

2.拉取makerdiary/nrf52-u2f项目的源代码

git clone --recursive https://github.com/makerdiary/nrf52-u2f

3.下载nRF5 SDK

在官网可以下载,nRF5 SDK downloads - nordicsemi.com。我们所需的版本是:15.2.0,对应的压缩包文件是:nRF5_SDK_15.2.0_9412b96

image-20220526014342117.webp

解压到nrf52-u2f/nrf_sdks/目录中。

image-20220526012735789.webp

目录结构为:

./nrf52-u2f/
├── LICENSE.md
├── README.md
├── boards
├── certs
├── docs
├── external
├── firmware
├── include
├── material
├── mkdocs.yml
├── nrf_sdks
│   ├── README.md
│   └── nRF5_SDK_15.2.0_9412b96
├── open_bootloader
├── source
└── tools

4.下载gcc-arm-none-eabi

从arm官网可以下载到GNU Arm Embedded Toolchain编译链工具,Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer

此次需要的版本是:

Linux 64-bit

File: gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 (95.90 MB)

我下载后放到了/home/cyqsd/Project/toolchain目录。

使用tar xjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2解压。

最好还配置一下全局环境变量,可以使用vi ~/.bashrc配置环境。

export PATH="/home/cyqsd/Project/toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin:$PATH"

source ~/.bashrc生效 一下,前面都弄正确的话,此步骤应该可以得到下面的输出:

cyqsd@ubuntu:~/Project/toolchain$ arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
COLLECT_LTO_WRAPPER=/home/cyqsd/Project/toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/../lib/gcc/arm-none-eabi/6.3.1/lto-wrapper
Target: arm-none-eabi
Configured with: /tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/src/gcc/configure --target=arm-none-eabi --prefix=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native --libexecdir=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/lib --infodir=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/share/doc/gcc-arm-none-eabi/info --mandir=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/share/doc/gcc-arm-none-eabi/man --htmldir=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/share/doc/gcc-arm-none-eabi/html --pdfdir=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/share/doc/gcc-arm-none-eabi/pdf --enable-languages=c,c++ --enable-plugins --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-nls --disable-shared --disable-threads --disable-tls --with-gnu-as --with-gnu-ld --with-newlib --with-headers=yes --with-python-dir=share/gcc-arm-none-eabi --with-sysroot=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/install-native/arm-none-eabi --build=x86_64-linux-gnu --host=x86_64-linux-gnu --with-gmp=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/build-native/host-libs/usr --with-mpfr=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/build-native/host-libs/usr --with-mpc=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/build-native/host-libs/usr --with-isl=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/build-native/host-libs/usr --with-libelf=/tmp/jenkins-GCC-6-buildandreg-223_20170621_1498033910/build-native/host-libs/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-pkgversion='GNU Tools for ARM Embedded Processors 6-2017-q2-update' --with-multilib-list=rmprofile
Thread model: single
gcc version 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437] (GNU Tools for ARM Embedded Processors 6-2017-q2-update)

4.配置编译链工具

然后进入/home/cyqsd/Project/nrf52-u2f/nrf_sdks/nRF5_SDK_15.2.0_9412b96/components/toolchain/gcc配置一下Makefile.posix

教程里面推荐的是:

GNU_INSTALL_ROOT := $(HOME)/gcc-arm-none-eabi/gcc-arm-none-eabi-6-2017-q2-update/bin/
GNU_VERSION := 6.3.1
GNU_PREFIX := arm-none-eabi

我写的是:

GNU_INSTALL_ROOT := /home/cyqsd/Project/toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/
GNU_VERSION := 6.3.1
GNU_PREFIX := arm-none-eabi

注意这个,我开发环境里面还有其他编译链工具,我也选用的覆盖:

:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值

5.配置并生成自签名证书

进入/home/cyqsd/Project/nrf52-u2f/certs。把myserver.cnf.example更名为myserver.cnf,里面的内容酌情修改一下。

回到~/Project/nrf52-u2f/tools,使用./generate-certs.sh来生成一份证书,类似下面这样(内容有手动改动):

cyqsd@ubuntu:~/Project/nrf52-u2f/tools$ ./generate-certs.sh
read EC key
Private-Key: (256 bit)
priv:

pub:
  
ASN1 OID: prime256v1
NIST CURVE: P-256
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, O = cyqsd, CN = www.cyqsd.cn
        Validity
            Not Before: May 25 18:08:45 2022 GMT
            Not After : May 22 18:08:45 2032 GMT
        Subject: C = CH, O = cyqsd, CN = www.cyqsd.cn
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
      
                ASN1 OID: prime256v1
                NIST CURVE: P-256
    Signature Algorithm: ecdsa-with-SHA256

Converting EC key to text...
read EC key
writing EC key
Successfully Completed!
The private key and certificate are stored in certs/keys.c
Bye bye~

6.编译U2F固件

因为是使用的硬件是nrf52840-mdk-usb-dongle,所以进入这个目录。

/home/cyqsd/Project/nrf52-u2f/boards/nrf52840-mdk-usb-dongle/armgcc

如果你的SDK版本并不是前面写的这个,还需要在当前目录的Makefile中改为正确的版本。

PROJECT_NAME     := nrf52_u2f_nrf52840_mdk_usb_dongle
TARGETS          := nrf52840_xxaa
OUTPUT_DIRECTORY := _build

SDK_ROOT := ../../../nrf_sdks/nRF5_SDK_15.2.0_9412b96
PROJ_DIR := ..

$(OUTPUT_DIRECTORY)/nrf52840_xxaa.out: \
  LINKER_SCRIPT  := nrf52_u2f_gcc_nrf52.ld

都觉得正常了就可以使用make clean来清理一下旧文件和make来编译了。

如果中途出现了:

Linking target: _build/nrf52840_xxaa.out
arm-none-eabi-gcc: error: ../../../nrf_sdks/nRF5_SDK_15.2.0_9412b96/external/micro-ecc/nrf52hf_armgcc/armgcc/micro_ecc_lib_nrf52.a: No such file or directory
../../../nrf_sdks/nRF5_SDK_15.2.0_9412b96/components/toolchain/gcc/Makefile.common:292: recipe for target '_build/nrf52840_xxaa.out' failed
make: *** [_build/nrf52840_xxaa.out] Error 1

则参考compile error · Issue #14 · makerdiary/nrf52-u2f (github.com)

进入/home/cyqsd/Project/nrf52-u2f/nrf_sdks/nRF5_SDK_15.2.0_9412b96/external/micro-ecc目录,执行一下build_all.sh

完成后,回到前面的目录,重新编译,就能成功了。

image-20220526023112764.webp

armgcc/_build/目录中的nrf52840_xxaa.hex就是固件。

7.编译Bootloader

进入/home/cyqsd/Project/nrf52-u2f/open_bootloader/nrf52840-mdk-usb-dongle/armgcc目录。同样使用make命令来编译。

image-20220526024043839.webp

armgcc/_build/目录中的nrf52840_xxaa_mbr.hex就是bootloader文件。

8.合并固件(可选)

从官网下载到nrf-command-line-tools,这个版本用最新的也行,我使用的是nrf-command-line-tools-10.15.4_Linux-amd64.tar.gz。解压到/home/cyqsd/Project/nrf-command-line-tools中:

使用tar -xvf nrf-command-line-tools-10.15.4_Linux-amd64.tar.gz

配置/home/cyqsd/Project/nrf-command-line-tools/nrf-command-line-tools/bin目录到环境变量中,同前面环境配置的操作,目录中有用于固件合并的mergehex工具。

export PATH="/home/cyqsd/Project/nrf-command-line-tools/nrf-command-line-tools/bin:$PATH"

回到/home/cyqsd/Project/nrf52-u2f/open_bootloader/nrf52840-mdk-usb-dongle/armgcc目录,使用make mergehex命令,即可合并固件完毕。

image-20220526025430158.webp

合并命令实际上做的工作是下面的内容:

# Merge the app and mbr
mergehex:
    @echo Merging nrf52840_xxaa.hex and mbr_nrf52_2.3.0_mbr.hex
    mergehex -m $(SDK_ROOT)/components/softdevice/mbr/nrf52840/hex/mbr_nrf52_2.3.0_mbr.hex $(OUTPUT_DIRECTORY)/nrf52840_xxaa.hex -o $(OUTPUT_DIRECTORY)/nrf52840_xxaa_mbr.hex

到这里整个编译步骤就完成了,就用合并好的文件烧录即可。

烧写固件

makerdiary上已经有很详细的烧写步骤了,我就不赘述了,nRF Connet for Desktop上是全图形化操作。Upgrade U2F Firmware with nRF Connet for Desktop

image-20220526010012472.webp

截图中的固件是我用的开源项目中的固件补充截图的,实际使用就使用自己新编译的就行了。

image-20220527024907587.webp

还可以使用Python下的nrfutil工具来完成烧录。或者Segger J-Link、OpenOCD、pyOCD等一大堆工具均可。

官方Dongle支持(未测试实践)

前面提到了nRF52840 Dongle的官方版本,并不能直接刷nRF52-U2F项目,因为引脚定义不一样,不过理论上完全可以通过修改引脚来实现官方Dongle,我也看见GitHub上有人在提问,但是并没有人回复。

boards\nrf52840-mdk-usb-dongle\config 目录下有custom_board.h配置文件,理论上按照现有设备重新修改引脚就可以使用,但是因为时间关系我就没去试了,还是直接推荐OpenSK项目比较好。

下面的代码只截取了一部分,仅供参考。

#define BUTTONS_NUMBER 1

#define BUTTON_1       NRF_GPIO_PIN_MAP(0,18)
#define BUTTON_PULL    NRF_GPIO_PIN_PULLUP

#define BUTTONS_ACTIVE_STATE 0

#define BUTTONS_LIST { BUTTON_1}

#define BSP_BUTTON_0   BUTTON_1

image-20220605181821660.webp

OpenSK

还可以使用这个项目来实现U2F、FIDO密钥。

google/OpenSK: OpenSK is an open-source implementation for security keys written in Rust that supports both FIDO U2F and FIDO2 standards. (github.com)

OpenSK是谷歌的开源项目,同样是开源的FIDO U2F项目,使用的硬件也是nRF52840,支持下面的硬件:

可以使用项目提供的setup.sh来自动化编译,这比较简单:

git clone https://github.com/google/OpenSK.git
cd OpenSK
./setup.sh

烧写时可以选用下列方式:

OpenOCD: ./deploy.py --board=nrf52840_dongle --opensk --programmer=openocd
pyOCD: ./deploy.py --board=nrf52840_dongle --opensk --programmer=pyocd
Custom(导出Hex文件): ./deploy.py --board=nrf52840_dongle --opensk --programmer=none

平替品 E104-BT5040U

我也买了E104-BT5040U,引脚是兼容官方Dongle的,属于国产版本,只是亿佰特官方的这个型号不仔细看容易分不太清楚。。。。还有要注意的就这个塑料外壳虽然挺好看,挺坚固的,但是没有给按钮打孔,这就导致U2F要按下按钮确认的时候操作不到,所以要么就用的时候不装壳子,或者在壳子上开一个孔。因为电路上的按钮、LED灯与官方Dongle是一致的,不用额外担心。

image-20220526000421834.webp

参数对比:

O1CN01ZjI56612045.webp

IMG_20220314_145038.webp

IMG_20220314_145041.webp

IMG_20220314_145027.webp

IMG_20220314_145032.webp

因为并不需要什么额外的外设,所以就使用的时候就核对一下引脚,看是否与项目支持的是否相同就行。

image-20220526010348343.webp

引脚序号引脚名称引脚方向引脚用途
36RSTRESET复位按键
37SWP1.06功能按键
38LED1RGB三色LEDR(红色):P0.08;G(绿色):P1.09;B(蓝色):P0.12
39LEDLEDP0.06

nRF Connect for Desktop

可以从官网上下载到:nRF Connect for Desktop

自带非常好用的蓝牙调试工具和RSSI分析工具。

2022-03-12 215641.webp

image-20220526000539861.webp

文章目录