U2F is another authentication technology which requires a trusted verifier, like a remote server: fundamentally the output of an authentication is ‘Yes’ or ‘No’ rather than some key material or new capability.
OTPs fall into this category too. Biometrics usually also do; biometric key generation is a thing, but the entropy of the resulting key is tricky to quantify without large-scale population studies.
This makes most authentication devices: unusable offline, and that means they don’t work for mobile, and certainly won’t work in early boot when you want to decrypt your disk.
U2F comes from the FIDO alliance, an industry consortium of a bunch of authentication hardware people (Vasco, NXP, RSA, Synaptics, Yubico, Oberthur), software people (Google, Microsoft), and payment card issuers.
U2F has an enrollment phase, where a token generates a per-site ECDSA key (on the NIST P-256 curve) and returns the associated public key, and an opaque ‘key handle’ which names the key. The verifier stores the key handle and public key.
Then, for an authentication later, the verifier presents the key handle back to the token along with a challenge, and the token signs the challenge. The user is authenticated if the the signature is valid.
This is pretty simple.
I have a Yubico Security key which costs £12.99. That’s pretty good, but even cheaper U2F tokens are available.
But I want to use this thing to decrypt my disk, or decrypt my password database!
So: we want some bytes with high entropy that are hard to guess without talking to a specific U2F device. We’ll hash them before use, so it doesn’t matter too much if the bytes are not uniformly distributed or have some bias.
The following abuses the design of U2F. It deliberately misuses cryptography. It is presented for your amusement rather than serious use.
U2F’s separation of keys between sites was done for privacy reasons, so database leaks don’t allow correlation of accounts to the same U2F device.
Storing all the per-site keys on a device is not a workable idea. The device will never be told if a key is abandoned by its verifier, so eventually it will run out of persistent storage.
There are two ways of achieving this:
Note that if a U2F device produces key handles which contain the public key in plaintext, this whole scheme fails catastrophically. This isn’t under our control, but it seems extremely unlikely.
A not well-known property of ECDSA: given a message and a valid signature over it, you can derive the corresponding public keys. There are two such public keys for each signature, and one is the ‘correct’ one (ie. pairs up with the original signing key).
If the signature is invalid, you’ll get junk or the maths won’t work at all.
Let’s sketch a password + U2F key derivation method. We’ll use PBKDF2, any slow hash is suitable as long as it processes arbitrary-length inputs.
PBKDF2(salt, encode(public key) + password)
, use the result as a key.Note: encode()
is a fixed length encoding of an elliptic curve point, like P1363’s EC2OSP-XY
.
PBKDF2(salt, encode(public key) + password)
.This has the following nice properties:
There’s a proof of concept of this in my u2f-key-storage repo. You’ll need Yubico’s python-u2flib-host and its prerequisites.