Closed mpalmer closed 7 months ago
Hello @mpalmer!
Thank you for the feedback. Generally you are right about the vulnerability of AES-CTR, but please also take into consideration the following details in our implementation:
VACUUM
for example.Even with the current state of things, without 4/5, the described attack is not that practical: the attacker needs the ability to run for example VACUUM FULL
on the table after a known and complete modification to it - and if he can do that, we can assume that the data is already compromised. I'm not saying that it's impossible, just that it is a very unlikely and specific scenario.
As for using XTS, or any other better algorithm: our current implementation approach (minimal modifications to the heap engine at the tuple level, as an extension) leaves us with limited options. We are actively discussing other approaches, but all of those would require modifications in postgres itself. We might also go in that direction in the future, but one of the requirements for this extension is that it works with postgres without any modifications.
AES-CTR, as with all stream ciphers (and block cipher modes that emulate a stream cipher) is vulnerable to key stream recovery if the same key stream is used to encrypt multiple blocks of data, when at least one of the encryptions is over a known plaintext (either predictable, such as all-zeroes, or provided by an attacker).
The vulnerability comes from the fact that the per-block key, which I'll call
X
, is statically derived from the encryption of the block counter with the main key. The stored ciphertext is simply the XOR of the plaintext,P
, with the per-block key,X
, to produceC
. If plaintextP
is known, the per-block keyX
can be trivially recovered withC XOR X
. This allows all other encryptions of the same block to be decrypted withC_n XOR X
.The most appropriate solution to this problem would be to switch to using a tweakable cipher mode, such as AES-XTS, for which there is an existing OpenSSL function, EVP_aes_128_xts.