From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36509) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V4eLK-0008Tk-0S for qemu-devel@nongnu.org; Wed, 31 Jul 2013 17:54:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V4eLE-0000Du-UW for qemu-devel@nongnu.org; Wed, 31 Jul 2013 17:54:01 -0400 Received: from mx1.redhat.com ([209.132.183.28]:12013) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V4aX0-00047w-CR for qemu-devel@nongnu.org; Wed, 31 Jul 2013 13:49:50 -0400 Message-ID: <51F94EC8.5030203@redhat.com> Date: Wed, 31 Jul 2013 19:52:08 +0200 From: Laszlo Ersek MIME-Version: 1.0 References: <20130723124706.GB5002@irqsave.net> <20130723130053.GW2477@redhat.com> <20130723144033.GE5002@irqsave.net> <20130723152247.GC14190@stefanha-thinkpad.redhat.com> <20130723153800.GD20225@dhcp-200-207.str.redhat.com> <20130723155741.GI2477@redhat.com> <51EFF30E.9060102@redhat.com> <20130731152714.GC4926@irqsave.net> In-Reply-To: <20130731152714.GC4926@irqsave.net> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] QCOW2 cryptography and secure key handling List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?ISO-8859-1?Q?Beno=EEt_Canet?= Cc: Kevin Wolf , Paolo Bonzini , qemu-devel@nongnu.org, stefanha@redhat.com, Stefan Hajnoczi On 07/31/13 17:27, Beno=EEt Canet wrote: >> For example, current qcow2 encryption is vulnerable to a watermarking >> attack. >> http://en.wikipedia.org/wiki/Disk_encryption_theory#Cipher-block_chain= ing_.28CBC.29 >=20 > 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; >=20 > for(i =3D 0; i < nb_sectors; i++) { > ivec.ll[0] =3D cpu_to_le64(sector_num); > ivec.ll[1] =3D 0; > AES_cbc_encrypt(in_buf, out_buf, 512, key, > ivec.b, enc); > sector_num++; > in_buf +=3D 512; > out_buf +=3D 512; > } > } >=20 > 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_.28CT= R.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 =3D=3D 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 =3D=3D 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 =3D 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 :=3D 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 :=3D encrypt(sector_num ^ B1, secret_key) - The remaining 496 bytes (considered one big message) use "cipher1" as I= V. In the next sector (Y), - The first 16 bytes are encrypted using "sector_num+1" as IV: cipher2 :=3D encrypt((sector_num+1) ^ B2, secret_key) However, (sector_num+1) ^ B2 =3D=3D (sector_num+1) ^ (B1 ^ sector_num ^ (sector_num + 1)) =3D=3D (sector_num+1) ^ (sector_num + 1) ^ B1 ^ sector_num =3D=3D sector_num ^ B1 Therefore, cipher2 =3D=3D encrypt(sector_num ^ B1, secret_key) =3D=3D 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=3D=3Dcipher1 as IV. However, since the plaintext contents ("S") i= s shared between the trailing 496 bytes of both sectors, and secret_key is the same, and the cipher2=3D=3Dcipher1 IVs are the same too, these encryp= t 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