Why would you need a salt for AES-CBS when IV is already randomly generated and stored with the encrypted data?
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
keyreally as a
password, and I just wanted to verify.
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.
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.