The cipher-name
in your example is not '@
'. The field you're looking at is actually the hdr_size
field.
The mistake you've made is trying to decode a LUKS2 container with LUKS1 encoding. In the table provided, you've shown that the second field (bytes 6-8) are the version
data field. And your hexdump clearly shows that the first LUKS container (luksVol1
) has version
= 00 01
while the second LUKS container (luksVol2
) has version
= 00 02
. These hex values directly correlate the former to LUKS1 and the latter LUKS2.
Quoting from OP that demonstrates this:
root@disp8551:~# hexdump -Cs 6 -n 2 luksVol1
00000006 00 01 |..|
00000008
...
root@disp85:~# hexdump -Cs 6 -n 2 luksVol2
00000006 00 02 |..|
00000008
Your encoding table in the OP was correct only for LUKS1 as defined in the LUKS On-Disk Format Specification published by Clemens Fruhwirth in 2005.
LUKS2 uses a different encoding that's defined in the LUKS2 On-Disk Format Specification published by Milan Brož in 2018. Here's the updated encoding table for LUKS2. Note that binary headers in LUKS2 must be exactly 4096 bytes long.
+-------+--------+--------------+
| Start | Length | Field Name |
+-------+--------+--------------+
| 0 | 6 | magic |
| 6 | 2 | version |
| 8 | 8 | hdr_size |
| 16 | 8 | seqid |
| 24 | 48 | label |
| 72 | 32 | csum_alg |
| 104 | 64 | salt |
| 168 | 40 | uuid |
| 208 | 48 | subsystem |
| 256 | 8 | hdr_offset |
| 264 | 184 | _padding |
| 448 | 64 | csum |
| 512 | 3584 | _padding4096 |
+-------+--------+--------------+
And here's the relevant hexdumps for the data fields shown above on an example LUKS2 container's primary header.
# magic
root@disp4117:~# hexdump -Cs 0 -n 6 luksVol2
00000000 4c 55 4b 53 ba be |LUKS..|
00000006
# version
root@disp4117:~# hexdump -Cs 6 -n 2 luksVol2
00000006 00 02 |..|
00000008
# hdr_size
root@disp4117:~# hexdump -Cs 8 -n 8 luksVol2
00000008 00 00 00 00 00 00 40 00 |......@.|
00000010
# seqid
root@disp4117:~# hexdump -Cs 16 -n 8 luksVol2
00000010 00 00 00 00 00 00 00 03 |........|
00000018
# label
root@disp4117:~# hexdump -Cs 24 -n 48 luksVol2
00000018 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000048
# csum_alg
root@disp4117:~# hexdump -Cs 72 -n 31 luksVol2
00000048 73 68 61 32 35 36 00 00 00 00 00 00 00 00 00 00 |sha256..........|
00000058 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |...............|
00000067
# salt
root@disp4117:~# hexdump -Cs 104 -n 64 luksVol2
00000068 4f b1 7c b2 bf 7d da 1f 15 64 df cc ab 74 68 5c |O.|..}...d...th\|
00000078 9a f9 3d 02 42 67 0f 92 ee 1d bf 98 11 5b 3d b8 |..=.Bg.......[=.|
00000088 87 e4 e0 a8 76 23 68 86 2f fc e1 98 a7 a1 5a a9 |....v#h./.....Z.|
00000098 b6 c5 e5 e2 9a 87 f7 ff 55 52 dc 07 07 dd fa a4 |........UR......|
000000a8
# uuid
root@disp4117:~# hexdump -Cs 168 -n 40 luksVol2
000000a8 65 63 30 32 36 64 64 66 2d 37 37 36 32 2d 34 34 |ec026ddf-7762-44|
000000b8 64 63 2d 39 65 37 30 2d 62 35 36 66 36 61 65 62 |dc-9e70-b56f6aeb|
000000c8 63 31 32 38 00 00 00 00 |c128....|
000000d0
# subsystem
root@disp4117:~# hexdump -Cs 208 -n 48 luksVol2
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000100
# hdr_offset
root@disp4117:~# hexdump -Cs 256 -n 8 luksVol2
00000100 00 00 00 00 00 00 00 00 |........|
00000108
# _padding
root@disp4117:~# hexdump -Cs 264 -n 184 luksVol2
00000108 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
# csum
000001c0
root@disp4117:~# hexdump -Cs 448 -n 64 luksVol2
000001c0 d0 9a e0 f8 96 ed 8f db 42 5f 58 19 99 2a 72 18 |........B_X..*r.|
000001d0 01 5e f7 81 34 99 f7 c5 17 a2 07 2f 60 be 40 bd |.^..4....../`.@.|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
# _padding4096
root@disp4117:~# hexdump -Cs 512 -n 3584 luksVol2
00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
root@disp4117:~#
Note that none of the above fields actually contain the cipher-name
. In LUKS2, that's stored in the JSON object. In LUKS2, there's actually six header areas:
\/ primary binary header alignment padding \/
+----+----------+----+----------+-------------------+----+
| /\ | 1st JSON | \/ | 2nd JSON | Keyslots area | /\ |
+----+----------+----+----------+-------------------+----+
/\ secondary binary header
The hexdump
shown above only shows the "primary binary header" area. To get the cipher-name
, we must look at the JSON area.
In LUKS2, there's actually two copies of the data stored in the "primary binary header" and the "1st JSON" area (the second copy is called the "secondary binary header" and "2nd JSON" area, respectfully). In most cases the data in the "primary binary header" exactly matches the "secondary binary header" and the data in the "1st JSON" area exactly matches the "2nd JSON" area. The data is stored twice to aid in recovery and protect against corruption.
While the "1st JSON" area always starts at byte 4096 (immediately after the "primary binary header" area), its length is variable. The length can be determined by looking at the binary header's hdr_size
(ie the same field that you confused for the cipher-name
). From the above hex dump, we clearly see the hdr_size
field has a value of 0x4000
(hex) = 16384
(decimal). But the hdr_size
field defines the size of the the "primary binary header" plus the "1st JSON" area. So the length of the "1st JSON" area is the hdr_size
value minus the "primary binary header" length. In this case, that's 16384 - 4096
= 122881
. Depending on the length of the LUKS2 container's metadata stored in the JSON object, the JSON area could be up to 4194304 - 4096
= 4190208
bytes long.
So here's a hexdump
of the "1st JSON" area, starting at byte offset 4096
with length 122881
:
root@disp4117:~# hexdump -Cs 4096 -n 12288 luksVol2
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",|
000010e0 22 74 69 6d 65 22 3a 34 2c 22 6d 65 6d 6f 72 79 |"time":4,"memory|
000010f0 22 3a 32 37 34 35 33 30 2c 22 63 70 75 73 22 3a |":274530,"cpus":|
00001100 32 2c 22 73 61 6c 74 22 3a 22 71 4a 6e 79 2b 4a |2,"salt":"qJny+J|
00001110 5c 2f 6f 35 71 77 57 77 35 78 2b 57 31 30 7a 47 |\/o5qwWw5x+W10zG|
00001120 59 54 6f 64 44 64 57 6f 39 6e 74 5c 2f 6c 67 49 |YTodDdWo9nt\/lgI|
00001130 41 61 61 6f 78 5c 2f 45 3d 22 7d 7d 7d 2c 22 74 |Aaaox\/E="}}},"t|
00001140 6f 6b 65 6e 73 22 3a 7b 7d 2c 22 73 65 67 6d 65 |okens":{},"segme|
00001150 6e 74 73 22 3a 7b 22 30 22 3a 7b 22 74 79 70 65 |nts":{"0":{"type|
00001160 22 3a 22 63 72 79 70 74 22 2c 22 6f 66 66 73 65 |":"crypt","offse|
00001170 74 22 3a 22 31 36 37 37 37 32 31 36 22 2c 22 69 |t":"16777216","i|
00001180 76 5f 74 77 65 61 6b 22 3a 22 30 22 2c 22 73 69 |v_tweak":"0","si|
00001190 7a 65 22 3a 22 64 79 6e 61 6d 69 63 22 2c 22 65 |ze":"dynamic","e|
000011a0 6e 63 72 79 70 74 69 6f 6e 22 3a 22 61 65 73 2d |ncryption":"aes-|
000011b0 78 74 73 2d 70 6c 61 69 6e 36 34 22 2c 22 73 65 |xts-plain64","se|
000011c0 63 74 6f 72 5f 73 69 7a 65 22 3a 35 31 32 7d 7d |ctor_size":512}}|
000011d0 2c 22 64 69 67 65 73 74 73 22 3a 7b 22 30 22 3a |,"digests":{"0":|
000011e0 7b 22 74 79 70 65 22 3a 22 70 62 6b 64 66 32 22 |{"type":"pbkdf2"|
000011f0 2c 22 6b 65 79 73 6c 6f 74 73 22 3a 5b 22 30 22 |,"keyslots":["0"|
00001200 5d 2c 22 73 65 67 6d 65 6e 74 73 22 3a 5b 22 30 |],"segments":["0|
00001210 22 5d 2c 22 68 61 73 68 22 3a 22 73 68 61 32 35 |"],"hash":"sha25|
00001220 36 22 2c 22 69 74 65 72 61 74 69 6f 6e 73 22 3a |6","iterations":|
00001230 36 31 39 34 33 2c 22 73 61 6c 74 22 3a 22 46 69 |61943,"salt":"Fi|
00001240 4c 67 31 35 56 5c 2f 55 56 4b 47 72 72 4e 39 4f |Lg15V\/UVKGrrN9O|
00001250 52 2b 5c 2f 69 59 46 51 70 38 38 59 44 77 50 4c |R+\/iYFQp88YDwPL|
00001260 6a 4f 6f 4c 70 6a 77 6d 78 58 77 3d 22 2c 22 64 |jOoLpjwmxXw=","d|
00001270 69 67 65 73 74 22 3a 22 49 70 34 31 5a 58 70 44 |igest":"Ip41ZXpD|
00001280 76 77 52 76 6d 41 73 33 30 58 69 72 6c 48 65 6d |vwRvmAs30XirlHem|
00001290 57 72 44 67 6c 5c 2f 44 4a 31 36 79 33 31 41 71 |WrDgl\/DJ16y31Aq|
000012a0 66 42 55 6f 3d 22 7d 7d 2c 22 63 6f 6e 66 69 67 |fBUo="}},"config|
000012b0 22 3a 7b 22 6a 73 6f 6e 5f 73 69 7a 65 22 3a 22 |":{"json_size":"|
000012c0 31 32 32 38 38 22 2c 22 6b 65 79 73 6c 6f 74 73 |12288","keyslots|
000012d0 5f 73 69 7a 65 22 3a 22 31 36 37 34 34 34 34 38 |_size":"16744448|
000012e0 22 7d 7d 00 00 00 00 00 00 00 00 00 00 00 00 00 |"}}.............|
000012f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00004000
root@disp4117:~#
To get the cipher-name
specific for encrypting the data in the LUKS container (as opposed to the cipher used to symmetrically encrypt the a given keyslot), we need to check the segments
object in the above JSON. Here's the same segments
section from above, but formatted for readability:
"segments": {
"0": {
"type": "crypt",
"offset": "16777216",
"iv_tweak": "0",
"size": "dynamic",
"encryption": "aes-xts-plain64",
"sector_size": 512
}
},
LUKS supports many distinct segments, but this LUKS container only has one. The attribute we want is encryption
, which has a value in the dm-crypt
notation. In this case, it's aes-xts-plain64
-- which means the cipher-name
is aes
and the cipher-mode
is xts-plain64
.
This also matches the cipher listed in a cryptsetup luksDump
on the LUKS2 container
root@disp4117:~# cryptsetup luksDump luksVol2 | grep -i cipher | head -n1
cipher: aes-xts-plain64
root@disp4117:~#