U2F Zero: Hobbyist Modifications

What’s U2F?

Traditionally authentication (logging in) relies on something you know (passwords) or something you have (your front door keys) or something you are (like fingerprints; this can also be thought of as a shitty version of something you have[1]). Most of the time only one authentication factor is in use: your door doesn’t require something you know, just your key, and many web services only require a password. However, in the age of massive data breaches (along with rampant password reuse) passwords are not especially trustworthy, so one might shore up security by using a 2nd factor alongside passwords, known generally as 2 factor authentication.

U2F (Universal 2 Factor) is an open standard for providing a “what you have” factor using strong cryptographic primitives. Contrast this with using SMS as a 2nd factor, which is:

U2F is usually implemented as a USB token, and implements a call and response protocol: after logging in, the service requests a U2F response. The U2F token starts blinking, and pushing the button on the token fulfills the response (you don’t want it to automatically send back the request, because some users keep their tokens inserted into their computers, and automatically responding would open them up to surreptitious attacks).

How does U2F fare when compared with SMS?

  • Unphishable: browsers know what domains a U2F request is being made from, and the U2F response is signed, so it’s not possible to simply replay the same payload like with OTP (One Time Passwords: this covers both TOTP and SMS)[2].
  • More secure: if someone wants to use your U2F token, they need to physically steal it from you, which is a very different proposition than surreptitiously redirecting a SMS from one device to another.

    Also, the separate token design is vastly simpler than a whole phone, and consequently easier to vet and secure.

    (But keep in mind that WebUSB can be used as a vector to neutralize U2F tokens. This shouldn’t be a problem, since WebUSB is still a nascent feature.)

    (But also keep in mind that sometimes U2F providers do make mistakes: Yubico uncovered an RSA key generation issue in 2017.)

For more details, take a look at the U2F whitepaper.

U2F Zero

However, U2F devices are still relatively expensive: the cheapest Yubikey U2F device is $20 as of time of writing (2018/07). Multiply this cost by 2 or 3: you want more than one key to serve as a backup if you lose one, especially if you disable more insecure fallbacks like SMS.

Plus, while the U2F standard is open, most devices are not, so there’s some trust you have to invest in your token provider[3].

Enter the U2F Zero.

It’s a open hardware implementation of U2F, allowing anyone with basic SMD soldering skills to turn out U2F keys on the cheap (around $2-3/key). For the open-stuff afficianado in me, and the security buff, making my own instead of buying makes a lot of sense.

(That said, the $2-3/key figure doesn’t take into account labor, or the cost of getting all the equipment to do soldering and programming. Costs becomes amortized if you do other hardware projects, but otherwise would add up quickly and make this economically infeasible unless you’re planning on churning out large scale. In short, it’s not really worth it unless you have another goal, like having fun with an easy hardware project, satisfying your rampant paranoia[4], or supporting open hardware[5].)

Making the U2F Zero, Round 1

The build process is fairly straightforward:

My initial build fell apart between “solder up the parts” and “program the token”. I noticed that I had made the rookie mistake of assuming all the passive components[6] were the same size (0603[7]), when one of the capacitors was in fact smaller (0402). I tried to shove the 0603 part I did have onto the 0402 pads, to possibly ill effect. And for those that haven’t dealt with SMD parts before, 0402 is tiny. My hands shake a bit, to the point that placing even the 0603 parts was a chore[8]. 5 out of 8 of the parts were similarly tiny sized, making it painful to place the parts before soldering, and then get high enough magnification to check that everything had soldered correctly.

And to top it all off, the part didn’t even respond to programming.

At that point there was a choice: do I simply go back and buy the correct 0402 part, and try to solder up another board, and hope that was the problem? Or, do I scream “fuck it, we’re doing it live!” and redesign the board to use sane part sizes[9]? The board had space to spare, so I wouldn’t have to get too creative, and this wouldn’t be like my previous noisEE project, where I had no idea what was going wrong and there was no exit strategy: in this case I knew there was a working product at the end of the rainbow, that a bunch of people have made this successfully.

