Disk encryption and online backups have a different thread model. What's appropriate for one isn't necessarily appropriate for the other.
Disk encryption typically only protects against one threat: theft of the disk. With this threat, the attacker gains one version of the data in encrypted form, and the goal is to maintain the confidentiality of the data.
An online backup system needs to defend against two other important threats. If the attacker gains access to the server where the backups are stored, they can access multiple versions of the encrypted data. So it's important that the difference between successive ciphertexts doesn't reveal too much about the plaintext. Furthermore, when you restore from the backup, it's absolutely crucial to verify that the backup is genuine. An attacker who has access to the server might have corrupted the ciphertext even if they weren't able to decipher it.
Disk encryption often uses XTS mode. XTS encrypts each disk block independently. Successive versions of a block are encrypted with the same key and IV, which can reveal a common prefix, but not much more. (XTS isn't very malleable, unlike, say, CTR, where repeating a counter value is an instant fail.) XTS does not protect the data's authenticity at all. Disk encryption typically makes no attempt to verify authenticity or integrity because it isn't necessary in the usual threat model and it has a high impact on performance¹.
For an online backup, you need some form of authenticated encryption. Authenticated encryption protects two things:
- The data's confidentiality: without the key, all the attacker knows is the approximate size. With successive versions of the same data, the attacker can know approximately what parts of the data have changed.
- The data's authenticity: when you read back some data and it verifies as correct, you know that the data is genuine. There's a subtlety here: genuine data could still be misplaced — it could be from a different location on the disk, or from a different version.
To make sure that the data is genuine without having to authenticate and read it all back as a single message, you can use a hash tree structure. Each block of data (or each file, depending on how you structure the data) has an authentication tag, and the blocks/files are organized in sets for which there is an authentication tag, and the sets are organized in supersets and so on until you get to the root. To verify that a block is genuine, you need to:
- verify that its authentication tag is correct;
- read the set containing that block and check that it contains the correct authentication tag;
- calculate and verify the authentication tag of the set;
- read the superset containing the set, and so on until the root.
With these verifications, you can retrieve files individually (plus a small overhead to retrieve the parent sets), and be confident that an attacker didn't substitute confidential_data.txt
for public_mailing.txt
. You can also be confident that the attacker didn't arrange to return database_schema.txt
from last month with database.db
from last week. There's still a limitation: the attacker could arrange to return a stale backup, as long as they return consistent data. To avoid that you need to remember the date or version of the last backup.
¹ If you need authenticity protection, you can't pipeline reads: you have to read a whole data block and verify it before you can serve the first byte to the reader. Furthermore, to protect against block reordering or version mix-and-matching, you have to verify that the ciphertext is the correct one for this position on the disk and is the correct version, which means that writes need to update more metadata.