Monday, April 09, 2012

YubiText and 3-factor password authentication

As I said in the last post, I obtained YubiKey USB tokens and started to play with it. One of the programs I made is YubiText, it allows to input text when a YubiKey is plugged. For instance, one can use it as a way to type a password. This post will describe how it works and how I use it to have something I call 3-factor password authentication.

A quick note on static password mode

YubiKey supports static password mode. You configure a text (maximum 64 chars), then when you plug the YubiKey, it sends this text (using a HID). Maybe this is acceptable for some usages but remember that if someone steals the YubiKey, the password is compromised.

I wanted something different, with the password divided between the machine and the token, so I designed YubiText.

YubiText, briefly

You configure YubiText with a text you want to input (e.g. a password). The token and the machine are configured with some magic (explained after). Then, you run YubiText in the background and whenever you plug the same YubiKey on this specific machine, another magic happens to get back your text and send it to the keyboard.

The text is split between the token and the machine. If only the token is stolen, it does not reveal the text. Likewise, if only the machine is stolen, it does not reveal the text.


The YubiKey is configured in HMAC-SHA1 challenge-response with a random, not saved secret. The challenge is of length block_size-1=63 bytes, the response is of length digest_size=20 bytes.

Then the user chooses the text to input. The text is transformed into a key, which is just a structure containing the length and some padding (to have a length multiple of the digest_size).

The key is then divided into N subkeys, each of size the digest_size. Now for each subkey[i], we do the following:
  • generate a random challenge, call it machine_challenge[i]
  • challenge the token with machine_challenge[i] and call the response token_half-key[i]
  • XOR token_half-key[i] with subkey[i] in order to get machine_half-key[i]
  • save machine_challenge[i] and machine half-key[i] on the machine, forget the rest.

This splits subkey[i] between the token and the machine.
Finally, a predefined challenge is sent and response is stored in order to authenticate the YubiKey.

Now the program runs, it uses python-gudev bindings to the GUDev udev helper library in order to receive events when a YubiKey is plugged. After authentication of the YubiKey, the program is able to reconstruct the key and therefore the text simply with:
subkey[i] = ChallengeResponse(machine_challenge[i]) XOR machine_half-key[i]
             \-------- token_half-key[i] --------/

The text is finally sent to the display using xvkbd - Virtual Keyboard for X window system.

Source is on my github: StalkR/misc/yubikey/

Multiple texts with one token

You can have multiple texts (not necessarily the same) with one token, but it has to be on different machines. First configure a token with --program yes to have challenge-response and a random secret, then for subsequent configurations on different machines use --program no not to reconfigure the token.

If you want multiple texts on the same machine, you need multiple tokens.

3-factor password authentication

Consider the following: the workstation is in a protected safe, with only screen and USB cables allowed out. Typing the password on the keyboard is insecure: an attacker can put a USB keylogger, a camera in the room to record the keystrokes, or simply replace the machine with another one and log everything.
Using YubiText, you can securely type your password (the virtual keyboard does not go over USB).

But if only this, all an attacker has to do is to steal the token. Even though the token itself will not reveal the text, the attacker can use it on the machine to reveals the text (for instance, go on "leave a note" and plug the token).

So, I choose to add another layer of protection and divide my password in two parts: the first part is like a regular password (only in my head and typed on the keyboard, with associated risks), the second part is using YubiText. It gives a somewhat 3-factor authentication:
  1. The first part, something I know.
  2. The second part, the token, something I have.
  3. The third part, the machine I want to authenticate on; while this is not listed as an authentication factor, I like it because it provides machine authentication (think SSL server certificate or SSH server fingerprint), if the machine is replaced it will not have the secret and so no text.


Current limitations of the program and this design:
  • it does not work at boot (when asking for disk encryption password) or at login (gdm/kdm), because the virtual keyboard requires X - maybe this can be fixed?
  • an attacker can man-in-the-middle USB to record all the challenge and responses, which is enough to fake the YubiKey later
  • it is still broken because passwords are broken (I want PKI everywhere!)

Any comments on the design or the code are welcome.


  1. Thanks for your writings on this new security token StalkR.

    Isn't it possible to have the yubikey contain an SSH/GPG fingerprint, and the software that runs on plugging that verifies fingerprint- and verifies that the user can enter the code for this private key (on his computer) .. To enable user-space functionality ?

    And for the boot password- I think it would be cool to make a "pandora's" box token. You would be able to program each key yourself- (some chars multiply characters, some does other operations) .. So you can remember the pattern- but not the actual code yourself, which is VERY long, because of the multiplying keys ..

    I'm very excited to hear more about how you go about securing your yubikey ..

    How does the one-time-passwords work ?

    1. You implement the one-time-password with API.

    2. Your yubikey ID is found @ yubi servers and OTP can be verified with this specific device-ID against all OTPs where one needs to match?

  2. SSH/GPG: yes it would be possible. But in this case I would go for SmartCard to store key and use pkcs11 so that the key never goes out.

    Boot password: yes it would work, it's a good idea but you need to buy as many tokens.

    OTP: in this program I am not using the token in OTP mode, so it's not 1) nor 2). I use it directly for hmac in challenge-response mode.

    If you want, you can also catch me on IRC to talk more about it.