Well, here we are, so I think you can guess which path was taken.

Redesigning the U2F Zero

Most of my previous hardware projects had been greenfield designs, completely new designs starting from a blank PCB. This was the first time I had stepped into an existing design and made changes, which was a welcome change of pace. Lots of important decisions had already been made, and I just had to work around them, instead of trying to try and balance between all of them.

For example, I didn’t need to decide which parts were necessary, but I did need to decide which parts could be swapped for other parts. So I hit up Octopart, and started choosing replacement parts:

  • EFM8UB (microcontroller), ATTEC508A (authentication chip), button: all these parts are relatively huge and easy to handle, so I kept them all the same.
  • Passives (resistors and capacitors): swapped the tiny 0603 and 0402 parts for a uniform 0805 size. It’s mildly larger, and I had a big book of passives with 0805 parts[10].
  • DF5A5 (TVS Diode, for ESD protection): swap the SOT-553-5 for a SOT-353-5[11]. The part is still tiny, but I wanted to keep this close to the USB plug, since it’s meant to handle transisent voltages, and there just isn’t much space there.
  • LED: I went though a few design iterations and part choices. As it turns out, there are lots and lots of different LED choices, to the point that restricting your choices to common anode (shared high voltage) doesn’t really help at all. A few thoughts:
    • 5050: the LED itself is nice and big, if a bit tall. I could also get it from Adafruit at a reasonable price ($0.50/part vs $0.60/part[12]), but that’s the only place I could get it[13]. With open hardware, it’s better to have a wide choice for a commodity part like this.
    • SK6812: after delving into the datasheets, found out it was an addressable LED, which is good for turning long strings of LEDs into a flashy cosplay costume, but would add complexity to the microcontroller software.
    • 2020: one may think this part should be more than 3x the size of 0606 LEDs, but one would be mistaken. 0606 is in mms, while 2020 is in mils, with the result that the size is approximately the same.
    • PLCC4 (4SMD): this is kind of a weird package, being meant to be inserted into a hotswappable socket. However, the part is inexpensive, not too dim, supports 3 channels, not obviously prone to availability problems, and definitely easier to handle than a tiny 0606 LED.

U2F Zero uses KiCAD (now I’m glad that I forced myself to learn it with noisEE), which meant the schematic could stay the same, and just the footprints needed to be swapped out, which is a fair bit easier than the equivalent operation with Eagle.

After that was placement and routing. Some considerations:

  • Placement was tricky even with only 8 parts, since now parts took up a larger portion of the board, and while it wasn’t too hard to route traces, I wanted to avoid deviating from the form factor, which meant tearing up traces a number of times. In particular, if I needed to concede extra space, I wanted to constrain it to making the token longer, not wider.
  • I created two branches, experimenting with LED placement, originally moving the LED to the side to avoid lengthening the board, and then trying out another routing solution that kept the LED in the middle. I went with the middle LED solution after some fiddling.
  • I tried to route around so the GND pours on the bottom wouldn’t be split down the middle, or otherwise leave non-GND voids on the backside of the PCB (mumbles something about electrical noise).
  • While I tried to take into account some previous PCB fixes contributed earlier, I can only hope I got it good enough[14].

After placement, I ended up updating the panelized design by hand. Unfortunately, there aren’t many options for doing automatic panelization in KiCAD, so I ended up moving copies of the PCB design around to precise values and then adjusting the connecting tabs by hand[15].

(I also outset the mousebite holes into the tables, since the original panelized design mousebites left holes bit into the final PCB, making the edge rough without a way to smooth it out.)


This took a lot of wall time, but it was fairly straightforward once I got into the swing of it, for reasons that will become obvious.

