How do I decode a Yubikey OTP token? - yubikey

I'm trying to figure out how to build a feature to authenticate with a Yubikey OTP.
I want to self-host my own authentication service, without relying on the Yubikey API.
I've looked through their example yubikey-ksm project, trying to figure out the format of the Yubikey requests, so I can try to build my own. However, it seems like their example is looking up the token's AES key in a key database. I'm not really sure where this key comes from, since there is no step to install an AES key when setting up a new Yubikey.
My current understanding of the process (please correct if anything is wrong):
Take the first 12 characters of the OTP; this is the token ID, as well as the last 32 characters; this is ciphertext.
Somehow get the AES key associated with this token ID (but where??) as well as an "internal name".
Decrypt the 32 character ciphertext with AES128 in ECB mode using the key from step 2 and 0x00000000000000000000000000000000 as an IV.
Check that the first 12 characters of the plaintext matches the "internal name" from step 2 and that the CRC of the plaintext is correct.
If step 4 is correct then the key is validated. The next 4 characters are the counter, the next 8 characters are a timestamp, and the next 2 characters are a use counter.
Where does this AES key and "internal name" from step 2 come from? And, given there's no secure way for the remote server and the Yubikey to negotiate a new AES key, how is this secure from an attacker obtaining the AES key in the same way a legitimate site owner would need to obtain it to validate the keys?

My understanding of yubicloud's webpage ( https://www.yubico.com/products/yubicloud/ ) is that you basically have 2 models of OTP validation with your yubikeys:
Either you use the built-in AES key in your device, which is known by the Yubikey (yubicloud) servers (so web apps can authenticate you using their API);
Or you generate you own AES key, and provide it both to your authentication server and your Yubikey, and setup you Yubikey so that it uses this custom key.
Regards

Related

AES256 password and iv, the right way

I want to create and manage user sessions with AES256 encrypted tokens.
I am using node's crypto library and followed this stackoverflow question.
I am using this to create session token that will be sent to frontend and stored in the backend for verification purpose and the data is stringified JSON.
Here I see two things one is password and other is iv.
so two questions,
Is the iv is safe to sent to frontend (iv + "." + encData)?
How should the password be generated? How about a SHA256 of (e.g. user's password that I store in db at signup)
This way I will be using a different password for each user. Is this approach correct?
P.S. Both of the answers below helped a lot, If you are here, do read all the comments and attached So question and the linked articles.
Let's keep to the question at hand:
Is the iv is safe to sent to frontend (iv + "." + encData)?
Well, yes. The IV may be public knowledge; as long as it is unique and - in the case of CBC mode encryption - random then this is fine. Of course, the IV and encData should be suitably encoded, for instance using hex (as in the linked answer) or base 64. This is not often done as the IV is always 16 bytes for AES, so it is easy to simply prefix the binary IV to the encData instead.
Beware of hackers changing the input; if the dot or colon is removed then you may have just an array of one element and accessing the ciphertext may result in an error or the decryption of empty data.
How should the password be generated? How about a SHA256 of (e.g. user's password that I store in db at signup)
No, you should use a password hash for that; SHA-256 is a cryptographically secure hash but not a password hash such as PBKDF2, bcrypt, scrypt or Argon2. And if you want to store something in the DB, then please do not let that be the AES secret key generated from the password.
This does not in any way invalidate any of the concerns in the answer of TheGreatContini. This is not security advice, just the cryptography related advice you asked for.
You may want AES encryption, but encryption is not what you need! For the security of your application, message integrity is more important than encryption.
Encryption does not generally provide message integrity (see section 7 of Top 10 Developer Crypto Mistakes) unless you specifically use a mode of operation that provides it (such as GCM mode). Therefore, the solution you are designing in inherently wrong. More info in footnote (!) below.
Understand what you need -- message integrity + encryption, or message integrity only. If it is message integrity only, then use HMAC.
Another thing you need to understand is that functions like AES and HMAC do not use passwords, instead they use cryptographic keys. See section 6 of Top 10 Developer Crypto Mistakes.
It is not clear whether your question on IV matters, given that your approach is wrong, but to answer it anyway, the IV does not need to be secret. See section 2 of Top 10 Developer Crypto Mistakes.
I generally agree with the comments above: use JWT the way it was meant to be used rather than trying to build your own solution. JWT has a claim reserved for expiration, so there is no reason not to.
footnote (!): If you want to see how confusion between message integrity and encryption gets abused, you can try this exercise from Pentester Labs (unfortunately it requires a subscription, but it is cheap). Granted that this is for ECB mode, a similar concept can work for CBC mode.

AES GCM decryption security

When I decrypt using AES GCM, if my Authentication Tag does not match the computed Authentication Tag (indicating something supplied in the decryption process is incorrect), is it completely safe for the user to see the output from the decryption?
Or should I set the output from the decryption to zeroes so that the potential attacker can not get any information back besides the decryption process failing?
I am worried that some hacker/mathematician would be able to begin guessing the key value more accurately if they had access to the output from the decryption.
The key value will be safe what ever you do - bar side channel attacks or abusing the key bytes. A block cipher such as AES is designed not to give any information back about the key. If the GCM authentication fails then you should not make the decrypted data available. Failure is failure - if GCM fails you cannot trust the contents of the bytes.
If you want to thwart attack, make sure that the attacker cannot easily change the plaintext that is encrypted, and make sure that all the bytes of the authentication tag are always verified. With GCM it also pays to make the authentication tag as big as possible.
Returning a minimum amount of information is generally seen as a good defense as well. Zapping the encrypted bytes to zero is probably a good thing, as long as you don't return any of those bytes.

Encrypt data to mobile

I need to send encrypted and dedicated data to a mobile application (ios/android) supposing that the application is not connected to internet.
My current idea is to send the data through a QRCode containing the encrypted data.
I don't want to use symmetric encryption and "share secret" on both sides for obvious security reasons.
I'm a beginner in encryption ;-)
I think that it can be acceptable that the application generates a 16 characters that the user can enter into a web form and then download the QRCode dedicated for this device and encrypted.
Then my feeling is that I'm looking for an asymetric algorithm that can be initiated starting from something like 16 characters.
It's acceptable that the application knows the server public keys, but application won't have possibility to send more that 16char to share their locally generated public key.
Any idea?
Your 16 characters sounds like a one-time password, from which you can derive a symmetric encryption key. Since it's a one-time password (unless the user re-uses this password again and again), there's not much risk in using it. Also you don't store this password (or the derived key) on the server to prevent leakage.
The key can be derived using PBKDF function. Length of user's passphrase is the most important thing - it must be as long as possible (16 characters is quite weak passphrase).

HMAC authentication for REST

I am looking to implment HMAC for my REST API based on
http://www.smartjava.org/content/protect-rest-service-using-hmac-play-20
The one thing I am still confused about is the how to get the SECRET to the client. The clients will be iphone, android and downloaded from the market
What I was thinking of was using something the user has entered as the SECRET like a pin, the server will have this pin via
1) client gets a public key from server
2) encrypts the pin with the public key
3) server stores pin in db
4) from that point forward the PIN in used as the SECRET
Any holes in this?
This would in principle be fine. However, a pin usually is only 4 digits. It would not be difficult for an attacker to get the public key and encrypt all 9999 combinations. He could then compare his encrypted keys with the encrypted data from the client and find the secret. You can avoid this problem by padding the pin with i.e. 50 random characters. The server must decrypt the padded data and simply throw away the last 50 characters.
There is a hole.
At step 3, the PIN is stored in the database. The server has no way of knowing that the request to save the PIN comes from a legitimate user.
For this to work, you must save the PIN either :
At account creation
When the old PIN is provided
That being said, a PIN stays very weak and easy to break. A 4 digit pin will be guessed in about 5000 tries, on average.
I'm not a security expert, but what if the client sent along a random seed with each request? Both the client and server would use this seed in generating a secret key based on a shared algorithm. I'm not sure how attackable the relationship between a given seed and a returned hash would be, however.

