November 02, 2013

Physical layout of data on disk and encryption in Linux

I’d like to share with my observations on how the data is arranged on a physical disk and reading further you will also understand how does the encryption look like on a disk.

The test scenario is to create 16 bytes file, filled with ones “1”, then to see how does it look like on a disk, find its location relative to the beginning of a disk (/dev/vda), also to see how does it look like when encrypted, and what is changed when its contents are altered.

I’ll use Debian 7.2 running under KVM, ext4 filesystem on LVM and AES in XTS mode.

Virtual disk size is 8GB. FS,LVM and, later, encryption layouts are default as Debian installer recommends.

Block device listing

root@debian:~# lsblk -f /dev/vda
NAME                     FSTYPE      LABEL MOUNTPOINT
vda
├─vda1                   ext2              /boot
├─vda2
└─vda5                   LVM2_member
  ├─rootvg-root (dm-0)   ext4              /
  ├─rootvg-swap_1 (dm-1) swap              [SWAP]
  ├─rootvg-usr (dm-2)    ext4              /usr
  ├─rootvg-var (dm-3)    ext4              /var
  ├─rootvg-tmp (dm-4)    ext4              /tmp
  └─rootvg-home (dm-5)   ext4              /home

Creating test data

Create a file filled with “1”’s, 16bytes in size.

root@debian:/tmp# while true; do printf 1;done |dd bs=16 count=1 of=./test.txt
1+0 records in
1+0 records out
16 bytes (16 B) copied, 0.00459532 s, 3.5 kB/s
root@debian:/tmp# ls -la ./test.txt
-rw-r--r-- 1 root root 16 Nov  1 16:52 ./test.txt
root@debian:/tmp# hexdump -C ./test.txt
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00000010

Make sure that data was physically written on a disk

# sync && mount -o remount /tmp && echo 1 | tee /proc/sys/vm/drop_caches

Looking for a file location relative to the beginning of the device

(hdparm method) Find a file offset relative to the beginning of the device

root@debian:/tmp# hdparm --fibmap ./test.txt

./test.txt:
 filesystem blocksize 1024, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0      16902      16903          2

16902*512 = 8653824 byte

(filefrag method) Find a file offset relative to the beginning of the device

root@debian:/tmp# filefrag -bsv ./test.txt
Filesystem type is: ef53
File size of ./test.txt is 16 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0     8451               1 eof
./test.txt: 1 extent found

8451 (in 1024 blocksize) - is an offset where data starts.

8451*1024 = 8653824 byte

Reading contents of a file relative to the beginning of the device

root@debian:/tmp# df .
Filesystem             1K-blocks  Used Available Use% Mounted on
/dev/mapper/rootvg-tmp    230069  6159    212032   3% /tmp

root@debian:/tmp# dd if=/dev/mapper/rootvg-tmp bs=1024 count=1 skip=8451 |hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.0161307 s, 63.5 kB/s

The same can be achieved with hexdump

root@debian:/tmp# hexdump -C -s $((8451*1024)) -n 1024 /dev/mapper/rootvg-tmp
00840c00  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00840c10  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00841000

hexdump indicates the offset in HEX -> 0x00840c00 = 8653824 (8451*1024)

Reading contents of a file relative to the beginning of the disk

Note: ‘-u’ gives sizes in sectors instead of cylinders.

root@debian:/tmp# fdisk -u -l /dev/vda

Disk /dev/vda: 8589 MB, 8589934592 bytes
16 heads, 63 sectors/track, 16644 cylinders, total 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00020cff

   Device Boot      Start         End      Blocks   Id  System
/dev/vda1   *        2048      499711      248832   83  Linux
/dev/vda2          501758    16775167     8136705    5  Extended
/dev/vda5          501760    16775167     8136704   8e  Linux LVM

dmsetup can show the beginning of the target device relative to the beginning of the parent device

root@debian:/tmp# dmsetup table rootvg-tmp
0 475136 linear 254:5 10053632
root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+(10053632)+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

What we skipped is following

  • 501760 (in 512 byte blocks) - Starting sector of the partition (/dev/vda5) used for LVM (physical volume)
  • 10053632 (in 512 byte blocks) - Starting point of the LV relative to the beginning of the device (/dev/vda5)
  • (8451*1024)/512 - Starting point of the test.txt file on a filesystem relative to the beginning of the LV

With hexdump

root@debian:/tmp# hexdump -C -s $(( 512* (501760+(10053632)+(8451*1024)/512) )) -n 512 /dev/vda
142a40c00  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
142a40c10  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
142a40e00

0x142a40c00 = 5413014528 byte

LUKS encryption

Before starting I suggest to read

Block device listing

root@debian:~# lsblk -f /dev/vda
NAME                       FSTYPE      LABEL MOUNTPOINT
vda
├─vda1                     ext2              /boot
├─vda2
└─vda5                     crypto_LUKS
  └─vda5_crypt (dm-0)      LVM2_member
    ├─rootvg-root (dm-1)   ext4              /
    ├─rootvg-usr (dm-2)    ext4              /usr
    ├─rootvg-var (dm-3)    ext4              /var
    ├─rootvg-swap_1 (dm-4) swap              [SWAP]
    ├─rootvg-tmp (dm-5)    ext4              /tmp
    └─rootvg-home (dm-6)   ext4              /home

