Turning A Teensy Into A Better U2F Key

A few days ago, we saw a project that used a Teensy to build a Universal 2nd Factor (U2F) key. While this project was just an experiment in how to implement U2F on any ‘ol microcontroller, and the creator admitted it wasn’t very secure, the comments for that post said otherwise: “making your own thing is the ONLY way to be secure,” read the comments.

In a stunning turn of events, writing comments on a blog post doesn’t mean you know what you’re talking about. It turns out, to perform a security analysis of a system, you need to look at the code. Shocking, yes, but [makomk] took a good, hard look at the code and found it was horribly broken.

The critical error of the Teensy U2F key crypto is simply how U2F is performed. During authentication, the device sends the U2F key handle to whatever service is trying to authenticating it. Because the key in the Teensy implementation is only ‘encrypted’ with XOR, it only takes 256 signing requests to recover the private key.

The original experimentation with using the Teensy as a U2F key was an educational endeavor, and it was never meant to be used by anyone. The attack on this small lesson in security is interesting, though, and [makomk] wrote a proof of concept that demonstrates his attack. This could be used to perform attacks from a remote server, but hopefully that won’t happen, because the original code should never be used in the wild.

11 thoughts on “Turning A Teensy Into A Better U2F Key

  1. The takeaway should be this: crypto is very difficult to do correctly, and insecure crypto looks an awful lot like secure crypto until closely analyzed. *Do* write (and read, and use) crypto code to learn – do not depend on that crypto code for security. Depend, if you can, on code that has been vetted by professionals and the community as a whole, that has a track record.

    It’s kind of like the old saying “A man who is his own lawyer has a fool for a client.” – do not underestimate the subtlety with which crypto can fail.

    1. Yup. Doing your own crypto is a terrible idea. It takes mathematical experts months and years to come up with the proper stuff, which is then subjected to all the other experts trying to find holes in it. At the very least, you should follow the standards, and that’s if you’re secure enough in your programming ability not to let any holes slip into it.

      Best bet is just download it from reputable site, put your trust in them. You can trust yourself to be honest, but not to be capable of everything. You can always compile it yourself, give the source enough of a reading to work out what you can. But, again, good crypto is created by people with giant brains. You basically just have to trust the mathematical establishment. Same way governments trust their crypto guys.

    1. Some people did think that XOR was reasonably secure in this application – and in a way they’re right, I guess. The bulk of my attack would still work if you replaced XOR with a secure stream cipher like ChaCha20 because it has exactly the same malleability property as XOR. The only place where I actually take advantage of the fact he used XOR is the very last step which uses knowledge of one site-specific private key to find the secret used to encrypt all the others. There are probably other attacks which make more use of the fact that the cipher being used is just XOR, of course, but this one doesn’t actually show that it’s that much worse than many proper ciphers here.

  2. It should also be noted that this behavior is NOT part of the spec. It is an individual’s decision based on the goals of the project.

    If you don’t want to read the specification yourself, yubico has very excellent documentation on the protocol, including how they generate key handles from a device secret security.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.