Can I use PBKDF2 to generate an AES256 key to encrypt and implicitly authenticate?

I have 2 devices and I want to set up a secure communication channel between them. The only shared secret is a (7- to 20- character ASCII) passphrase. If I use PBKDF2 (from RFC 2898) with a common salt, iterations, and passphrase to generate an AES256-CBC key and IV on both sides, I think I can authenticate the user and provide an encrypted channel all in one step. Is that true, or is there some reason why I've only seen people use PBKDF2 to verify passwords?
My reasoning is that both sides need to know the passphrase to generate the same key and IV. So if device B can decrypt data from device A, they both have demonstrated that they have the same passphrase.
PBKDF2 is a fine way to generate a common key from a shared secret (you should not be generating the IV in such a way though - the IV should be random, and sent alongside the ciphertext).
However, CBC is not an authenticating cipher mode. This is because an attacker can take an encrypted message and make predictable modifications to it, without needing to be able to read the message or know the key. Such attacks have broken real world systems in the past.
You can use an authenticating cipher mode, like Galois Counter Mode (GCM) instead of CBC.
An alternative is Encrypt-Then-MAC. Use PBKDF2 with two different salts to generate two different keys - first the data is encrypted using CBC with the first key, and then a HMAC is calculated over the ciphertext using the second key.
You will also need to use single-use-nonces to prevent replay attacks.
In general, you wouldn't be able to authenticate a message using a cipher, because the message could be anything. However, if the message conforms to some specified format, I suppose it's reasonable to assume the ciphertext must have been produced with the shared key—with longer messages in more complex formats giving better assurance. For example, the padding in a block cipher can serve as a weak authentication.
For better security, compute a MAC using the shared secret and send that with the ciphertext.
While PBKDF2 can be used to produce an IV, it can only do so for a single message. In most cases it's better to select a random IV and send it with the ciphertext.
PBKDF2 does not "verify passwords". It generates keys from passwords.
To verify a password, normally you have a thing that gets encrypted with a key. The key is generated from the original password, via PBKDF2. Then the cryptotext is saved.
When you want to check whether the user-entered text matches the password, generate the key from the password candidate using PBKDF2, then try to decrypt the saved cryptotext. If the decryption works, then you have a match.
Normally, though, you would not use the password-based key as a session key.
So, NO, you normally would not protect the secure channel with the password-based key.
caf's answer is good. I'd just like to add that you're trying to implement crypto, and even for trained experts that's generally a bad idea. Using the highest-level library you can is much safe.

Resources