Designing a biometric password manager
Tags: design, hardware, security
Published: 2019-09-08 13:05:33

Password prompts. Password prompts everywhere. Between logging into my work VPN every day and sudo access on my personal machine, I have to enter multiple passwords multiple times every day. I'm a lousy typist, which means I'll often mistype the passwords in question (especially on those godawful butterfly keyboards) and frustrate myself to no end.

Compare that with my phone, where in most cases I can use my fingerprint to log in and even authorise transactions. Entering passwords or PINs is a back-up option rather than the default. Convenient and secure authentication, based on something you _are_ rather than something you _know_. Wouldn't it be brilliant if I could do this on every device I use?

Yes, yes it would be. And here's how I want to do it.

## The goal

<!--
Describe the function and high-level operation of the device:
* Stores passwords securely, unlocks them only for the device owner
* Does not require special drivers to enter passwords
* Has simple controls
-->

I am taking a more design-led approach in this section, where I outline what task I want to achieve and then flesh out how I want to achieve it. And what I want can be summarised in a sentence:

> I want to be able to enter my passwords on any computer with a touch of my finger, but still be secure.

I decided that this can be broken up into three distinct sub-goals:

1. **Security:** The password should only be unlocked for the right person. Someone who got hold of the device should not be able to retrieve the passwords without significant effort.
2. **Compatibility:** The device should be able to enter passwords on any reasonable computer without special software or drivers.
3. **Simplicity:** Ideally I'd only store a handful of passwords on the device, I want to be able to quickly scroll through the list and confirm my fingerprint to enter the password.

I will discuss the implementation details in more depth later, but for now I would like to draw your attention to the inherent conflict between the security goal and the usability goals (2 and 3). This is the inherent challenge in designing security systems, as increasing a thing's usability often also increases its attack surface. I think the biometrics approach is better than secure entry keypads or miniature card readers such as the Mooltipass for this tradeoff - a secure keypad still requires you to enter a code which can be guessed, and the Mooltipass cards can be lost. A fingerprint-based system provides a reasonable level of security and convenience - a third party can't get to your passwords without cracking open the device and spending some time with a debug probe, and if you lose your finger you probably have bigger immediate problems than keeping your data secure.

## Motivation

<!--
Expanding from the lead-in, why do I want to do this project?
* Interested in embedded programming
* Interested in learning Rust
* Found a problem I'd like to solve
* Intersects UX design, security
-->

The key reason for doing this project is that I'm tired of mistyping my password which we also have to change every three months. My ideal device would be something that sent that particular password down USB with a simple button press, however that's not super secure! As mentioned above I think fingerprint authentication is ultimately more secure _in the average case_ than a typed-in password, because once you're verifying who you are rather than what you know, you can make the "password" as long and secure as you can because no human will ever see it. It also makes sense to go with a keychain approach for storing a handful of passwords.

The other big reason for me starting this is that I want to learn something new. To that end I decided that I want to go back to ARM microcontrollers which I know and hate from university, but on slightly different terms this time - using Rust instead of C/C++, and using a microcontroller much more popular in the maker circles. I settled on the STM32 family, and more concretely on the STM32F446RE part simply because there's a development board for it that costs £13 and it's a powerful little chip.

I chose Rust because I think embedded projects are better suited to learning this systems programming language. For most projects I do on desktop, I usually prefer using something more high-level and portable, such as Python or JavaScript. However I will try out desktop Rust when writing the configuration program.

## The device

<!--
Describe the device functionality in more detail:
* Some form of encryption scheme based on fingerprint data + unique chip id
* Use USB keyboard emulation to send password keystrokes
* Use a scroll wheel control to select credential
* Use an OLED display to show which credential is selected
* Finger tap doubles as a confirmation button
-->

Given the overall goals of this project, I decided on a USB dongle form factor. With USB, I can register the device as a keyboard and send the password keystroke by keystroke to the host. USB keyboards work on any system that has USB - so no extra drivers are necessary. The configuration interface can be a virtual serial port, which also should not require extra drivers. Finally, USB can be used for firmware updates.

I decided to use a scroll wheel control to select the password to enter. The scroll wheel should have nice detents and should be able to rotate freely. I want the interface to scale well to 10s of passwords stored, and so buttons are right out. Notably, the Mooltipass also uses this approach.

An OLED display will be used to show the user which password they have selected, as well as other information such as the status of the device if in configuration or DFU modes. I am also considering adding a Neopixel-type RGB LED for extra indication - perhaps I'll want to let the user associate each password with a colour.

Further on the user interaction - because the fingerprint reader I have in mind for this can also act as a button, I decided that placing one's finger on the reader will confirm the selection and acquire the fingerprint and try to enter the password. A fingerprint confirmation will also be necessary for entering configuration mode and updating firmware. For extra security, I may add a feature which erases the password list if no successful authentication is made a certain number of times, with exponential backoff to prevent the user accidentally erasing their device.

As for the encryption - I will need to come up with a reasonable scheme that would require an attacker to have physical possession of the device and at least some lab equipment to recover the password list. At the moment, I am thinking of combining the main microcontroller's unique ID and the user's fingerprint template as a symmetric encryption key.

