{"id":13676148,"url":"https://github.com/gl-sergei/u2f-token","last_synced_at":"2026-02-03T02:48:40.333Z","repository":{"id":24195180,"uuid":"98025917","full_name":"gl-sergei/u2f-token","owner":"gl-sergei","description":"u2f token firmware for stm32f103 and efm32hg boards","archived":false,"fork":false,"pushed_at":"2023-07-23T07:45:31.000Z","size":663,"stargazers_count":349,"open_issues_count":11,"forks_count":57,"subscribers_count":24,"default_branch":"master","last_synced_at":"2024-11-11T17:45:46.286Z","etag":null,"topics":["efm32hg","fido-u2f","stm32f103","u2f"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gl-sergei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-22T11:04:37.000Z","updated_at":"2024-10-20T23:04:10.000Z","dependencies_parsed_at":"2024-11-11T17:44:02.647Z","dependency_job_id":null,"html_url":"https://github.com/gl-sergei/u2f-token","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl-sergei%2Fu2f-token","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl-sergei%2Fu2f-token/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl-sergei%2Fu2f-token/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gl-sergei%2Fu2f-token/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gl-sergei","download_url":"https://codeload.github.com/gl-sergei/u2f-token/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251426699,"owners_count":21587634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["efm32hg","fido-u2f","stm32f103","u2f"],"created_at":"2024-08-02T13:00:19.188Z","updated_at":"2026-02-03T02:48:35.277Z","avatar_url":"https://github.com/gl-sergei.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/gl-sergei/u2f-token/.github%2Fworkflows%2Fc-cpp.yml)\n![GitHub all releases](https://img.shields.io/github/downloads/gl-sergei/u2f-token/total)\n[![Latest Release](https://img.shields.io/github/release/gl-sergei/u2f-token.svg)](https://github.com/gl-sergei/u2f-token/releases/latest)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n\n\n# U2F-TOKEN firmware for STM32F103 and EFM32HG boards\n\nTurns your cheap STM32F103 or EFM32HG board into U2F token.\n\n## Supported boards\n\nU2F-TOKEN is known to work on:\n\n- [Tomu board](https://tomu.im/) (EFM32HG) is an excellent device to use for U2F\n  as it can sit entirely inside of your USB port (and it is opensource)\n- Blue pill (STM32F103) as well as Black pill\n- Countless ST32F103 based Chinese St-Link V2 clones can be turned into U2F\n  devices with U2F-TOKEN\n- Variety of Maple Mini clones which can be found on Aliexpress\n\n## Udev rules\n\nOn Linux you need to add the following rules to be able to use your device as\nnon root user. Create the file `/etc/udev/rules.d/10-u2f-token.rules` (as root)\nand paste in the following lines:\n\n``` text\nACTION==\"add|change\", KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"16d0\", ATTRS{idProduct}==\"0e90\", TAG+=\"uaccess\"\nACTION==\"add|change\", SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"16d0\", ATTRS{idProduct}==\"0e90\", TAG+=\"uaccess\"\n```\n\n### Using webauthn from snap packages\n\nSnap has additional security measures so that you will need to add a tag to the hidraw rule\nfor each snap app that you want to have access to the token.\n\nFor Chromium and Firefox (snap since ubuntu 21.10) this then reads:\n``` text\nACTION==\"add|change\", KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"16d0\", ATTRS{idProduct}==\"0e90\", TAG+=\"uaccess\", TAG+=\"snap_firefox_firefox\", TAG+=\"snap_chromium_chromedriver\"\n```\n\n## Installing using prebuilt release binaries\n\n### Requirements\nPython 3.6 or later and pip are needed. You will also need the `hidapi` library:\n\n* To install on OS X run `brew install hidapi`\n* To install on Ubuntu run `sudo apt install libhidapi-hidraw0 python3-hid`\n* To install on Archlinux, run `pacman -Sy hidapi`\n\nIf you are on Linux, you will also need to install the aforementioned Udev\nrules.\n\n### Flash binary\n\nDownload the binary suitable for your board at [releases page][releases].\n\n[releases]: https://github.com/gl-sergei/u2f-token/releases\n\nBinaries for Tomu are built with bootloader support, use the following command\nto flash the firmware:\n\n``` sh\ndfu-util -d 1209:70b1 -D u2f-TOMU.bin\n```\n\nBinaries for STM32 boards are built without bootloader support, you need to\nflash the firmware using SWD or JTAG interface. Example using OpenOCD and\nSTLINK-V2:\n\n``` sh\nopenocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'init' -c 'halt' -c 'flash write_image erase unlock u2f-BLUE_PILL.bin  0x08000000' -c 'exit'\n```\n\n(replace BLUE_PILL with appropriate board name)\n\n### Initialize device\n\nAfter flashing device with binary it requires to be initialized.\nRelease binaries come with readout protection enabled and without attestation certificate provisioned.\nTo initialize the device, clone this repository and run\n(Python 3.6+ and the hidapi library are required):\n\n``` sh\npip3 install -r requirements.txt --user\ncd src/cert\npython3 certtool init\n```\n\nYou will see something similar to:\n\n``` text\nTrying to initialize device HIDDevice:\n    USB_16d0_0e90_14100000 | 16d0:e90 | unknown | U2F-token (STM32) | 1.00\n    release_number: 256\n    usage_page: 61904\n    usage: 1\n    interface_number: -1\nSuccess\n```\n\nThe above command will upload pre-generated `attestaion.der` from this\nrepository to the device. If for whatever reason you want to use your own\ncertificate, tweak and run `./gen.sh` to generate it.\n\nTest your key with latest Chrome or Firefox browser using [this page][yubico-test].\n\n[yubico-test]: https://demo.yubico.com/webauthn-technical/\n\n## Building and flashing\n\n### Requirements\n\n#### Build tools\n\nInstall and setup Command Line tools for Xcode on macOS.\n\nInstall build-essentials package on Debian/Ubuntu:\n\n``` sh\nsudo apt install build-essential\n```\n\n#### GNU Toolchain for ARM Embedded Processors\n\nInstalling on macOS with homebrew:\n\n``` sh\nbrew tap osx-cross/arm\nbrew install arm-gcc-bin\n```\n\nInstalling on Debian/Ubuntu:\n\n``` sh\nsudo apt-add-repository ppa:team-gcc-arm-embedded/ppa\nsudo apt update\nsudo apt install gcc-arm-embedded\n```\nFor Kali Linux:\n``` sh\napt install gcc-arm-none-eabi\n```\n\n\n#### OpenSSL\n\nMacOS comes with openssl/libressl installed out of the box.\n\nInstalling on Debian/Ubuntu:\n\n``` sh\nsudo apt install openssl\n```\n\n#### asn1crypto\n\nThere is a tiny python script used to convert certificates generated by OpenSSL\nfrom DER format into C-array. It depends on asn1crypto package.\n\nTo install with pip:\n\n``` sh\npip install --user --upgrade asn1crypto\n```\n\n#### OpenOCD\n\nInstalling on macOS with homebrew:\n\n``` sh\nbrew install open-ocd\n```\n\nInstalling on Debian/Ubuntu:\n\n``` sh\nsudo apt install openocd\n```\n\n\n### Building\n\n``` sh\ngit clone https://github.com/gl-sergei/u2f-token.git\ncd u2f-token\ngit submodule update --init\ncd src\n```\n\n``` sh\nmake TARGET=\u003ctarget\u003e\n```\n\nwill produce firmware file `build/u2f.bin`.\n\nSupported targets are:\n\n- [TOMU](http://tomu.im/)\n- [MAPLE_MINI](https://wiki.stm32duino.com/index.php?title=Maple_Mini) \n- [BLUE_PILL](https://wiki.stm32duino.com/index.php?title=Blue_Pill)\n- [BLACK_PILL](https://wiki.stm32duino.com/index.php?title=Black_Pill)\n- [ST_DONGLE](https://wiki.stm32duino.com/index.php?title=ST-LINK_clone)\n- [ST_DONGLE_NO_PUSH](https://wiki.stm32duino.com/index.php?title=ST-LINK_clone)\n\nUse BLUE_PILL or BLACK_PILL for generic STM32F103 board without push button.\n\nIf build was unsuccessful for whatever reason and you want to start from scratch\nyou may want to run\n\n``` sh\nmake clean\n```\n\nto remove all object files, or\n\n``` sh\nmake certclean\n```\n\nto remove generated certificates, or\n\n``` sh\nmake distclean\n```\n\nto remove `board.h` symlink, or even all of the above.\n\n\n### Readout protection\n\nMake sure to enable readout protection if you are going to use your device as\n2FA for your accounts. Build firmware with `ENFORCE_DEBUG_LOCK=1`:\n\n``` sh\nmake clean\nmake TARGET=\u003ctarget\u003e ENFORCE_DEBUG_LOCK=1\n```\n\n### Injecting private key\n\nFirmware generates EC private key on its first boot and erases it when it\nenters the bootloader. You may want to backup your private key and make it\nsurvive firmware upgrade. To achieve this, generate the key on your host machine\nand inject it into the firmware binary.\n\nGenerate your private key:\n\n``` sh\nopenssl ecparam -name prime256v1 -genkey -noout -outform der -out key.der\n```\n\nYou may want to encrypt your `key.der` and back it up.\n\nCheck device's authentication counter if you are going to perform the firmware\nupgrade. You can see it in Yubikey demo site output. For the new device, you can\nskip `ctr` parameter all together or set it to 1. Let's say the current counter\nvalue is 1000.\n\nUse this command to patch firmware binary:\n\n``` sh\n./inject_key.py --key key.der --ctr 1001\n```\n\n### Flashing\n\n#### To STMF103 board using ST-LINK/V2 and OpenOCD\n\nStart OpenOCD:\n\n``` sh\nopenocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg\n```\n\nOn other terminal run:\n\n``` sh\ntelnet localhost 4444\n\u003e reset halt\n\u003e stm32f1x unlock 0\n\u003e reset halt\n\u003e program build/u2f.elf verify reset\n\u003e shutdown\n```\n\n#### To EFM32HG (Tomu) board using DFU\n\nProviding you have Toboot installed:\n\n``` sh\ndfu-util -v -d 1209:70b1 -D build/u2f.bin\n```\n\nAfter flashing device you still need to initialize device as described in [Initialize device](#initialize-device)\n\n## Security considerations\n\n\n### Random number generator (RNG)\n\nU2F-TOKEN is using [Neug][neug] to generate high quality random numbers. The\nsource of entropy is built-in Analog to Digital Converter (both STM32F103 and\nEFM32HG have ones). 32-bit ADC output is passed through CRC32 35 times to get\n1120 bit input for SHA256-based whitening element.\n\n[neug]: https://www.gniibe.org/memo/development/gnuk/rng/neug.html \"Neug\"\n\nI ran [this suite][rngtest] on 1.7M of raw RNG output from Tomu board.\n\n```text\nSUMMARY\n-------\nmonobit_test                             0.119269669219     PASS\nfrequency_within_block_test              0.11518538339      PASS\nruns_test                                0.0626194973829    PASS\nlongest_run_ones_in_a_block_test         0.585067135452     PASS\nbinary_matrix_rank_test                  0.862015222632     PASS\ndft_test                                 0.965404804209     PASS\nnon_overlapping_template_matching_test   1.00000631693      PASS\noverlapping_template_matching_test       0.35076924588      PASS\nmaurers_universal_test                   0.999954925686     PASS\nlinear_complexity_test                   0.906328320146     PASS\nserial_test                              0.159775233458     PASS\napproximate_entropy_test                 0.15960828003      PASS\ncumulative_sums_test                     0.0774471722878    PASS\nrandom_excursion_test                    0.251774950817     PASS\nrandom_excursion_variant_test            0.0871834280054    PASS\n```\n\n[rngtest]: https://github.com/dj-on-github/sp800_22_tests \"SP800-22 Rev 1a PRNG test suite\"\n\n\n### Device Key\n\nDevice key is a private key for ECDSA p256r1. Any 256 bits are valid key. It is\ngenerated using RNG on first run and stored in device's flash memory. It should\nnot leave the device. You must protect your device's flash from readout to\nprotect device key (see below).\n\n\n### Key handles\n\nU2F protocol specifies two actions - register and authenticate.\n\nRegister takes appID and challenge from the caller and returns key handle,\npublic key corresponding to that key handle and attestation certificate. No one\nusually verify the validity of attestation certificate.\n\nAuthenticate takes the key handle, appID and another challenge, then it signs\nboth with the private key corresponding to the key handle. Caller then able to\ncheck if signature has been made by the same device using a public key from\nregister step. Device in turn has to make sure to refuse signing requests for\nunknown key handles and don't mess private keys corresponding to different key\nhandles.\n\nIf embedded devices would have unlimited storage, the best would be to store all\npairs of key handle and private key on the device. But it is not the case, so\nthe private key actually computed based on key handle and device key.\n\nHere is how it is done by U2F-TOKEN firmware:\n\n\n#### Register request (`app_id` is given):\n\n1. Generate random `nonce` (32 bytes)\n2. Compute `HMAC_SHA265(app_id + nonce)` using device key. Result becomes a\n   private key (32 bytes)\n3. Compute `HMAC_SHA256(private_k + app_id) + nonce`. Result becomes a key\n   handle (64 bytes)\n4. Compute public key for the private key (it's a nice feature of ECC that\n   public key can be easily computed for given private key, but it is not that\n   easy to do vice versa) and hand it out to the caller along with the key\n   handle\n\n\n#### Authenticate request (`app_id` and key handle are given):\n\n1. Extract `nonce` (last 32 bytes of key handle)\n2. Compute `HMAC_SHA256(app_id + nonce)` using device key. This is a private key\n3. Compute `HMAC_SHA256(private_k)` and compare it to the first 32 bytes of key\n   handle, they should match. If they don't, return key not found error.\n\n\nKey handle should look random for casual observer and it does. I ran the same\nsuite on 200K of key handle data generated on Tomu board:\n\n``` text\nSUMMARY\n-------\nmonobit_test                             0.228183190471     PASS\nfrequency_within_block_test              0.226128174333     PASS\nruns_test                                0.0567490131255    PASS\nlongest_run_ones_in_a_block_test         0.748631279961     PASS\nbinary_matrix_rank_test                  0.612219673314     PASS\ndft_test                                 0.553339041027     PASS\nnon_overlapping_template_matching_test   1.00000008312      PASS\noverlapping_template_matching_test       0.932591232105     PASS\nmaurers_universal_test                   0.999315334632     PASS\nlinear_complexity_test                   0.335268833847     PASS\nserial_test                              0.201711285468     PASS\napproximate_entropy_test                 0.20129897411      PASS\ncumulative_sums_test                     0.11790756896      PASS\nrandom_excursion_test                    0.199118786038     PASS\nrandom_excursion_variant_test            0.157445636324     PASS\n```\n\n\n### Tamper resistance\n\nSTM32F103 and EFM32HG devices are not tamper resistant. Highly skilled hacker\nwith the right equipment will be able to read the contents of device's flash and\nget the device key. Then he will be able to clone your device and use it as\nsecond factor to log into your account providing that he knows your passwords as\nwell.\n\nHowever, they are resistant enough for daily use as *second factor*\nauthentication device, because:\n\n1. Firmware does not allow to read flash contents by USB, neither does it disclose\n   device key\n2. Both STM32F103 and EFM32HG have \"flash readout protection\" feature. Once\n   enabled, this feature protecting flash from being read via debug interface.\n   See [this post][p1] for EFM32, and [this question][q1] for STM32F103. See also\n   `efm32 debuglock` and `stm32f1x lock` commands in [OpenOCD manual][openocd-flash].\n\n[p1]: http://community.silabs.com/t5/32-bit-MCU/Read-Write-Protection-of-Flash-and-SRAM/td-p/106405 \"readout protection\"\n[q1]: https://stackoverflow.com/q/32509747 \"readout protection\"\n[openocd-flash]: http://openocd.org/doc/html/Flash-Commands.html \"readout protection\"\n\n## License\n\nChopstx is a threading library for Cortex-M0 and Cortex-M3 processors written by\nNiibe Yutaka.\n\nECC is taken from Gnuk project by Niibe Yutaka.\n\nSome constants and memory layout structures were taken from EFM32 platform\nlibraries by Silicon Laboratories.\n\nCopyright \u0026copy; 2017 Sergei Glushchenko\n\nThis program is free software: you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\nAs additional permission under GNU GPL version 3 section 7, you may\ndistribute non-source form of the Program without the copy of the\nGNU GPL normally required by section 4, provided you inform the\nrecipients of GNU GPL by a written offer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgl-sergei%2Fu2f-token","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgl-sergei%2Fu2f-token","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgl-sergei%2Fu2f-token/lists"}