Yubico Forum
https://forum.yubico.com/

OTP validation cookbook
https://forum.yubico.com/viewtopic.php?f=4&t=103
Page 1 of 2

Author:  Jakob [ Sun Jun 15, 2008 9:37 pm ]
Post subject:  OTP validation cookbook

Questions regarding how a minimal OTP validation routine should be implemented comes in every now and then. It therefore seems like a good idea to keep a basic "cookbook" here involving the necessary steps involved.

"There are may ways to skin a cat" and the same thing apply here. It is somewhat up to each individual implementation to decide which steps are to be included and how the exact implementation is done.

I'll try to keep it reasonably brief for clarity reasons.


Step 1: Basic decoding and sanity validation

1. Convert the received modhex string into binary

2. Split the data in two parts – the last 16 bytes is the OTP part and the first, i.e. len – 16 bytes is the fixed id

3. Use the fixed id to look up the AES key for the id in question.

4. Decrypt the 16 bytes (128 bits) using AES-128 decryption

5. Calculate a ISO13239 checksum over the 16 bytes and verify that the residual is 0xf0b8. If not, abort

6. Check if the 6-byte private ID matches the value in the database. If the private id is not used, ensure that it is set to all zeroes and at verification, verify that all bytes are zero. If it does not match, abort

7. If any of the two last stages fail, it is most likely due to an invalid AES key, i.e. the decryption creates garbage.


Step 2: Check for "static OTP" (if used)

1. If (useCtr & 0x7fff) == 0x7fff and sessionCtr == 0xff and rnd = 0xffff the OTP is a "static OTP". If this matches, accept without further checks


Step 3: Basic (simple) counter validation

1. Set ctr32 = ((useCtr & 0x7fff) << 8) + sessionCtr

2. Verify that ctr32 > lastCtr32. If not, it is a fair guess that the OTP is subject to a replay

3. If successful, store ctr32 in the database to be lastCtr32


Step 4: Optional/alteranative: Detect lost OTPs

1. Verify that lastUseCtr > (useCtr & 0x7fff) || (lastUseCtr == (useCtr & 0x7fff) && lastSessionCtr > sessionCtr). If not, it is a fair guess that the OTP is subject to a replay

2. If lastUseCtr == (useCtr & 0x7fff), check that sessionCtr == (lastSessionCtr + 1). If not (at least) one OTP has been lost

3. If lastUseCtr != (useCtr & 0x7fff), check that (useCtr & 0x7fff) == (lastUseCtr + 1) and that sessionCtr == 0. If not (at least) one OTP has been lost

4. If not failing at step 1, store (useCtr & 0x7fff) as lastUseCtr and sessionCtr as lastSessionCtr

5. Depending on policy, accounts may be locked if more than one OTP is lost. Alternatively, the user may be informed by this and decide himself.


Step 5: In-session timer validation

Each Yubikey has a slightly varying "fingerprint" in terms of timestamp variation. The nominal frequency is 8Hz, but can vary +/- 30% between devices and over temperature.

1. For the sake of simplicitly, calculate tstp32 = tstpl + (tstph << 16)

2. When a new session is detected, i.e. lastUseCtr != (useCtr & 0x7fff), set tstpBase = tstp32 and store current time as timeBase

3. After the first OTP verification within a session, check (tstp32 - tstpBase) vs. (currentTime - timeBase). This value shall be fairly constant for each individual device.

4. Remember that the tstpl/tstph is 24 bits wide and therefore wraps after approx 24 days. An appropriate "fixup" routine will be needed.

5. A sophisticated application can store the calculated (expected) frequency for each individual device. At reasonable room temperature bounds (10-40 degrees C), it will stay within +/- 10%.



All feedback is appreciated,

Regards,

JakobE
Hardware- and firmware guy @ Yubico

Author:  jwoltman [ Mon Jun 16, 2008 6:57 am ]
Post subject:  Re: OTP validation cookbook

JakobE wrote:
Step 5: In-session timer validation

Each Yubikey has a slightly varying "fingerprint" in terms of timestamp variation. The nominal frequency is 8Hz, but can vary +/- 30% between devices and over temperature.

1. For the sake of simplicitly, calculate tstp32 = tstpl + (tstph << 16)

2. When a new session is detected, i.e. lastUseCtr != (useCtr & 0x7fff), set tstpBase = tstp32 and store current time as timeBase

3. After the first OTP verification within a session, check (tstp32 - tstpBase) vs. (currentTime - timeBase). This value shall be fairly constant for each individual device.

4. Remember that the tstpl/tstph is 24 bits wide and therefore wraps after approx 24 days. An appropriate "fixup" routine will be needed.

5. A sophisticated application can store the calculated (expected) frequency for each individual device. At reasonable room temperature bounds (10-40 degrees C), it will stay within +/- 10%.


