1

Why is the metadata in my LUKS header listed twice?

I started poking at the bits in a drive that's encrypted with LUKS, and I found some metadata in a JSON object. What's odd though is that the same JSON object actually appears twice. Here's a snippet of a hexdump that shows what I mean

root@disp85:~# hexdump -Cn 99999 luksVol2
00000000  4c 55 4b 53 ba be 00 02  00 00 00 00 00 00 40 00  |LUKS..........@.|
00000010  00 00 00 00 00 00 00 03  00 00 00 00 00 00 00 00  |................|
...
00001000  7b 22 6b 65 79 73 6c 6f  74 73 22 3a 7b 22 30 22  |{"keyslots":{"0"|
00001010  3a 7b 22 74 79 70 65 22  3a 22 6c 75 6b 73 32 22  |:{"type":"luks2"|
00001020  2c 22 6b 65 79 5f 73 69  7a 65 22 3a 36 34 2c 22  |,"key_size":64,"|
00001030  61 66 22 3a 7b 22 74 79  70 65 22 3a 22 6c 75 6b  |af":{"type":"luk|
00001040  73 31 22 2c 22 73 74 72  69 70 65 73 22 3a 34 30  |s1","stripes":40|
00001050  30 30 2c 22 68 61 73 68  22 3a 22 73 68 61 32 35  |00,"hash":"sha25|
00001060  36 22 7d 2c 22 61 72 65  61 22 3a 7b 22 74 79 70  |6"},"area":{"typ|
00001070  65 22 3a 22 72 61 77 22  2c 22 6f 66 66 73 65 74  |e":"raw","offset|
00001080  22 3a 22 33 32 37 36 38  22 2c 22 73 69 7a 65 22  |":"32768","size"|
00001090  3a 22 32 35 38 30 34 38  22 2c 22 65 6e 63 72 79  |:"258048","encry|
000010a0  70 74 69 6f 6e 22 3a 22  61 65 73 2d 78 74 73 2d  |ption":"aes-xts-|
000010b0  70 6c 61 69 6e 36 34 22  2c 22 6b 65 79 5f 73 69  |plain64","key_si|
000010c0  7a 65 22 3a 36 34 7d 2c  22 6b 64 66 22 3a 7b 22  |ze":64},"kdf":{"|
000010d0  74 79 70 65 22 3a 22 61  72 67 6f 6e 32 69 22 2c  |type":"argon2i",|
...
000012e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00004000  53 4b 55 4c ba be 00 02  00 00 00 00 00 00 40 00  |SKUL..........@.|
00004010  00 00 00 00 00 00 00 03  00 00 00 00 00 00 00 00  |................|
...
000041e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00005000  7b 22 6b 65 79 73 6c 6f  74 73 22 3a 7b 22 30 22  |{"keyslots":{"0"|
00005010  3a 7b 22 74 79 70 65 22  3a 22 6c 75 6b 73 32 22  |:{"type":"luks2"|
00005020  2c 22 6b 65 79 5f 73 69  7a 65 22 3a 36 34 2c 22  |,"key_size":64,"|
00005030  61 66 22 3a 7b 22 74 79  70 65 22 3a 22 6c 75 6b  |af":{"type":"luk|
00005040  73 31 22 2c 22 73 74 72  69 70 65 73 22 3a 34 30  |s1","stripes":40|
00005050  30 30 2c 22 68 61 73 68  22 3a 22 73 68 61 32 35  |00,"hash":"sha25|
00005060  36 22 7d 2c 22 61 72 65  61 22 3a 7b 22 74 79 70  |6"},"area":{"typ|
00005070  65 22 3a 22 72 61 77 22  2c 22 6f 66 66 73 65 74  |e":"raw","offset|
00005080  22 3a 22 33 32 37 36 38  22 2c 22 73 69 7a 65 22  |":"32768","size"|
00005090  3a 22 32 35 38 30 34 38  22 2c 22 65 6e 63 72 79  |:"258048","encry|
000050a0  70 74 69 6f 6e 22 3a 22  61 65 73 2d 78 74 73 2d  |ption":"aes-xts-|
000050b0  70 6c 61 69 6e 36 34 22  2c 22 6b 65 79 5f 73 69  |plain64","key_si|
000050c0  7a 65 22 3a 36 34 7d 2c  22 6b 64 66 22 3a 7b 22  |ze":64},"kdf":{"|
000050d0  74 79 70 65 22 3a 22 61  72 67 6f 6e 32 69 22 2c  |type":"argon2i",|
...
root@disp85:~# 

Why are there two JSON objects here? Which one is the right one that's actually used by cryptsetup?

1

There are two copies of the header data, not just the JSON but also the preceding binary header. This is very common in storage formats. The reason is resilience against failures while writing the header data, for example a power loss. If updating one of the copies of the header fails, the other copy is still valid. When the driver mounts the volume, it reads both copies, and picks the most recent one if both are valid.

In the case of LUKS2, see the LUKS2 on-disk format specification for details. In §2 “LUKS2 On-Disk Format”:

The binary and JSON areas are stored twice on the device (primary and secondary header) and under normal circumstances contain same functional metadata.

See §4.5 “Metadata Recovery” for what a LUKS2 driver does when mounting a volume where the headers have different content. The format specification doesn't mandate a particular procedure to update the header, so while a header update is in progress, either the first copy or the second copy may be the most recent one. The most recent copy (assuming both are in a valid state) is the one whose seqid field is larger. The seqid field is at byte offsets 16..23 in the binary header (see §2.1 ”Binary Header“). In the example you posted, the two copies are identical (as expected in normal operation), both at seqid=3.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.