Let's say that I want to save some encrypted data to a database through a Spring Boot microservice. For that I will be using Spring Security Crypto that, as the documentation says it uses AES256 with CBC or GCM and derives the key from a passphrase and salt through PBKDF2. And I want to comment about the possible security implications of some decisions. The database, being a database, will get many frequent read and write operations. Let's say that my project is quite successful and I get hundreds or thousands of requests per second, so the performance of the encryption and decryption process matters here.
- Since only the microservice writes to the database and the data doesn't come encrypted from the user (save for coming by HTTPS requests), I think I can improve the performance using CBC instead of GCM since the data don't need to be authenticated. It's only encrypted and decrypted by a trusted party (the microservice) supposing that the database access hasn't been compromised (we'll get to that) and returned in clear through HTTPS to the final user.
- The key derivation process needs a passphrase and a salt and here I have two options: Use a different random salt per encryption operation or use the same salt for all the records in the database and here is where I'd like to discuss the security vs performance implications.
I've seen libraries like Jasypt that generate a salt per encryption operation and saves this salt prepended to the encrypted message. With this approximation the encryption key is unique per encrypted text but the throughput gets a very huge performance penalty. The derived key needs to be computed per every encrypt and decrypt operation and that means that it needs to be computed constantly for a big number of read and write operations. Furthermore, even in a single record the key is different per encrypted column so if I want to read a record with three encrypted columns it will need to derive three keys per record. Multiply that by potentially hundreds of records.
Another possibility is to use a constant salt which is secret, just like the passphrase. In this situation the key is derived once when the microservice starts and it can be enforced to be even stronger. For example, since the service is starting and not serving I could enforce ten times or a hundred times the iterations needed to derive the key since it will only be computed once. After this, every operation to the database will use the same key and the throughput in any modern hardware is stellar given it uses AES-NI. The throughput gets multiplied by thousands over the first scenario.
The derived key will be in memory as long as the microservice runs but so will be the passphrase in the first case even using a random salt per encryption so a malicious attacker getting a memory dump will get the key in both cases. What's more, in the first case he would get the passphrase itself while in the second case he will get the derived key since the passphrase can be thrown immediately after the key has been generated.
Now let's suppose the database is compromised. ¿Is there any advantage in the random salt scenario over the constant salt one? If the salt is random it needs to be saved in clear prepended to the cyphered message so the attacker can get a record, get the salt, compose a rainbow table using this salt and try to decrypt the record. If it succeeds then the random salt won't save the rest of the records since he already knows the passphrase. On the other hand, if the salt is constant but secret, the attacker needs to compose a rainbow table for every possible passphrase and salt combination, making it harder to guess the passphrase and compose a rainbow table to attack a single record.
Barring the leak of the secret data (passphrase and salt, in which case the database is compromised for good with random or constant salt) I see that using a random salt in this case has a huge impact in the performance of the system, offering little to none security advantage over a constant but secret salt. ¿Am I missing something here? ¿Is there any type of attack that I'm missing and that can compromise the database data for using a AES-256 CBC with PBKDF2 and constant but secret salt?