The ./test.txt file filled with ones “1” was created as follows

root@debian:/tmp# while true; do printf 1;done |dd bs=16 count=1 of=./test.txt
1+0 records in
1+0 records out
16 bytes (16 B) copied, 0.00459532 s, 3.5 kB/s
root@debian:/tmp# ls -la ./test.txt
-rw-r--r-- 1 root root 16 Nov  1 17:15 ./test.txt
root@debian:/tmp# hexdump -C ./test.txt
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00000010

Find a file offset relative to the beginning of the device (in our case the device is /dev/mapper/rootvg-tmp)

root@debian:/tmp# hdparm --fibmap ./test.txt

./test.txt:
 filesystem blocksize 1024, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0      16902      16903          2
root@debian:/tmp# filefrag -bsv ./test.txt
Filesystem type is: ef53
File size of ./test.txt is 16 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0     8451               1 eof
./test.txt: 1 extent found

Reading file contents relative to the beginning of the device

root@debian:/tmp# dd if=/dev/mapper/rootvg-tmp bs=1024 count=1 skip=8451 |hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.0069164 s, 148 kB/s
root@debian:/tmp# hexdump -C -s $((8451*1024)) -n 1024 /dev/mapper/rootvg-tmp
00840c00  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
00840c10  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00841000

Looking at the encrypted block

root@debian:/tmp# fdisk -u -l /dev/vda

Disk /dev/vda: 8589 MB, 8589934592 bytes
16 heads, 63 sectors/track, 16644 cylinders, total 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000047b6

   Device Boot      Start         End      Blocks   Id  System
/dev/vda1   *        2048      499711      248832   83  Linux
/dev/vda2          501758    16775167     8136705    5  Extended
/dev/vda5          501760    16775167     8136704   83  Linux

root@debian:/tmp# dmsetup table rootvg-tmp
0 475136 linear 253:0 10053632

root@debian:/tmp# dmsetup table vda5_crypt
0 16269312 crypt aes-xts-plain64 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0 254:5 4096

root@debian:/tmp# dmsetup table rootvg-tmp
0 475136 linear 253:0 10053632

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C -n32
00000000  96 6a 48 e3 7e 31 d8 f4  6c 2c 86 a6 02 49 f5 e5  |.jH.~1..l,...I..|
00000010  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|

Altering the test file contents in order to see a change in the encrypted block.

Writing number “2” to the end of a test file.

root@debian:/tmp# printf 2 |dd of=./test.txt count=1 bs=1 seek=15 status=noxfer
1+0 records in
1+0 records out

root@debian:/tmp# filefrag -bsv ./test.txt
Filesystem type is: ef53
File size of ./test.txt is 16 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0     8451               1 eof
./test.txt: 1 extent found

After each ./test.txt file modification, always make sure (using hdparm of filefrag) that physical offset did not changed.

root@debian:/tmp# hexdump -C ./test.txt
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 32  |1111111111111112|
00000010
root@debian:/tmp# sync && mount -o remount /tmp && echo 1 | tee /proc/sys/vm/drop_caches
root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C  -n32
00000000  c8 c2 19 59 ea 54 3c e7  05 6f 80 98 94 7d df 37  |...Y.T<..o...}.7|
00000010  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|
00000020

One more attempt.

root@debian:/tmp# printf 3 |dd of=./test.txt count=1 bs=1 seek=15 status=noxfer
1+0 records in
1+0 records out
root@debian:/tmp# hexdump -C ./test.txt
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 33  |1111111111111113|
00000010
root@debian:/tmp# sync && mount -o remount /tmp && echo 1 | tee /proc/sys/vm/drop_caches
1
root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C  -n32
00000000  38 59 ca b4 86 b3 aa 99  27 5f 5c 3b c0 6c 4c 3d  |8Y......'_\;.lL=|
00000010  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|
00000020

Extra

Reading directly from /dev/vda5

root@debian:/tmp# dd if=/dev/vda5 bs=512 count=1 skip=$(( 4096+10053632+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C  -n32
00000000  38 59 ca b4 86 b3 aa 99  27 5f 5c 3b c0 6c 4c 3d  |8Y......'_\;.lL=|
00000010  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|
00000020

Reading directly from decrypted device

root@debian:/tmp# dd if=/dev/mapper/vda5_crypt bs=512 count=1 skip=$(( 10053632+(8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C  -n32
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 33  |1111111111111113|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020

Reading directly from LV

root@debian:/tmp# dd if=/dev/mapper/rootvg-tmp bs=512 count=1 skip=$(( (8451*1024)/512 )) status=noxfer 2>/dev/null|hexdump -C  -n32
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 33  |1111111111111113|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020

Simulating LUKS container

Recreating new container using master key of original volume

root@debian:/tmp# cryptsetup luksDump /dev/vda5
LUKS header information for /dev/vda5

