I've realized that the following implementation isn't truly safe:

$pb = pbkdf2('sha256', $_POST['pass'], "enc_salt", 100, 100);
$d = openssl_decrypt ($data['container'],'aes-192-cbc', $pb, true, $data['iv']);

In fact, I should use a unique salt for $pb instead of "enc_salt", shouldn't I?

Furthermore, can I simply use the same IV to PBKDF-generate the key and to actually encrypt the content?


The salt is here to prevent cost sharing by attackers. If two passwords are hashed with the same salt, then an attacker could hash a potential password using that salt value, and compare the output with the hashed versions of the two passwords; in other words, the attacker can attack the two hashed passwords for the cost of attacking one. This scales up: if there are 1000 hashed passwords, all with the same salt, then the attacker gets 999 of them "for free".

This kind of cost sharing can take several forms, one of them being precomputed tables (and one specific kind of table is called "rainbow table"). In all generality, cost sharing is an instance of parallelism (with the appropriate space-time warp).

You should strive to reuse salt values as rarely as possible; if possible, never. In your case, you would store the salt along with the encrypted file; and each file would have its own salt value (even if two files use the same password, each should have its own salt).

If each file has its own salt value, then you could do any of the following for the IV:

  • Select a random IV and add it to the file header (along with the salt).
  • Use PBKDF2 to generate the key and the IV in one go (e.g. ask for 256 bits of output, 128 for the key and 128 for the IV).
  • Use a fixed IV.

The second and third option are safe only if you are really generating a new salt for each file, in a big enough space that collisions don't occur in practice. Otherwise, you may end up with IV reuse, which is a sin. Specifically, what is Really BadTM is using twice the same IV with the same key. If each file has its own key (because the key comes from processing the password with the salt and each file has its own salt) then a fixed IV is fine.

Anyway, if you need encryption then chances are that you need checked integrity as well, which calls for a MAC. Assembling encryption and a MAC properly is tricky. The proper way is to use an encryption mode that already does the job in a way that makes cryptographers happy. In practice, use 'aes-192-gcm', not 'aes-192-cbc' (or 'aes-128-gcm': 128 bits are already good enough, and it will be slightly faster).

Note that the actual IV length for GCM is 12 bytes.

  • Thanks a lot for the detailed answer, as usual of you.. could you please tell me something about the code posted? I don't provide openssl_encrypt a salt (and I don't disable it) so I think that openssl thinks to it (i.e. generates and store in the header a random salt). Is that wrong? – Surfer on the fall Jul 16 '15 at 7:43
  • openssl_encrypt() and openssl_decrypt() are explicitly documented as not being, actually, documented, so what they do is anyone's guess. This also implies that you would be quite mad to rely on such things for security (some would say that this applies to PHP as a whole). – Thomas Pornin Jul 16 '15 at 12:30

The main purpose of the salt is to protect against rainbow table attacks. There are different scenarios:

  1. If you do not use salts, an attacker could already have a rainbow table ready to start attacking your passwords.
  2. If you use the same salt for every entry, the attacker would need to generate a new rainbow table based on your salt, which he could then use to attack your passwords.
  3. If you use different salts for each password, an attacker would need to generate a separate rainbow table for each password he wants to crack, which is not feasible.

Therefore it is recommended to always use a different salt for each password.

Usually, the salt is not considered as a secret resource and can therefore be saved in unencrypted form in the database. It's only purpose is to make the use of Rainbow Tables not feasible. I'm not an expert in IVs, but as far as I know, the IVs should be secret, and it is probably not a good idea if the IVs are stored in the database in unencrypted form. Therefore, I would not recommend to use the IV as the salt.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.