11

I was looking at this code and came across these comments which says encrypting without a salt is insecure. Why would it be insecure when you are already using a random IV for each value? I think the comment might be incorrect, but it is a popular gem so I wasn't sure. I think it is treating key really as a password, and I just wanted to verify.

https://github.com/attr-encrypted/encryptor/blob/master/lib/encryptor.rb#L57

  if options[:iv]
    cipher.iv = options[:iv]
    if options[:salt].nil?
      # Use a non-salted cipher.
      # This behaviour is retained for backwards compatibility. This mode
      # is not secure and new deployments should use the :salt options
      # wherever possible.
      cipher.key = options[:key]
    else
      # Use an explicit salt (which can be persisted into a database on a
      # per-column basis, for example). This is the preferred (and more
      # secure) mode of operation.
      cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(options[:key], options[:salt], 2000, cipher.key_len)
    end
  else
    cipher.pkcs5_keyivgen(options[:key])
  end

I'm intending to write something from scratch, and only use base libraries. My key comes from SecureRandom.base64(32) and I will store that in the code and Base64 decode it to get the binary key, and use that for encryption/decryption, along with random IVs for each data element. I don't think I need a salt for that. Would like to confirm.

Chloe
  • 1,708
  • 3
  • 16
  • 30

2 Answers2

19

You need both a salt and an IV when you do... two distinct actions, one needing a salt and the other an IV. That's your case here.

The salt relates to turning a password into a secret key. That's what is used in your example code: PBKDF2 is a password-based key derivation function. As anything which uses passwords, PBKDF2 needs configurable slowness (that's the "2000" parameter) and also uniqueness, which the salt grants. This is a subcase of password hashing, which is explained there.

The IV is needed for the actual encryption. CBC mode is a sequential algorithm, in which each data block is first XORed with the output of the processing of the previous block. It must start somewhere... so the IV is the arbitrary "previous block" to be used for the first block.

Generally speaking, CBC mode requires an IV which is uniformly random and cannot be predicted by an attacker who is in position of choosing part of the data which is to be encrypted (the BEAST attack on SSL is of that kind). However, trouble arises only when the same key is used at least twice. Therefore, the two following tricks may be applicable, and avoid the need to transmit an IV along the encrypted file:

  • PBKDF2 can be used to generate an output of configurable length. It is possible to generate with PBKDF2 enough bytes for the key and the IV.
  • A conventional, fixed IV (e.g. "all zeros") is used.

Both methods are valid only if the specific encryption key is used only once. This means that if the same password is used to encrypt two files, then a new random salt must be generated for each file. This implies that if the password-to-key transform is computationally expensive (and it should be), and many files must be encrypted with the same password, then the total cost can become prohibitive.

If the same salt is used for several files (with the same password)(*), then the consequence is that the same key will be used for all these files, which is fine... as long as each file also gets its own IV. So the IV must be stored somehow in the file header. On the other hand, if all files use the same salt, then maybe you can mutualize the storage space for that salt ?

The generic, safe method is to use a random IV (generated from a cryptographically strong PRNG) for each encryption run, regardless of how the key was obtained. This avoids making implicit assumptions on the key generation process and how often it occurs in the overall protocol. Also, this allows mutualizing the password-to-key transform if many files are to be encrypted as a batch process with the "same password": as long as each file gets its own random IV, the same key (derived once from the password, with one salt) can be safely applied for all. This is somehow what happens in TLS (version 1.1 and more): all records in a given connection get encrypted with the same key, but each record gets its own IV, and this is safe (in TLS 1.0, each record gets its own IV by copying it from the end of the previous encrypted record, which is vulnerable to BEAST because these IV are then predictable through observation; in TLS 1.1+, each record has a new, specific random IV).

(*) NEVER reuse a salt value for distinct passwords. Never.

Tom Leek
  • 170,038
  • 29
  • 342
  • 480
  • The conventional IV has one issue: It enables multi target attacks. With 256 bit keys that's irrelevant, but with 128 bit keys and many messages it might drop the security level a bit too much for comfort. – CodesInChaos Jan 03 '14 at 13:46
8

You understand correctly. The code you found includes a common nomenclature error. i originally misread the code. Tom Leek is correct. The code isn't screwing up, but rather it's using the salt while hashing then later using an IV while encrypting.

Many people conflate the terms 'salt' and 'initialization vector'. They serve the same purpose, but are technically used in different operations. Salt is used when hashing, IV when encrypting. In both cases, the purpose is to prevent the same input from always resulting in the same output by adding a random input.

If you see 'salt' in context of encryption, it probably means IV. If you see IV in context of hashing, it probably is the salt.


It is important to point out that, when encrypting, you need to protect the IV. There is a type of attack where an unprotected IV can be used to learn the encrypted data. BEAST (unless I'm misremembering) was an example of such an attack. You can get this protection automatically by using GCM, XST or a couple other newer encryption modes. If you use an older encryption mode like CBC, you'll need to protect the IV yourself iwth a signature or an HMAC.

atk
  • 2,156
  • 14
  • 15
  • http://blog.cryptographyengineering.com/2011/09/brief-diversion-beast-attack-on-tlsssl.html I think it's a very specific attack. – Chloe Jan 03 '14 at 04:05
  • 1
    Yep, that's it. TLS happened to make just the right mistakes to make BEAST possible, but the attack is possible against any protocol that makes those same attacks – atk Jan 03 '14 at 04:09
  • _"you need to protect the IV."_ I assume here that "protected" in your sentence means "secret". My amateur understanding is that BEAST exploits the fact that IVs were [_predictable_](https://crypto.stackexchange.com/q/22511). ["you just need to make sure that an adversary cannot predict the IV in advance".](https://crypto.stackexchange.com/a/75588) ["The IV itself is not supposed to be secret."](https://security.stackexchange.com/a/12076) I believe it is okay for IVs to be public - in particular, [they can be attached to the encrypted message.](https://stackoverflow.com/a/44704398) – DharmaTurtle Dec 21 '22 at 16:33
  • you are correct tha what you need to "protect" the IV from was undefined in my answer. At minimum, it needs to be protected from attacker control and reuse. Depending upon the algorithm/moose you may need to protect against other things, like predictability. – atk Dec 21 '22 at 19:04