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

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.

Related

Why we generally hash the 'key' before applying it on any encryption algorithm?

I am making a Password Manager application for android to store and retrieve passwords whenever needed. I want to first encrypt my password and then store it in my database. I saw a tutorial where he first hash the 'key' and then apply it on the AES algorithm to encrypt the password. I am unable to understand why he does so.
I would guess that the "key" is a passphrase of some kind, which is known only to the password manager, and which encrypts all passwords -- the passwords are encrypted so they can later be decrypted and returned.
If that is the case, do not hash the key. It's better to "derive" an encryption key from it. For example, the "key" may be "snowfallsinthesummertime". HKDF is an example of a key derivation algorithm which can take this "key" and produce a strong encryption key which is then used with AES encryption to encrypt the password. That's the only way I can explain the "hashing the key" of your question.
Furthermore, along with encrypting the password, it's a good idea to prevent tampering of the encrypted data. A good way to do that is to chose the GCM mode of AES encryption which includes an "authentication tag" which would detect tampering.

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.

Secure HMAC shared secret by encrypting authorization hash with RSA

I am considering building an API system that uses HMAC. The server and client will have a shared secret, the client will sign the requests, the server will validate, and proceed if all is well. The trouble with this sort of system is that the secret has to be stored in a way where it can be retrieved, such as a database. If someone were to steal the secret, they have the key needed to do basically anything that user is authorized to do.
I was thinking that there must be a more secure alternative. Are there any flaws with using RSA?
Client has the "public" key instead of a shared secret. (The public key must still be kept secret for my use case.)
Client will hash the message with SHA-1 or whatever as normal.
Instead of adding the hash to the message directly, the hash will be encrypted via it's public key, and then sent with the message.
Server has the "private" key (to decrypt messages) but has no knowledge of the "public" key. (This is the part that makes this more secure than the normal approach. If the database is stolen, no keys are stolen that can impersonate a user.)
Server will decrypt the hash and validate the message as normal.
Is there anything wrong with this approach? Are there known implementations of this or something similar?
It depends on the asymmetric cryptosystem you chose:
(EC)Diffie-Hellman: It does not work. Publickey is directly derived from the privatekey via the generator, e.g. [d]G = Q
RSA: Usually people chose fixed publickeys like 0x010001. This is done for efficiency reasons. If you take a large enough, fully random e and derive d from it there is no possibility to calculate p and q given d and N OR e and N. Actually they are pretty equally then and the label private and public don't make much sense anymore. All that relies on a smmyetrical property of RSA. Be sure not to walk into textbook RSA issues. And be sure to ask enough clever people about it, this is just my thoughts on it.
If you base your crypto system on a proof of possession of a secret you need to, well - keep it secret :)
But yes, if you dont need the speed of a symmetric authentication then you can use a assymetric signature. Typically it is done with a signed hash, but you can also use a signed hmac.
The terminology is normally, that you sign with a secret key and validate with the public key (even when the signing operation looks like an encryption).

REST authentication S3 like hmac sha1 signature vs symetric data encryption