Version:       	1
Cipher name:   	aes
Cipher mode:   	xts-plain64
Hash spec:     	sha1
Payload offset:	4096
MK bits:       	512
MK digest:     	e2 51 ef 39 ba 4f 55 04 86 55 27 98 b0 fe 18 59 cc d7 df bd
MK salt:       	23 e3 17 94 c1 40 f6 97 f5 26 fd 04 d9 89 a6 3b
               	72 b3 b3 3e ba 01 ec 9c 31 dd 0f 50 4f 60 93 3d
MK iterations: 	43500
UUID:          	814ed852-3354-4f79-beb2-12b0146492df

Key Slot 0: ENABLED
	Iterations:         	174019
	Salt:               	0c 9e 77 23 72 8d 9c 58 08 20 5a 0b 02 83 a9 51
	                      	d3 99 a7 70 1c ef 8c 1e 1f ec a6 3b a8 4c eb a4
	Key material offset:	8
	AF stripes:            	4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Dump your master key

root@debian:/tmp# dmsetup table vda5_crypt --showkeys
0 16269312 crypt aes-xts-plain64 9a7a685a9b03218f773d9235b7b51922df8ffad4900bbc97f4152c4fd5a85b821953bfb192c6d7f1c01a689462bae979ad8b757f5e2e89e523ad2bb9a50a63fc 0 254:5 4096

You can also use cryptsetup command to get the master key

root@debian:/tmp# cryptsetup luksDump --dump-master-key /dev/vda5

**WARNING!**
========
LUKS header dump with volume key is sensitive information
which allows access to encrypted partition without passphrase.
This dump should be always stored encrypted on safe place.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
LUKS header information for /dev/vda5
Cipher name:   	aes
Cipher mode:   	xts-plain64
Payload offset:	4096
UUID:          	814ed852-3354-4f79-beb2-12b0146492df
MK bits:       	512
MK dump:	9a 7a 68 5a 9b 03 21 8f 77 3d 92 35 b7 b5 19 22
		df 8f fa d4 90 0b bc 97 f4 15 2c 4f d5 a8 5b 82
		19 53 bf b1 92 c6 d7 f1 c0 1a 68 94 62 ba e9 79
		ad 8b 75 7f 5e 2e 89 e5 23 ad 2b b9 a5 0a 63 fc

Save the mater key to a file

# echo -n "9a7a685a9b03218f773d9235b7b51922df8ffad4900bbc97f4152c4fd5a85b821953bfb192c6d7f1c01a689462bae979ad8b757f5e2e89e523ad2bb9a50a63fc" | xxd -r -p > master.key

