qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] QCOW2 cryptography and secure key handling


From: Laszlo Ersek
Subject: Re: [Qemu-devel] QCOW2 cryptography and secure key handling
Date: Wed, 31 Jul 2013 19:52:08 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130621 Thunderbird/17.0.7

On 07/31/13 17:27, Benoît Canet wrote:
>> For example, current qcow2 encryption is vulnerable to a watermarking
>> attack.
>> http://en.wikipedia.org/wiki/Disk_encryption_theory#Cipher-block_chaining_.28CBC.29
> 
> void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
>                            uint8_t *out_buf, const uint8_t *in_buf,
>                            int nb_sectors, int enc,
>                            const AES_KEY *key)
> {
>     union {
>         uint64_t ll[2];
>         uint8_t b[16];
>     } ivec;
>     int i;
> 
>     for(i = 0; i < nb_sectors; i++) {
>         ivec.ll[0] = cpu_to_le64(sector_num);
>         ivec.ll[1] = 0;
>         AES_cbc_encrypt(in_buf, out_buf, 512, key,
>                         ivec.b, enc);
>         sector_num++;
>         in_buf += 512;
>         out_buf += 512;
>     }
> }
> 
> CBC mode would imply that each sector would be crypted by combining the
> plaintext with the previous sector.
> It's does not look to be the case as the IV is reset to sector_num for each
> sector.
> It look like CTR mode.

No, it's CBC.

Each individual sector is encrypted with CBC. For each sector, the IV is
selected with a scheme that "resembles" CTR, but (a) IV selection is a
different concept from chaining mode, (b) the IV generation used above
is *not* CTR either.

http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29

http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29

The watermarking attack Paolo linked does work here:

    If the IVs are predictable an adversary can manage to store a file
    specially created to zero out the IV, it is possible to leave a
    "watermark" on the disk, proving that the specially created file is,
    indeed, stored on disk. The exact method of constructing the
    watermark depends on the exact function providing the IVs; but the
    general recipe is to create two encrypted sectors which have
    identical first blocks b1 and b2;  these two are then related to
    each other by

      b1 xor IV1 == b2 xor IV2

    Thus, when these two blocks are encrypted, they both encrypt to the
    same thing, leaving a watermark on the disk.

We can "xor IV2" both sides of the above equation:

  b1 xor IV1 xor IV2 == b2

Suppose that you as the attacker can have a good guess at the
"sector_num" parameter of the qcow2_encrypt_sectors() function. Then you
create two (consecutive) sectors:

sector X:
- Let's denote the first 16 bytes with B1. The contents of these bytes
doesn't matter, you can fill them from /dev/urandom eg. for good
selectivity. (16 bytes because that's the block size of AES.)

- Let's denote the remaining 512-16 = 496 bytes with S. The same idea
covers the contents of S.

Then, sector Y:
- Let's denote the first 16 bytes with B2. Prepare their contents as
follows:

  B2 := B1 ^ sector_num ^ (sector_num + 1)

- The remaining 496 bytes should be filled with the same S.


When qcow2_encrypt_sectors() is called with the "sector_num" you
predicted, with "in_buf" pointing at X directly followed by Y, the
following happens:

In the first sector (X),
- The first 16 bytes are encrypted using "sector_num" as IV:

  cipher1 := encrypt(sector_num ^ B1, secret_key)

- The remaining 496 bytes (considered one big message) use "cipher1" as IV.

In the next sector (Y),
- The first 16 bytes are encrypted using "sector_num+1" as IV:

  cipher2 := encrypt((sector_num+1) ^ B2, secret_key)

However,

  (sector_num+1) ^ B2 ==
  (sector_num+1) ^ (B1 ^ sector_num ^ (sector_num + 1)) ==
  (sector_num+1) ^ (sector_num + 1) ^ B1 ^ sector_num ==
  sector_num ^ B1

Therefore,

  cipher2 == encrypt(sector_num ^ B1, secret_key) ==
  cipher1

Which means that the first 16 bytes of these two sectors will look the
same in the encrypted image.

- The remaining 496 bytes in the second block are encrypted using
cipher2==cipher1 as IV. However, since the plaintext contents ("S") is
shared between the trailing 496 bytes of both sectors, and secret_key is
the same, and the cipher2==cipher1 IVs are the same too, these encrypt
to the same data as well.

You'll end up with two identical sectors in the encrypted image.

    To protect against the watermarking attack, a cipher or a hash
    function is used to generate the IVs from the key and the current
    sector number, so that an adversary cannot predict them. In
    particular, the ESSIV approach uses a block cipher in CTR mode to
    generate the IVs.

Laszlo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]