Normally I would simply send my KiCAD file off to OSHPark for fabrication. However, Dirty PCBs was really the only game in town this time, since they have a 2mm thickness option, and it appears getting that option with low costs means Dirty PCBs or interfacing directly with a Chinese PCB house.

Dirty PCBs only takes gerbers, but it turns out that this is straightforward to export from KiCAD, following random instructions online. There was a bit of confusion on my part whether I should be selecting the “merge NPTH and Plated” option in KiCAD, but it turned out to work without selecting that option.

The old and new U2F Zero designs side by side.

I got lucky with Dirty PCBs ProtoPack option, getting 13 panelized boards in a nominally 10 board pack, for a total of 39 separate device PCBs. A vice and pliers made quick work of snapping the panels apart, and a hand held angle cutter and a dremel cleaned up the edges[16].

A big pile of U2F tokens.

I tried to use my new hot air toy I picked up while working on noisEE, but using it to do the original soldering run didn’t work, since the parts would get blown around by even the weakest stream of air. The hot plate soldering method worked as usual.

The bare token PCB and parts before placing.

However, I did run into a number of soldering problems. Almost every token had one pin or another that didn’t get soldered correctly, especially with the smaller components, which could tilt one way or the other. A lot of examination under a magnifying glass and rework ensued, which got tedious when spread over 20+ devices.

The Software

Thankfully, I didn’t need to modify the software at all, having used drop in replacements for all the parts.

However, I did need to get the software into the devices, which turned into a mini adventure.

The EFM8 devices use custom software, which means using a custom IDE known as Simplicity Studio. Coming from the widely supported Arduino and Raspberry Pi, it was a shock needing to run custom software in order to do the simple act of compiling. Whatever, it’s what the project uses, and the path of least resistance. It’s just a shame I couldn’t get it to run with Linux, the package being plauged with WINE problems.

Additionally, I needed to actually move the compiled program from my Windows machine onto the device. I didn’t buy an actual EFM8 programmer device, but instead used conorpp’s other git repo, efm8-arduino-programmer.

So the programming process went something like:

  • Create the cryptographic keys for the U2F key.
  • Compile the microcontroller binary using Simplicity Studio, which includes the generated keys.
  • Program the U2F key using the Arduino programmer.
  • (Swear and resolder if some connections didn’t set correctly, and prevented programming from working.)
  • Test it out on the Yubico demo site to make sure everything works as expected.

My hacky setup for programming the U2F tokens.

Much like the possibility of automating panelization, I think there’s ways to make the programming process better: folding the Arduino script into the programmer script (instead of being a separate server)[17], investigating the possibility of templatizing the binary, and having a more flexible script to tie everything together. Again, there’s just a deficit of energy and time, so I didn’t get around to any of this.


At this point the U2F keys are functional, but I wasn’t done. I wanted to go a step further, and provide some protection from the elements and low effort malicious actors.

First, the keys are completely bare, so they’re exposed to the elements. All the parts should be fine with some water splashed on them, but I was a bit worried that water could get under the SOIC pins, not get shed with a simple flick due to surface tension, and then short out the device if a user too eagerly plugged it in after coming in from the rain.

Second, while it’s true that if Mossad wants to Mossad you then you will get Mossad’, we are already trying to force state-sized adversaries to show their hand, or at least beat you with rubber hoses. While putting up a barrier to physical access is of dubious effectiveness[18], it shouldn’t hurt to prevent access to the full buffet of pins on the microcontroller.

conformal coating fills this role nicely: it’s meant to keep dirt out, provide electrical insulation, and be fairly lightweight.

However, most conformal coatings are clear, which isn’t so great for us. A clear coating is effectively optically not there, which means that its absence is harder to detect. An opaque coating would be mildly better, since removing it uncovers the underlying chips, and reapplying it would be inconvenient over short time scales (day long timescales are out of scope).