First, thanks a lot for posting this Jakob, it was very helpful. I have question about the timing code: I'm allowing a deviation of 20% in my code before the server denies a key. Is this reasonable? When I'm testing the code on my own computer, the yubikey timer gets about that far away from the computer's timer. Do you have any recommendations for what is acceptable?

Author:  patgadget [ Mon Jun 16, 2008 3:08 pm ]
Post subject:  Re: OTP validation cookbook

Hy,
I think it would be a nice idea to make a manual that really describe all the step that are require to check a yubikey.
because if we add explanation on each step on this forum it will start to be confusing as post come trying to explain this step or this one in more description (the post could be a start thought)

You could wait a bit to have question from a lot a person then have a better idea for the FAQ ;-)

or make a wiki, but i would make it read only for now (then why call it a wiki :-) ) as only maker wright now are mostly answering question and poster (user) asking them. But a least you could easily modify your cookbook as step needs clarification

My two cents

Author:  patgadget [ Mon Jun 16, 2008 3:19 pm ]
Post subject:  Re: OTP validation cookbook

Step 1.1 Modhex
http://forum.yubico.com/viewtopic.php?f=6&t=96

Author:  aha42 [ Tue Jun 17, 2008 12:44 pm ]
Post subject:  Re: OTP validation cookbook

Is it a (good?) idea to make a reference implementation of the validation cookbook i the various language currently being hacked in?

Any particular server would of course depend on some specific database schema and API for retrieval of key information, but cookbook implementation could be written independent of such with a interface like:

ValidationResult YubiKeyValidation.validate(Token t, KeyData kd)

So this would be invoked after OTP is decrypted and parsed. KeyData contains information of last OTP received from YubiKey in question.

Speaking as a Java programmer, the Java reference cookbook could perhaps fit in the yubico-j library?

Author:  jwoltman [ Tue Jun 17, 2008 10:56 pm ]
Post subject:  Re: OTP validation cookbook

aha42 wrote:
Is it a (good?) idea to make a reference implementation of the validation cookbook i the various language currently being hacked in?

ValidationResult YubiKeyValidation.validate(Token t, KeyData kd)

So this would be invoked after OTP is decrypted and parsed. KeyData contains information of last OTP received from YubiKey in question.


I think this is a great idea. That's what I'm trying to accomplish with the PHP version. If you or anyone else has any input, please let me know.

My method (YubiAuthenticator::authenticate) takes the exact same parameters as your sample ValidationResult. :)

Author:  merlin [ Wed Sep 17, 2008 5:03 am ]
Post subject:  Re: OTP validation cookbook

JakobE wrote:
4. Decrypt the 16 bytes (128 bits) using AES-128 decryption


Hi

I've been searching for the specific layout of the decrypted 128 bits. Some of the fields are referenced in various posts, but I've not seen it "all in one place", offsets etc

I'm sure it must be somewhere but I'm not finding it - can someone give the link

TIA

Author:  paul [ Wed Sep 17, 2008 3:26 pm ]
Post subject:  Re: OTP validation cookbook

merlin wrote:
JakobE wrote:
4. Decrypt the 16 bytes (128 bits) using AES-128 decryption


Hi

I've been searching for the specific layout of the decrypted 128 bits. Some of the fields are referenced in various posts, but I've not seen it "all in one place", offsets etc

I'm sure it must be somewhere but I'm not finding it - can someone give the link

TIA


Page 2 in this doc explains it well: http://yubico.com/files/YubiKey_Security_Review.pdf

If you like to find the code that decrypts the OTP, you can find them here:
http://yubico.com/developers/library/

and http://yubico.com/developers/srv/

Author:  chaeron [ Sat Jan 10, 2009 2:39 am ]
Post subject:  Re: OTP validation cookbook

JakobE wrote:
Step 3: Basic (simple) counter validation

1. Set ctr32 = ((useCtr & 0x7fff) << 8) + sessionCtr

2. Verify that ctr32 > lastCtr32. If not, it is a fair guess that the OTP is subject to a replay

3. If successful, store ctr32 in the database to be lastCtr32


OK...what happens when the 1 byte sessionCtr rolls over from 255 to 0, as in if a user kept their key plugged in for 256 invocations?

The PDF says that that the sessionCtr rolls to zero, but no mention if the 2 byte useCtr is incremented....I'm assuming that the useCtr does not increment during the rollover.

In which case the validation will fail according to the algorithm set out in Step 3.

So....do we just live with this and tell the user to remove and re-insert their key and try again?

Or is there a better way?

Thx!

Author:  Jakob [ Sat Jan 10, 2009 6:00 pm ]
Post subject:  Re: OTP validation cookbook

The usage counter is incremented when the session counter wraps from 255 to 0. Just like if the key was unplugged and inserted again.

With the best regards,

JakobE
Hardware- and firmware guy @ Yubico

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/