root@debian:/tmp# hexdump -C ./master.key
00000000  9a 7a 68 5a 9b 03 21 8f  77 3d 92 35 b7 b5 19 22  |.zhZ..!.w=.5..."|
00000010  df 8f fa d4 90 0b bc 97  f4 15 2c 4f d5 a8 5b 82  |..........,O..[.|
00000020  19 53 bf b1 92 c6 d7 f1  c0 1a 68 94 62 ba e9 79  |.S........h.b..y|
00000030  ad 8b 75 7f 5e 2e 89 e5  23 ad 2b b9 a5 0a 63 fc  |..u.^...#.+...c.|
00000040

Copying encrypted block data to ./todecrypt.luks file

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632+(8451*1024)/512 )) status=noxfer of=./todecrypt.luks 2>/dev/null
root@debian:/tmp# ls -lah todecrypt.luks
-rw-r--r-- 1 root root 512 Nov  1 18:55 todecrypt.luks
root@debian:/tmp# hexdump -C ./todecrypt.luks
00000000  38 59 ca b4 86 b3 aa 99  27 5f 5c 3b c0 6c 4c 3d  |8Y......'_\;.lL=|
00000010  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|
00000020  a1 46 a0 40 85 42 82 82  27 b1 99 89 25 b7 a1 c4  |.F.@.B..'...%...|
00000030  55 57 de 53 47 5d a8 d8  fe 2f 37 7a 4b 8c 7f 41  |UW.SG].../7zK..A|
00000040  b7 f9 ad 62 c8 49 0f 52  3b cd 7e 6a 39 89 ee 6a  |...b.I.R;.~j9..j|
00000050  98 d9 23 f0 cf 3b ce 79  4c 11 87 62 33 0e 96 29  |..#..;.yL..b3..)|
00000060  7a 6f c2 25 50 eb 8f b8  b3 de 90 ba 97 b6 da b5  |zo.%P...........|
00000070  91 a4 c5 cc ab d0 c9 0a  2d 1f 2d 88 a0 28 8c 32  |........-.-..(.2|
00000080  15 f7 58 f0 aa cd 7f 50  01 55 23 f2 18 2f 90 6d  |..X....P.U#../.m|
00000090  7c 03 7f a0 32 68 66 1c  48 cd ce 5c 07 9b f7 71  ||...2hf.H..\...q|
000000a0  80 fa 08 a8 2f 71 45 3d  c0 f8 67 39 b4 96 10 ce  |..../qE=..g9....|
000000b0  72 60 a0 bd ae 37 b1 32  10 b1 7a 1c 76 53 f6 3f  |r`...7.2..z.vS.?|
000000c0  66 eb f8 96 3c 32 1e 18  4b a2 77 7e be 0d 8d bb  |f...<2..K.w~....|
000000d0  a5 99 97 54 6d 9e dc 4d  1d c2 0d ba 78 db ff ed  |...Tm..M....x...|
000000e0  44 8f 61 31 84 24 68 ab  db 6a e7 9d 0a 44 a5 90  |D.a1.$h..j...D..|
000000f0  c1 f8 28 bc e3 4c ac 5c  1f bd 7e a4 90 57 89 3a  |..(..L.\..~..W.:|
00000100  bb 90 3d c0 4b 7d a0 94  f5 1b 0a 12 c0 9e d9 d9  |..=.K}..........|
00000110  f8 25 a7 0f 6b ca 73 57  90 e4 96 bd 26 b4 a4 ad  |.%..k.sW....&...|
00000120  28 7a 7c 69 d3 5a 8b a7  b4 f5 bf b8 a2 81 11 3d  |(z|i.Z.........=|
00000130  8a d0 c6 a5 3f 12 0e 6e  37 2d 30 c7 c0 c9 f9 70  |....?..n7-0....p|
00000140  7f 13 45 ad 41 17 c4 96  8a 78 a5 4a da 61 3a fc  |..E.A....x.J.a:.|
00000150  75 96 5c 39 d3 46 3f cb  10 2b 1c a5 84 3a 61 d1  |u.\9.F?..+...:a.|
00000160  44 37 67 4a a0 b4 44 70  b4 1a 86 45 4f be 1f 1b  |D7gJ..Dp...EO...|
00000170  4a 20 70 a8 40 3e 69 a0  a9 50 89 7e 70 f4 ab 73  |J p.@>i..P.~p..s|
00000180  c7 b9 85 7b 3a 37 cd 0d  8a fc ad fc b4 13 c6 27  |...{:7.........'|
00000190  41 64 f0 a9 95 89 10 c5  8c f0 5b 9b 44 b6 af ab  |Ad........[.D...|
000001a0  ec 9a 20 3f b9 ce c1 f0  18 e4 1c 36 d6 8d b5 d8  |.. ?.......6....|
000001b0  5c 42 21 b0 57 e7 a8 76  85 a9 ff f2 39 f8 d4 39  |\B!.W..v....9..9|
000001c0  ee 6a 4d db ad d6 ab ab  f8 d6 3e 92 38 cf c9 58  |.jM.......>.8..X|
000001d0  54 be 74 af 40 c0 9d 4d  98 75 b1 9e 20 6d 28 6b  |T.t.@..M.u.. m(k|
000001e0  ec 71 5a ff 39 3a cb dd  37 7f aa 73 c9 13 d4 9e  |.qZ.9:..7..s....|
000001f0  d1 8a 1f cc c0 a3 d6 a7  41 f8 ae 3e a4 8e 46 88  |........A..>..F.|
00000200

Create dummy.luks file with size of 2MB (which is just enough to store LUKS Header and Keyslots)

root@debian:/tmp# dd if=/dev/zero of=./dummy.luks bs=512 count=4096
4096+0 records in
4096+0 records out
2097152 bytes (2.1 MB) copied, 0.0183268 s, 114 MB/s
root@debian:/tmp# ls -latrh dummy.luks
-rw-r--r-- 1 root root 2.0M Nov  1 19:00 dummy.luks
root@debian:/tmp# losetup /dev/loop1 ./dummy.luks
root@debian:/tmp# cryptsetup luksFormat --cipher aes-xts-plain64 --key-size 512 --master-key-file ./master.key /dev/loop1

WARNING!
========
This will overwrite data on /dev/loop1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
Verify passphrase:
root@debian:/tmp#

NOTE: You can leave an empty passphrase. (just hit Enter)

Appending encrypted block to the LUKS container

root@debian:/tmp# dd if=./todecrypt.luks of=./dummy.luks bs=512 count=1 oflag=append conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 8.9331e-05 s, 5.7 MB/s
root@debian:/tmp# losetup -c /dev/loop1
root@debian:/tmp#

Open the dummy LUKS container

root@debian:/tmp# cryptsetup luksOpen /dev/loop1 dummy.deluks
Enter passphrase for /dev/loop1:

root@debian:/tmp# hexdump -C /dev/mapper/dummy.deluks

root@debian:/tmp# cryptsetup luksClose dummy.deluks

Alternatively you could “clone” the original LUKS headers to the dummy LUKS container

root@debian:/tmp# cryptsetup luksHeaderBackup /dev/vda5 --header-backup-file ./vda5.luks.header
root@debian:/tmp# cryptsetup luksHeaderRestore /dev/loop1 --header-backup-file ./vda5.luks.header

root@debian:/tmp# cryptsetup luksOpen /dev/loop1 dummy.deluks
Enter passphrase for /dev/loop1: luks

To completely recreate LUKS headers without destroying the encrypted data

root@debian:/tmp# cryptsetup luksClose dummy.deluks
root@debian:/tmp# dd if=/dev/zero of=./dummy.luks bs=512 count=4096 conv=notrunc
root@debian:/tmp# cryptsetup luksFormat --cipher aes-xts-plain64 --key-size 512 --master-key-file ./master.key /dev/loop1
root@debian:/tmp# cryptsetup luksOpen /dev/loop1 dummy.deluks
root@debian:/tmp# hexdump -C /dev/mapper/dummy.deluks
00000000  e4 47 d7 3f 21 1f de 8b  50 92 7c e8 5a cc 7b 86  |.G.?!...P.|.Z.{.|
...

Moving encrypted block of data to the dummy LUKS device

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632+0 )) status=noxfer of=./todecrypt.luks 2>/dev/null

If you are changing size of a dummy LUKS device, you have to let device-mapper and LUKS aware of this

root@debian:/tmp# losetup -c /dev/loop1
root@debian:/tmp# cryptsetup resize dummy.deluks

To replace 512 bytes starting from 4096’s sector (sector size is 512 bytes)

root@debian:/tmp# dd if=./todecrypt.luks of=./dummy.luks bs=512 seek=4096 count=1 conv=notrunc

Trying to decrypt previously copied encrypted block of data

root@debian:/tmp# hexdump -C /dev/mapper/dummy.deluks

For some reason it does not give the desired result…

However, it will be OK if starting to decrypt the data from the very beginning of the encrypted area, see below.

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096 )) status=noxfer of=./todecrypt.luks 2>/dev/null
root@debian:/tmp# hexdump -C /dev/mapper/dummy.deluks
00000000  be 87 04 3b 77 d9 c2 20  f7 11 c5 5b 46 1a d2 71  |...;w.. ...[F..q|
00000010  f5 e8 84 fe 59 6c c4 0f  91 d6 0f 19 56 e1 cb e3  |....Yl......V...|
00000020  3b 51 f7 fc a8 1c d6 db  bd da 1e c1 28 e3 ae 54  |;Q..........(..T|
00000030  10 0c 3d d8 90 b7 18 85  a5 08 eb 9b 48 a1 ff 52  |..=.........H..R|
00000040  e8 98 f2 db d2 ba c1 dd  f9 c0 f7 c3 85 1c 99 a7  |................|
00000050  65 67 c8 b3 a2 16 b3 f5  b1 a2 69 58 c1 37 cf 7e  |eg........iX.7.~|
00000060  1a dc d9 88 95 fe 24 51  6b 40 ee ec 56 59 8e 04  |......$Qk@..VY..|
00000070  51 60 05 33 67 cc a9 ec  f2 21 86 30 9e 11 a1 d6  |Q`.3g....!.0....|
00000080  db 49 cb 79 d4 6a 9a 9a  fc 05 89 53 98 d3 0c 6f  |.I.y.j.....S...o|
00000090  f8 da 24 0d 66 64 f3 73  10 6b a7 da 89 dc 0a 39  |..$.fd.s.k.....9|
000000a0  3e 4c 4c 61 9d 87 6e b3  83 06 a3 48 ef 92 59 db  |>LLa..n....H..Y.|
000000b0  49 d5 09 0b b9 3f f3 6a  33 f2 8b 53 1d c1 5a 5d  |I....?.j3..S..Z]|
000000c0  a6 25 74 07 2b c9 44 03  98 a6 71 d5 72 4e 9f 25  |.%t.+.D...q.rN.%|
000000d0  19 c3 01 77 f0 d7 49 07  e3 2f bb ae 34 45 33 25  |...w..I../..4E3%|
000000e0  fc 4d c8 ab 23 93 f6 7e  36 d7 1e 42 31 08 d2 e4  |.M..#..~6..B1...|
000000f0  d5 bd 4b d3 57 b5 d6 7e  00 26 b5 12 2a 2e da 23  |..K.W..~.&..*..#|
00000100  a0 8b 6e f5 66 d1 39 b3  09 11 52 50 a4 f4 38 1c  |..n.f.9...RP..8.|
00000110  89 00 ad 93 58 9d 7d 15  b2 22 eb ed e2 62 86 f4  |....X.}.."...b..|
00000120  d0 6a f6 da c6 85 48 da  b5 eb 69 48 17 d8 1f 05  |.j....H...iH....|
00000130  63 1c 2f f5 13 8f 02 18  b0 58 88 d4 ad 37 94 44  |c./......X...7.D|
00000140  b9 c4 d0 29 58 c8 a2 1e  38 e4 13 61 89 bc a8 00  |...)X...8..a....|
00000150  3d 2a 3a 16 f3 f3 42 e0  89 87 29 c7 76 ca 30 19  |=*:...B...).v.0.|
00000160  7b 3a 50 21 02 60 ec db  4c 5a 26 1c 2b 7b dc ae  |{:P!.`..LZ&.+{..|
00000170  84 76 70 1c 24 13 8a 7c  18 3e 13 53 57 ee f7 b6  |.vp.$..|.>.SW...|
00000180  f4 f9 19 28 42 43 d3 79  50 ac 32 2c 17 34 30 2f  |...(BC.yP.2,.40/|
00000190  16 b8 0f 54 78 fe 9a fe  08 0b da 9c 71 a2 94 89  |...Tx.......q...|
000001a0  c7 15 4d 85 98 75 0a e0  0a f8 9d 5b 78 93 c7 b8  |..M..u.....[x...|
000001b0  b0 01 12 7e c8 24 cb 10  4d af 7a 96 2a 83 17 11  |...~.$..M.z.*...|
000001c0  87 e3 fa 2d ca 13 8e f7  90 85 4e 87 04 6b 8d fe  |...-......N..k..|
000001d0  a9 9e b0 b0 27 80 70 0f  7f 97 ee 54 fa 07 13 fb  |....'.p....T....|
000001e0  2e 43 70 11 b9 c4 51 21  b0 e9 96 1c 8e da 27 db  |.Cp...Q!......'.|
000001f0  6e 00 42 4a 08 1c 9d 67  ba b4 70 ad d9 5f 62 ce  |n.BJ...g..p.._b.|
00000200
root@debian:/tmp# dd if=./todecrypt.luks of=./dummy.luks bs=512 seek=4096 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 5.2223e-05 s, 9.8 MB/s
root@debian:/tmp# hexdump -C /dev/mapper/dummy.deluks
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200
root@debian:/tmp#

That is correct, first 512 bytes of /dev/vda5 device -> are empty (00 in HEX).

One-liner commands would look as follows

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096 )) status=noxfer of=./dummy.luks seek=4096 2>/dev/null && losetup -c /dev/loop1 && cryptsetup resize dummy.deluks && hexdump -C /dev/mapper/dummy.deluks  |less

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632 )) status=noxfer 2>/dev/null |dd bs=512 count=1 status=noxfer seek=4096 of=./dummy.luks 2>/dev/null && losetup -c /dev/loop1 && cryptsetup resize dummy.deluks && hexdump -C /dev/mapper/dummy.deluks  |less

Findings

After many attempts trying to get the desired output (contents of test.txt file), I have found that the encryption/decryption is depending on the sector number where encrypted block is located.

Basically this is because encryption alogrithm AES is “supplied” by XTS block cipher mode.

You can learn more at the Block cipher-based modes wiki page.

Truncate dummy LUKS file (Remove everything after LUKS part that ends at 2MB point keep)

root@debian:/tmp# dd if=/dev/zero of=./dummy.luks bs=512 count=0 seek=4096 oflag=append

Add one block (512 bytes) to a dummy LUKS file so that it will be possible to luksOpen it

root@debian:/tmp# dd if=/dev/zero of=./dummy.luks bs=512 seek=4096 count=1
root@debian:/tmp# cryptsetup luksOpen /dev/loop1 dummy.deluks

Reading 512 block of encrypted test.txt and writing this block to LUKS dummy container, also keeping the same sector offset when writing.

root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632 + (8451*1024)/512 )) status=noxfer 2>/dev/null |dd bs=512 count=1 status=noxfer seek=$((4096+10053632 + (8451*1024)/512 )) of=./dummy.luks 2>/dev/null && losetup -c /dev/loop1 && cryptsetup resize dummy.deluks && dd bs=512 count=1 skip=$((10053632 + (8451*1024)/512)) if=/dev/mapper/dummy.deluks status=noxfer 2>/dev/null |hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 33  |1111111111111113|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

root@debian:/tmp# ls -la dummy.luks
-rw-r--r-- 1 root root 5158211584 Nov  2 07:55 dummy.luks
root@debian:/tmp# ls -lah dummy.luks
-rw-r--r-- 1 root root 4.9G Nov  2 07:55 dummy.luks

Voila! This proves that sector (which is 512bytes block) decryption was depending on the sector number that was kept in ‘seek=’ parameter to dd write command (of=./dummy.luks).

Below is one more confirmation that we have the only 1 encrypted block at the location 0x133740c00 = 5158210560 (decimal) relative to the beginning of the disk (/dev/vda). 512* (4096+10053632 + (8451*1024)/512) = 5158210560 bytes.

root@debian:/tmp# hexdump -C -s $((4096*512)) dummy.luks
00200000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
133740c00  38 59 ca b4 86 b3 aa 99  27 5f 5c 3b c0 6c 4c 3d  |8Y......'_\;.lL=|
133740c10  85 a1 cf d4 99 b2 ec cc  35 db 8c c9 94 db 28 14  |........5.....(.|
133740c20  a1 46 a0 40 85 42 82 82  27 b1 99 89 25 b7 a1 c4  |.F.@.B..'...%...|
133740c30  55 57 de 53 47 5d a8 d8  fe 2f 37 7a 4b 8c 7f 41  |UW.SG].../7zK..A|
133740c40  b7 f9 ad 62 c8 49 0f 52  3b cd 7e 6a 39 89 ee 6a  |...b.I.R;.~j9..j|
133740c50  98 d9 23 f0 cf 3b ce 79  4c 11 87 62 33 0e 96 29  |..#..;.yL..b3..)|
133740c60  7a 6f c2 25 50 eb 8f b8  b3 de 90 ba 97 b6 da b5  |zo.%P...........|
133740c70  91 a4 c5 cc ab d0 c9 0a  2d 1f 2d 88 a0 28 8c 32  |........-.-..(.2|
133740c80  15 f7 58 f0 aa cd 7f 50  01 55 23 f2 18 2f 90 6d  |..X....P.U#../.m|
133740c90  7c 03 7f a0 32 68 66 1c  48 cd ce 5c 07 9b f7 71  ||...2hf.H..\...q|
133740ca0  80 fa 08 a8 2f 71 45 3d  c0 f8 67 39 b4 96 10 ce  |..../qE=..g9....|
133740cb0  72 60 a0 bd ae 37 b1 32  10 b1 7a 1c 76 53 f6 3f  |r`...7.2..z.vS.?|
133740cc0  66 eb f8 96 3c 32 1e 18  4b a2 77 7e be 0d 8d bb  |f...<2..K.w~....|
133740cd0  a5 99 97 54 6d 9e dc 4d  1d c2 0d ba 78 db ff ed  |...Tm..M....x...|
133740ce0  44 8f 61 31 84 24 68 ab  db 6a e7 9d 0a 44 a5 90  |D.a1.$h..j...D..|
133740cf0  c1 f8 28 bc e3 4c ac 5c  1f bd 7e a4 90 57 89 3a  |..(..L.\..~..W.:|
133740d00  bb 90 3d c0 4b 7d a0 94  f5 1b 0a 12 c0 9e d9 d9  |..=.K}..........|
133740d10  f8 25 a7 0f 6b ca 73 57  90 e4 96 bd 26 b4 a4 ad  |.%..k.sW....&...|
133740d20  28 7a 7c 69 d3 5a 8b a7  b4 f5 bf b8 a2 81 11 3d  |(z|i.Z.........=|
133740d30  8a d0 c6 a5 3f 12 0e 6e  37 2d 30 c7 c0 c9 f9 70  |....?..n7-0....p|
133740d40  7f 13 45 ad 41 17 c4 96  8a 78 a5 4a da 61 3a fc  |..E.A....x.J.a:.|
133740d50  75 96 5c 39 d3 46 3f cb  10 2b 1c a5 84 3a 61 d1  |u.\9.F?..+...:a.|
133740d60  44 37 67 4a a0 b4 44 70  b4 1a 86 45 4f be 1f 1b  |D7gJ..Dp...EO...|
133740d70  4a 20 70 a8 40 3e 69 a0  a9 50 89 7e 70 f4 ab 73  |J p.@>i..P.~p..s|
133740d80  c7 b9 85 7b 3a 37 cd 0d  8a fc ad fc b4 13 c6 27  |...{:7.........'|
133740d90  41 64 f0 a9 95 89 10 c5  8c f0 5b 9b 44 b6 af ab  |Ad........[.D...|
133740da0  ec 9a 20 3f b9 ce c1 f0  18 e4 1c 36 d6 8d b5 d8  |.. ?.......6....|
133740db0  5c 42 21 b0 57 e7 a8 76  85 a9 ff f2 39 f8 d4 39  |\B!.W..v....9..9|
133740dc0  ee 6a 4d db ad d6 ab ab  f8 d6 3e 92 38 cf c9 58  |.jM.......>.8..X|
133740dd0  54 be 74 af 40 c0 9d 4d  98 75 b1 9e 20 6d 28 6b  |T.t.@..M.u.. m(k|
133740de0  ec 71 5a ff 39 3a cb dd  37 7f aa 73 c9 13 d4 9e  |.qZ.9:..7..s....|
133740df0  d1 8a 1f cc c0 a3 d6 a7  41 f8 ae 3e a4 8e 46 88  |........A..>..F.|
133740e00  28 4b 6d 2a df ea ca 76  0c f2 45 25 c6 90 6b 06  |(Km*...v..E%..k.|
133740e10  9a e8 f3 95 d7 2c 3e 78  08 c1 0a 7c 92 9a 40 b2  |.....,>x...|..@.|
133740e20  d7 a7 c4 f9 8c aa 31 81  23 a7 e4 df f7 23 96 fd  |......1.#....#..|
133740e30  3c ae 2a de c8 c9 9c 39  75 16 65 a9 52 6e 50 00  |<.*....9u.e.RnP.|
133740e40  8a 7a f9 df a5 85 29 be  18 7a b9 3f 97 85 0a c3  |.z....)..z.?....|
133740e50  ca 2c 2e d6 4c 5f 03 2a  91 0f ee 5b 08 f4 bc 00  |.,..L_.*...[....|
133740e60  96 66 5e 80 eb ea a3 69  c2 16 03 61 24 5d ae d5  |.f^....i...a$]..|
133740e70  e3 bc 6a 8e 92 9b c6 82  06 2f 6b aa f6 87 00 08  |..j....../k.....|
133740e80  8d 0c f4 4f a7 ec 19 e3  5b b4 4b 31 84 8e a9 6f  |...O....[.K1...o|
133740e90  7d 37 bc c9 26 3d 39 b5  5c 7f 43 aa ca 54 d3 5a  |}7..&=9.\.C..T.Z|
133740ea0  9a d3 10 0c 4b cc bb 68  ff 86 86 cc a7 18 fc 37  |....K..h.......7|
133740eb0  c4 67 0e 98 4d 93 3e 1c  92 8b 22 11 fd be 5b 0b  |.g..M.>..."...[.|
133740ec0  9b 2f 81 0a d0 db 83 3e  55 23 d8 03 a0 21 c1 c2  |./.....>U#...!..|
133740ed0  f0 6f a4 ef c5 55 63 37  f2 4c 4c 03 54 5c e6 8b  |.o...Uc7.LL.T\..|
133740ee0  d1 9b 59 9e 76 38 cd 93  5a 31 3f a5 d6 4d cc d2  |..Y.v8..Z1?..M..|
133740ef0  a8 09 88 ad 49 ce 2f 13  07 42 86 b1 07 5f 9c 33  |....I./..B..._.3|
133740f00  24 7b a9 cb 1c 68 d5 4a  8f 91 aa 9f c1 f1 3a cf  |${...h.J......:.|
133740f10  d7 0a 5e 2b a7 63 35 76  d9 3a 5f 95 72 bf 54 7b  |..^+.c5v.:_.r.T{|
133740f20  f4 e4 d0 e3 02 40 95 e8  f5 28 13 ab 91 d9 6a 10  |.....@...(....j.|
133740f30  2d 45 ba 3f d3 d1 a4 d5  cf 80 e0 7f 05 81 62 c7  |-E.?..........b.|
133740f40  7c 0d f9 3a 16 0e d6 02  0c 53 15 0e ab 2b 5f 9c  ||..:.....S...+_.|
133740f50  56 0c 50 ec d1 d4 1f 4f  62 48 bb 2d 72 af b2 ca  |V.P....ObH.-r...|
133740f60  8d 80 3e d6 4e 81 12 d3  04 63 cb 95 4a 29 0d 6b  |..>.N....c..J).k|
133740f70  65 b3 73 eb 59 ae 96 c7  72 0b 4d 1a b2 ac e2 0f  |e.s.Y...r.M.....|
133740f80  be 8d c4 16 c6 1c 03 f9  cd 3c 6c 96 03 56 ef e1  |.........<l..V..|
133740f90  75 90 89 c7 a2 1f 43 dc  0a e2 a0 0a fb 1c f1 05  |u.....C.........|
133740fa0  e5 0e a8 71 42 de 11 6e  a5 60 26 57 10 04 b9 7c  |...qB..n.`&W...;||
133740fb0  79 bf fd 5f 5e c8 e4 cb  09 16 6b 8d 30 67 0c 0f  |y.._^.....k.0g..|
133740fc0  fb 53 a5 b2 ec 6c b1 c2  cd 25 37 1f 12 a6 a3 b2  |.S...l...%7.....|
133740fd0  98 af 1d 03 5c a0 b2 2d  f9 fc e3 8b 51 0b 16 a8  |....\..-....Q...|
133740fe0  65 1a c5 97 9f df 82 e2  2c bf 0f ba 6b 03 b9 af  |e.......,...k...|
133740ff0  42 99 3f b0 11 62 19 0c  57 df d0 a8 a8 65 71 46  |B.?..b..W....eqF|
133741000

Extra test, trying to alter the test.txt file by adding a number “4” to the end of it.

root@debian:/tmp# printf 4 |dd of=./test.txt count=1 bs=1 seek=15 status=noxfer
1+0 records in
1+0 records out
root@debian:/tmp# filefrag -bsv ./test.txt
Filesystem type is: ef53
File size of ./test.txt is 16 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0     8451               1 eof
./test.txt: 1 extent found
root@debian:/tmp# hexdump -C ./test.txt
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 34  |1111111111111114|
00000010
root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632 + (8451*1024)/512 )) status=noxfer 2>/dev/null |dd bs=512 count=1 status=noxfer seek=$((4096+10053632 + (8451*1024)/512 )) of=./dummy.luks 2>/dev/null && losetup -c /dev/loop1 && cryptsetup resize dummy.deluks && dd bs=512 count=1 skip=$((10053632 + (8451*1024)/512)) if=/dev/mapper/dummy.deluks status=noxfer 2>/dev/null |hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 33  |1111111111111113|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200
root@debian:/tmp# sync && mount -o remount /tmp && echo 1 | tee /proc/sys/vm/drop_caches1
root@debian:/tmp# dd if=/dev/vda bs=512 count=1 skip=$(( 501760+4096+10053632 + (8451*1024)/512 )) status=noxfer 2>/dev/null |dd bs=512 count=1 status=noxfer seek=$((4096+10053632 + (8451*1024)/512 )) of=./dummy.luks 2>/dev/null && losetup -c /dev/loop1 && cryptsetup resize dummy.deluks && dd bs=512 count=1 skip=$((10053632 + (8451*1024)/512)) if=/dev/mapper/dummy.deluks status=noxfer 2>/dev/null |hexdump -C
00000000  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 34  |1111111111111114|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

In the end of tests do not forget to dismount encrypted LUKS dummy device and sanitize the master key if it is important for you.

root@debian:/tmp# cryptsetup luksClose dummy.deluks
root@debian:/tmp# losetup -d /dev/loop1
root@debian:/tmp# shred -uvz master.key
root@debian:/tmp# rm ./dummy.luks ./todecrypt.luks