Considered options:

  • Sugru: I’ve used sugru before, but it has a tendency to rub off and leave a residue on things, which isn’t a good property for something on a keychain. Surely there are better options?
  • Potting: plenty of potting compounds exist, with the caveat that they need to sit and cure in a mold, which I don’t have. We don’t really want to cover up the LED or prevent the button from working, which might happen with just too much potting compound. And, I imagine the end result is much like the Yubikeys, just heavier.
  • Heat shrink: this would work out pretty well (heat gun FTW) except for the fact I couldn’t find heat shrink in a size that would fit the U2F: the closest diameter I could find left millimeters of space, and that much slop is not what you want with something on a keychain.
  • Plastidip: seems primarily focused on the automotive market. I didn’t want to spend the money to find out if it was going to be tough enough.
  • Liquid electrical tape: thinking about normal electrical tape, it seems tough enough to stick around on a keychain, so I went with this covering. And empirically, I can state that it’s held up over the last few months.

A finished U2F Zero token, covered in liquid electrical tape.

And after that, you have a few dozen U2F keys! Maybe you won’t procrastinate at the task of giving them away to your friends and family, like I am.

And as always, the changes are open source, see my pull request into the U2F Zero project.

If you’re read all this, and you want one, but don’t want to go through the trouble of making one, you can:

Thanks for reading!

[1]  To be fair, all of these factors can be thought of as “something you have”, since you “have” the memories of your password, but until we get street available memory reading technologies, it’s useful to treat this factor as qualitatively different.

[2]  If the attacker controls your browser, so that domain checks aren’t being done correctly, then it’s already game over.

[3]  Let’s get real. If you’re Joe Regular, and Yubico turns out to be evil, Yubico is not going to blow a 0-day on you. Any TLA that has suborned Yubico’s manufacturing chain is not going to blow a 0-day on you. Worrying about the usual authentication providers being out to get you isn’t really useful.

[4]  Like I said in a previous footnote, if you’re paranoid it’s unlikely it’s going towards something useful, but humans gonna human.

[5]  Note that while it is theoretically possible for everyone to audit the code, as far as I know no one has done so, including myself. Factor this into your paranoia as you will.

[6]  Resistors and capacitors, as opposed to active parts built with transistors.

[7]  The passive component sizes are XXYY, where XX is the number of 10s of mils long, and YY is the number of mils wide.

[8]  Mind you, 0805 is still a chore to work with, but less of a chore.

[9]  If I had a pick and place machine, or was doing this commercially, I think the smaller parts make a lot of sense, since they’re mildly cheaper.

[10]  It was possible that I could use 1206, but it would have slightly pushed the size limits.

[11]  Paradoxically, the smaller number denotes a larger part.

[12]  This only holds with non-bulk discounts; once bulk discounts kick in, the original LED becomes much more cost competitive.

[13]  Aside from a weird looking deal from Newark, which doesn’t really help.

[14]  On the other hand, the panelized board had never got updated after that PR, so I don’t feel too bad about possibly making a mistake.

[15]  There is almost certainly room for a script here, but at this point of the project I was pretty tired and needed to make progress, so I skipped automating this step.

[16]  It turns out that unlike asbestos, fiberglass (and hence FR4, the stuff PCBs are made from) won’t fucking kill you.

On second thought, is that site trustworthy? I had to go find it in the Wayback Machine, and the site overall is pretty sketchy.

Doing some more post-hoc research (RedditQuora: I know, some really quality data sources), it seems like the basic claims on that page are basically correct, where equating asbestos and fiberglass is not the same.

And, Berkley Lab seems to be hosting a copy of the earlier page in a Word document, for some reason, so maybe it’s legit?

In the end, I don’t feel bad about taking precautions. Respiratory disease is no joke.

[17]  The programmer script also needs some love, with a number of hardcoded variables and a lack of niceties like a properly provisioned requirements.txt: for example, it was missing a requirement for the requests library, and was hard coded to work with the Arduino Mega.

[18]  There are already at least 4 pins that must be exposed by virtue of it being a USB device.