I was arguing about an S3 like aproach using authorization hash with a secret key as the seed and some data on the request as the message signed with hmac sha1 (Amazon S3 way) vs an other developer supporting symetric encryption of the data with a secret key known by the emiter and the server.
What are the advantage of using signed data with hmac sha1 vs symetric key other than the fact that with the former, we do not need to encrypt the username or password.
What would be the hardest to break ? symetric encryption or sha1 hashing at la S3 ?
If all big players are using oauth and similar without symetric key it is sure that there are obvious advantages, what are those ?
An hmac and a symmetric cipher are not mutually exclusive ideas. In fact AES-CMAC which is both an MAC (not hashed) and a symmetric cipher, AES-CMAC is the cryptographic primitive that makes WPA secure. (Although a WPA can still be broken using a rainbow table).
You should not need an exotic authentication system for this. Logging in with a username and password and maintaining session state with a cookie is commonly used because it is easy to implement and it is secure. By storing state, like a cookie its no longer technically RESTful, but there is nothing stopping you from doing it.
However, in terms of authentication I believe that asymmetric cryptography like RSA is the most secure. (Amazon uses asymmetric cryptography for ssh connections by default.) This allows you to only store the public keys, so that if your server where to be compromised no authentication credentials could be used. It also defends against MITM attacks. In many cases this can be implanted quite easily with REST because HTTPS already supports client certificates. You can sign the clients certificates for free and then verify them your self.
If implemented properly, the strength of an hmac vs symmetric cipher it mostly comes down to the strength of the secret. If you are using a secret like a password, then both systems are equally very weak. These secretes must be large, Cryptographically Secure Psudorandom Numbers. Another thing to keep in mind is that symmetric ciphers are very difficult to implement properly. Most programmers do not understand this and end up reusing PRNG when using stream cipher or when using a block cipher they use an incorrect mode and leave the IV null. By contrast HMACS are very easy to implement and less can go wrong. If everything is transmitted over HTTPS, and your are using an hmac then its easy to implement a secure authentication system. If you really want to implement a symmetric cipher you must get a copy of Piratical Cryptography, there are a few chapters devoted to symmetric ciphers alone because so much can go horribly wrong. You also have to take key distribution into consideration, ssl uses a DH-Key Exchange for its symmetric keys.
Make sure to read the OWASP top 10, especially Broken Authentication and Session Management. This requires the use of https for the entire session, most web application programmers don't realize this.
The big differences would be that HMAC would provide integrity but no privacy, while encryption would provide privacy without integrity. Many use cases would require both, but I can't think of any where integrity is unnecessary. HMAC seems like a minimum requirement, with encryption being a likely companion.

For sending passwords over the wire, which is more secure: Diffie-Hellman/AES or RSA? (It bothers me that AES doesn't obscure password length)

I was given advice that I am suspicious about so I'm looking for support here to go back and challenge the advice.
I was advised to use Diffie-Hellman to get both sides to agree on a secret key, use the secret key to generate an AES key, and then use AES to encrypt/decrypt passwords that are being transmitted. Pretty much like the sample code here
When using this scheme, the length of the encrypted password is the same as the length of the unencrypted password. Should I be worried about this?
Before, I was using RSA, encrypting the passwords with the receiver's public key. This was resulting in an encrypted length of 256 no matter what the password length. Isn't that better?
You can just pad to whatever length with any data. It doesn't have to be random. As long as it's all encrypted. I think though that is the least of your worries.
Note if you use Diffie-Hellman you still need to authenticate the parameters sent, which you probably need to do with RSA.
The alternatives are:
Use RSA to exchange an encrypted secret key that you then use to encrypt your data.
Use Diffie-Hellman to exchange a secret key and then use RSA to sign values sent to authenticate the transaction.
If you do all this, then you have to also worry about whether exchanges have been replayed to make you reuse keys etc.
To be honest if you need to ask this question then you probably are not qualified to write a crypto protocol. They are extremely hard to get right and not for the faint hearted.
Suggest you use SSL/TLS for your exchange if you need to stream a lot of data. PGP/PKCS#7 if you just need to send a single message.
First off: Don't invent your own authentication protocol. Period. If you do, you WILL get it wrong even if you're using strong encryption. There are a number of existing well documented authentication protocols that have been vetted by cryptographers and thus are thought to be secure. Don't be tempted to "simplify" them, they've already been simplified.
Second: IMHO you should never send passwords on the wire for authentication (I'm not aware of any authentication protocol which does, including the hideously insecure NTLMv1 protocol)[1].
If you're dead set on going down the "roll my own authentication scheme" path, here's how I'd make the scheme you described above more secure (Caveat: I'm not a cryptographer - I believe that there are serious weaknesses in what I'm describing here):
Instead of sending the password directly, send a one-way-function (also known as a OWF, often implemented as a cryptographic hash like SHA256 or stronger) of the password.
In other words, have the server send the client a salt value, add the salt to the password, compute the OWF of the password+salt value and send the OWF result to the server. On the server, add the salt to the password and also perform the OWF calculation. If the results are the same, the password is valid, if they're not it's invalid.
And finally have whatever you do reviewed by a real cryptographer. They will find problems in your implementation and you're going to have to fix them. They're likely to suggest that you abandon your effort in favor of an existing published protocol.
[1] AFAIK, the only time you should send the password on the wire is when you're changing the password and even then, you should pad the length to a multiple of the block size (include the length in the cybertext so that when you decrypt it you can distinguish between the password and the padding).
If you can help it, don't send passwords over the wire at all. Instead, use a scheme like SRP, which authenticates both parties with one password.

Resources