![Combining the user's fingerprint and the microcontroller's unique ID to create an encryption key](https://thepracticaldev.s3.amazonaws.com/i/gctqz81j461l9hxxbr63.png)

I would have liked the fingerprint module itself to be able to generate a cryptographic value based on the user's fingerprint and then only release it if the authorised finger was detected - however this functionality is not available on the module I have chosen.

## Implementation

<!--
Describe the implementation details:
* Use Rust - I want to learn it, it's safer than C/C++, systems programming language
* Use STM32 - Good quality ARM microcontroller, good Rust support
* Which fingerprint sensor, say how difficult it is to find small modules that aren't cellphone replacement parts, describe limitations of the Grow R502 in terms of security and that it essentially runs a STM32 clone
* Block diagram/schematics of what I want to do
-->

While I mostly chose Rust because I wanted to learn the language, I also know that it is a much safer language than C/C++ when it comes to memory access. Unless code is explicitly marked as unsafe, Rust will attempt to validate memory access at compile time, catching entire classes of bugs such as use-after-free or buffer overflows.

I chose this particular STM32 part for several reasons. One, the cheap development board - the chip itself is about $6 so I would not be surprised if ST sold the things at cost price. Two, it's a pretty powerful part. And three, the STM32 family is popular with makers and hobbyist electronics people. As a consequence, there is lots of documentation, both from the vendor and the community. There are also Rust libraries for accessing the chip's peripherals in a relatively nice way.

The fingerprint sensor was the hardest thing to find. While there are some Arduino-friendly devices sold by Adafruit (with clones from the usual suspects), they are rather big. Good for safes or doors, not good for portable devices. It did take some research time to find a part which was small and had a reasonably convenient interface. Predictably, it comes from a relatively unknown Chinese supplier, with many clones on the market. It is the [Grow R502](http://en.hzgrow.com/product/113.html), a module roughly the size of a 10p coin, with a UART interface. It can be ordered through AliExpress or Alibaba and comes relatively quickly. However, documentation in English is a bit lacking, and I could not find demo software to go with the module. I have emailed the vendor.

The Grow R502 does not do everything I'd like it to do. For one, I'd love a single piece of functionality to be added to it: when the fingerprint is first enrolled, a token is generated, which is then only returned on successful matches against that fingerprint. This would simplify my design and make the whole system more secure, as I could use that as the encryption key. Bit of trivia: the fingerprint module has a GD32 MCU, an STM32 clone from GigaDevice.

Given the features I want to include on the device and the constraints imposed by the parts I want to use, I decided to lay out the system like this:

![Block diagram of the device](https://thepracticaldev.s3.amazonaws.com/i/6xml3o3seq1mngqcuhii.png)

## The plan

<!--
Describe the plan for the series of posts:
1. Learning examples with the STM32F466RE Nucleo board, including generating a configuration in STMCube and translating it into Rust. Goal is to display something on the OLED display using a breakout board.
2. Playing with the fingerprint sensor: trying to find the vendor software, connect it to a PC for some tests. Possibly writing a Rust program on the STM32 to display something on the screen depending on whether an authorised or unauthorised finger was detected.
3. USB keyboard emulation: making a rubber ducky clone (read commands from SPI flash and send keystrokes down USB)
4. Putting some of it together: Making a breadboard prototype capable of entering a single password stored in plaintext in the program code if the fingerprint matches the authorised finger.
5. Configuring passwords: create a composite USB device (USB keyboard + USB COM port), simple program to manage passwords stored in the flash.
6. UI: Handling input from the rotary encoder, using that to select the password on display. Talk more about the UX of the thing, including user flows for entering passwords with the aid of the device, as well as for programming it with passwords.
7. Encryption: figuring out how to encrypt the SPI flash with some security, ie by not writing the cryptography code myself and avoiding obvious footguns. Discuss the limitations of the R502 module and its lack of a 'secure enclave'.
8. Putting it all together: Making a breadboard prototype capable of being programmed with passwords, and then allowing me to select which password to type in.
9. Design for manufacture: Creating an electronic design and PCB, outline the process of "find your most complex part, replicate reference schematic, for each support component recurse until you're left with passives; then connect up the parts and don't spare the decoupling capacitors"
10. The one in which I put the whole thing together and it probably fails spectacularly
11. Eating my own dog food: Use my device for some time, reflect on how it looks and works, conditional on success in (10).
12. Reflection and evaluation: Where I reflect on the whole process and decide whether it's worth it to stick the thing up on Tindie
-->

I will blog my way through this project, and possibly even make some demonstration videos along the way. I want to share notes from the development process with you, and I want to get some feedback on my plans. For now I am planning 11 blog posts.

1. Rust on the STM32F446RE Nucleo board - where I skip the blinky and go straight for getting something on the OLED display. I will also try to cover initialisation code generation in STM Cube IDE and whether it's a good idea to do first before translating into Rust.
2. R502 exploration - where I try to find some existing software to test the module with and start writing a test STM32 program in Rust.
3. USB keyboard - where I try to create a simple USB Rubber Ducky clone from SPI flash
4. Basic prototype - where I build a device which sends one password stored in plain text when the fingerprint is correct
5. Configuring passwords - where I create a composite USB device which has both a USB keyboard and a virtual serial port, and then use that to configure the password list
6. UI prototype - where I connect the encoder and use it to navigate up and down the list of passwords, and talk a bit more about the overall UX of the thing
7. Encryption - where I start integrating encryption routines into the firmware
8. Full breadboard prototype - where I put everything together on a breadboard and talk through what's going on
9. Electronic engineering - where I create a full schematic and design a PCB for the USB dongle
10. The one where I put together the device on the PCB and hope that it works
11. Reflections - where I spend some time talking about what I learned through this project and where I want to take it; with some usage commentary if the thing even works after I put it together

There's a lot on here and I hope to be able to do it all in reasonable time. For now I'd like to invite you all to follow this series and send in some comments on this project. Until next time!