Hi Jari,
thanks for elaborating a bit on these issues, your comments are quite
interesting to me. I tried to create the sceneario you described,
however I'm not sure if I've done everything right:
On Wed, 30 May 2007, Jari Ruusu wrote:
1) Set up a small dm-crypt essiv AES encrypted device
# dd if=/dev/zero of=/tmp/disk1.img count=50 bs=1M
# sudo losetup /dev/loop/0 /tmp/disk1.img
# sudo losetup /dev/loop/0
/dev/loop/0: [000f]:1575167 (/tmp/disk1.img)
# head -c 2880 /dev/urandom|uuencode -m -|head -n 65|tail -n 64|gpg -ac --cipher-algo aes256 --digest-algo SHA512 > /tmp/k.gpg
# gpg -d /tmp/k.gpg 2>/dev/null | sudo cryptsetup luksFormat -c aes-cbc-essiv:sha256 -s 192 /dev/loop0
# gpg -d /tmp/k.gpg 2>/dev/null | sudo cryptsetup luksOpen /dev/loop0 test1
# sudo cryptsetup status test1
/dev/mapper/test1 is active:
cipher: aes-cbc-essiv:sha256
keysize: 192 bits
device: /dev/loop0
offset: 1544 sectors
size: 100856 sectors
mode: read/write
2) Write some data to to plaintext device
# ls -lgo words && head -1 words
-rw-r--r-- 1 9728 May 31 23:51 words
Abelard
# sudo dd if=words of=/dev/mapper/test1
3) Save copy of ciphertext
(I noticed that I had to close the test1, to get the data down to the
loop0)
# sudo cryptsetup luksClose test1
# sudo dd if=/dev/loop0 of=test1.loop0
# sha1sum test1.loop0
9653a783668f453903bdad23ac2c8a87bfe52807 test1.loop0
4) Write same data again, but with first byte of some 512 byte sector
altered.
Hm, I tried:
# dd if=words 2>/dev/null | sed 's/^Abelard$/9belard/' | head -1
9belard
# dd if=words 2>/dev/null | sed 's/^Abelard$/9belard/' | sudo dd of=/dev/mapper/test1
# sudo cryptsetup luksClose test1
# sudo dd if=/dev/loop0 of=test1.loop0.altered
5) Compare previous and current ciphertexts. You will notice ciphertexts
will differ on first cipherblock within that 512 byte sector. This
leaked that there was plaintext change within first plaintext block
inside that 512 byte sector.
# sha1sum test1.loop0 test1.loop0.altered
9653a783668f453903bdad23ac2c8a87bfe52807 test1.loop0
9f68c329de554ccf6f0a81c3d3a21ef47410b9bf test1.loop0.altered
# cmp -b test1.loop0 test1.loop0.altered
test1.loop0 test1.loop0.altered differ: byte 790529, line 373 is 234 M-^\ 201 M-^A
# od -x test1.loop0 > test1.loop0.hex
# od -x test1.loop0.altered > test1.loop0.altered.hex
diff -u test1.loop0.hex test1.loop0.altered.hex | wc -l
73
6) Save copy of ciphertext
done (test1.loop0)
7) Now modify plaintext data again, alter 130th byte of some 512 byte
sector.
Hm, a bit trickyer for me, I used dd/vi to alter the "words" file:
# vi words
[...]
# gpg -d /tmp/k.gpg 2>/dev/null | sudo cryptsetup luksOpen /dev/loop0 test1
# dd if=words 2>/dev/null | sudo dd of=/dev/mapper/test1
# sudo cryptsetup luksClose test1
# sudo dd if=/dev/loop0 of=test1.loop0.altered.130
8) Compare previous and current ciphertexts. You will notice ciphertexts
will differ on 9th cipherblock within that 512 byte sector. This leaked
that there was plaintext change within 9th plaintext block inside that
512 byte sector.
# sha1sum test1.loop0 test1.loop0.altered test1.loop0.altered.130
9653a783668f453903bdad23ac2c8a87bfe52807 test1.loop0
9f68c329de554ccf6f0a81c3d3a21ef47410b9bf test1.loop0.altered
5dc0e66f0ff0d37959bf9cd43bb0433ecaae6728 test1.loop0.altered.130
# cmp -b test1.loop0.altered test1.loop0.altered.130
test1.loop0.altered test1.loop0.altered.130 differ: byte 790529, line 373 is 201 M-^A 234 M-^\
# diff -u test1.loop0.altered.hex test1.loop0.altered.130.hex | wc -l
113
...While I'm not sure if the "9th plaintext block" I notice that the
line# is the same and the values swapped. spooky :)
9) Save copy of ciphertext
done (test1.loop0)
10) Modify plaintext data again, alter last byte of some 512 byte sector.
Again, with vi(1):
# vi words
[...]
# gpg -d /tmp/k.gpg 2>/dev/null | sudo cryptsetup luksOpen /dev/loop0 test1
# dd if=words 2>/dev/null | sudo dd of=/dev/mapper/test1
# sudo cryptsetup luksClose test1
11) Compare previous and current ciphertexts. You will notice ciphertexts
will differ on last cipherblock within that 512 byte sector. This leaked
that there was plaintext change within last plaintext block inside that
512 byte sector.
# cmp test1.loop0.altered.130 test1.loop0.altered.512
test1.loop0.altered.130 test1.loop0.altered.512 differ: char 791025, line 376
# diff -u test1.loop0.altered.130.hex test1.loop0.altered.512.hex | wc -l
11
In case someone is interested, I've put all the .hexfiles and the diffs
on: http://nerdbynature.de/bits/dm-crypt-fun/
If you do above test with loop-AES version 2 or 3 on-disk format, you will
notice that all cipherblocks within the 512 byte sector change regardless of
where changed plaintext data is, thus hiding what location was changed.
I'll do this tomorrow, after getting some sleep. I'm surprised that this
(already known) issue has not been addressed in dm-crypt. Yes, I know
about the flamewars dm-crypt vs. loop-aes vs. whatnot but that's no
excuse for not documenting this flaw (I said 'documenting', because how
can someone *expect* to get a bug fixed in the OSS world ;)).
loop-AES still leaks what 512 byte sectors have been modified, because full
512 byte sector ciphertexts will be different, but such significantly lower
resolution is much better than adversary being able to pinpoint changes
inside 512 byte sector.
Hm, would it be possible to get this note into the loop-AES.README,
maybe under "8. Security levels"?
Thank you for your time,
Christian.
--
BOFH excuse #247:
Due to Federal Budget problems we have been forced to cut back on the number of users able to access the system at one time. (namely none allowed....)
-
Linux-crypto: cryptography in and on the Linux system
Archive: http://mail.nl.linux.org/linux-crypto/