mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-11 19:00:02 +01:00
280 lines
9.6 KiB
Plaintext
280 lines
9.6 KiB
Plaintext
LUKS2 on-disk format
|
|
====================
|
|
|
|
Note: these are temporary documentation notes only.
|
|
The more formal definition will be published later.
|
|
|
|
Design goals
|
|
~~~~~~~~~~~~
|
|
The LUKS2 is an on-disk storage format designed to
|
|
provide simple key management, primarily intended for Full Disk
|
|
Encryption based on dm-crypt.
|
|
|
|
The LUKS2 is highly inspired by LUKS1 format and in some
|
|
specific situations (most of the default installations) can be converted
|
|
in-place (in both ways - to and from LUKS1).
|
|
|
|
The LUKS2 format is designed to allow future updates of various
|
|
parts without the need to modify binary structures.
|
|
|
|
On-disk format provides redundancy of metadata, detection
|
|
of metadata corruption and automatic repair from metadata copy.
|
|
|
|
NOTE: For security reasons, there is no redundancy in keyslots
|
|
binary data (encrypted keys) but format allows updating to redundant
|
|
keyslot encryption in future (add forward error correction codes
|
|
is one possibility).
|
|
|
|
On-disk structure
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
The LUKS2 header contains three parts:
|
|
- binary header (one 4096 bytes sector)
|
|
- area for metadata stored in JSON format
|
|
- keyslot area (per-context binary data).
|
|
|
|
The binary header and JSON area are stored twice to increase
|
|
redundancy. Keyslot area is allocated per-demand, and it is stored only once.
|
|
|
|
The basic on-disk structure is then
|
|
|
|
0 4096
|
|
| bin hdr1 | JSON ... | bin hdr2 | JSON ... | Keyslot data | <padding> | (data payload)
|
|
|
|
Binary header
|
|
~~~~~~~~~~~~~
|
|
|
|
The binary header is intended for quick scanning (by blkid and udev) and contains
|
|
magic string to detect the device, basic information (labels), header size information
|
|
and metadata checksum.
|
|
Checksum covers both binary data and following JSON area and is calculated
|
|
with checksum fields zeroed. By default plain SHA256 checksum is used.
|
|
|
|
The primary binary header is always stored in sector 0 of the device.
|
|
|
|
The C structure of binary header (see luks2.h) is
|
|
|
|
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
|
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
|
#define LUKS2_MAGIC_L 6
|
|
#define LUKS2_UUID_L 40
|
|
#define LUKS2_LABEL_L 48
|
|
#define LUKS2_SALT_L 64
|
|
#define LUKS2_CHECKSUM_ALG_L 32
|
|
#define LUKS2_CHECKSUM_L 64
|
|
|
|
struct luks2_hdr_disk {
|
|
char magic[LUKS2_MAGIC_L]; /* "LUKS\xba\xbe" (1st) or "SKUL\xba\be" (2nd) */
|
|
uint16_t version; /* Version 2 */
|
|
uint64_t hdr_size; /* in bytes, including JSON area */
|
|
uint64_t seqid; /* sequence ID, increased on every update */
|
|
char label[LUKS2_LABEL_L]; /* ASCII label or empty */
|
|
char checksum_alg[LUKS2_CHECKSUM_ALG_L]; /* checksum algorithm, "sha256" */
|
|
uint8_t salt[LUKS2_SALT_L]; /* random salt, unique for every header */
|
|
char uuid[LUKS2_UUID_L]; /* UUID of device */
|
|
char subsystem[LUKS2_LABEL_L]; /* owner subsystem label or empty */
|
|
uint64_t hdr_offset; /* header offset from device start in bytes */
|
|
char _padding[184]; /* must be zeroed */
|
|
uint8_t csum[LUKS2_CHECKSUM_L]; /* header checksum */
|
|
char _padding4096[7*512]; /* must be zeroed */
|
|
} __attribute__ ((packed));
|
|
|
|
The LUKS1 compatible field (magic, UUID) are placed intentionally on the same offsets.
|
|
The header version must be set to 2.
|
|
The UUID is the same format as in LUKS1.
|
|
|
|
Magic string differs between the first and second header.
|
|
|
|
The hdr_offset must match physical header offset on the device.
|
|
If hdr_offset does not match, the header is misplaced and must not be used.
|
|
(It is a prevention to partition resize or manipulation with device start offset.)
|
|
|
|
The hdr_size contains the size of the binary header and JSON data area.
|
|
The offset and size of the second (backup) header must match to these data.
|
|
(Prevention to rewrite of a header with different JSON area size.)
|
|
|
|
There are two labels - label and subsystem. Content of these fields will be visible
|
|
in UDEV/blkid scan and can be used for similar purposes as a filesystem label.
|
|
These fields are by default empty.
|
|
|
|
The salt field in binary header is generated by an RNG and is different for
|
|
every header, even the backup header must contain a different salt.
|
|
The salt in binary header is not used after the header is read, the main intention
|
|
is to avoid deduplication of the header sector.
|
|
The salt must be regenerated on every header repair (but not on regular update).
|
|
|
|
The sequential number (seqid) is a counter that is always increased when a new
|
|
update of the header is written. The header with higher seqid is more recent and
|
|
is used for recovery (if there are two headers with different seqid, the
|
|
more recent one is automatically used).
|
|
|
|
The rest of binary header must be zeroed.
|
|
|
|
JSON area
|
|
~~~~~~~~~
|
|
The JSON area starts immediately after the binary header. Its size is set
|
|
by binary header hdr_size field (JSON area size = hdr_size - 4096).
|
|
|
|
The area contains metadata in JSON format and is fixed. Unused remainder
|
|
of the area must be empty.
|
|
|
|
The header cannot store larger metadata that this fixed buffer and header
|
|
size must be set properly during format. For now, only areas with 14 kB
|
|
header (4kB binary header + 14kB JSON area) is created during format.
|
|
|
|
The JSON is structured to be able to describe system in very generic way,
|
|
but LUKS2 intentionally limits options to values that are supportable
|
|
in implemented version.
|
|
|
|
JSON structure is as follows:
|
|
|
|
Mandatory sections (must be present but some can be empty):
|
|
- config
|
|
- keyslots
|
|
- digests
|
|
- segments
|
|
- tokens
|
|
|
|
Except for config section, all section contains array of objects that must be named
|
|
as number (unsigned integer) - for example keyslot "0", "1" etc.
|
|
Every object is typed (must contain attribute "type").
|
|
According to type, library decides how to handle (or ignore) such an object.
|
|
|
|
Binary data inside JSON (for example salt) is stored in Hexa64 encoding.
|
|
|
|
If a value is needed to be stored as a 64bit integer (usually offset or size),
|
|
it is stored in text format and later converted to the 64bit integer.
|
|
(JSON cannot store 64bit integers directly.)
|
|
|
|
Config section
|
|
~~~~~~~~~~~~~~
|
|
Config contains information about JSON buffer size (cross-checked with binary header),
|
|
keyslot area size and optional object with activation flags.
|
|
|
|
The "flags" section is array of activation flags that are automatically used
|
|
when LUKS device is activated (for example it can unconditionally allow TRIM/discard
|
|
functionality on the encrypted device).
|
|
|
|
Segments sections
|
|
~~~~~~~~~~~~~~~~~
|
|
The segment is an encrypted area on the disk containing data (in LUKS1 often
|
|
mentioned as a data payload).
|
|
For now, only one data area is available for the user.
|
|
(More segments will be later used for on-line re-encryption functionality.)
|
|
|
|
Segments contain definition about encryption parameters, sector size and
|
|
start and length of the segments. By default, the segment starts directly
|
|
after the LUKS2 header and is marked as "dynamic" (it automatically detects
|
|
the size of the available device).
|
|
|
|
Optionally it can contain information about data integrity protection,
|
|
then the data segments is formatted as dm-integrity device and dm-crypt
|
|
encryption is stacked above.
|
|
|
|
To activate a segment, there must be at least one digest linked to it.
|
|
|
|
Keyslots section
|
|
~~~~~~~~~~~~~~~~
|
|
Keyslot object contains information stored key - area, where it is stored
|
|
(keyslot data), encryption, anti-forensic function, and Key Derivation Function
|
|
and its parameters (PBKDF type, costs, salt).
|
|
|
|
For now, only internal "luks2" keyslot type is available, it uses the same logic
|
|
as LUKS1 keyslot, but allows to define per-keyslot algorithms
|
|
(for example different PBKDF).
|
|
|
|
Digests section
|
|
~~~~~~~~~~~~~~~
|
|
The digest is used to verify that volume key decrypted from a keyslot is correct.
|
|
A digest is linked to keyslots and segment.
|
|
|
|
For now, only "pbkdf2" digest (LUKS1 compatible digest that uses PBKDF2)
|
|
is supported.
|
|
|
|
Tokens section
|
|
~~~~~~~~~~~~~~
|
|
A token is an object that can describe "how to get passphrase or key" to unlock
|
|
particular keyslot or it can be used t store any additional data (even unrelated
|
|
to a keyslot).
|
|
This area can be user configurable, and libcryptsetup provides interface to
|
|
store used data directly in JSON format.
|
|
Some token types are implemented internally, for now, there is only "luks2-keyring".
|
|
type. This token type tries to load unlocking passphrase from kernel keyring
|
|
with stored identification.
|
|
|
|
There can be external application that uses token objects to store metadata and
|
|
implements bindings to specific hardware (TPM etc.).
|
|
|
|
LUKS2 JSON Format Example
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
For illustration this is example of a LUKS2 device JSON:
|
|
|
|
{
|
|
"keyslots":{
|
|
"0":{
|
|
"type":"luks2",
|
|
"key_size":32,
|
|
"kdf":{
|
|
"type":"argon2i",
|
|
"time":181,
|
|
"memory":1024,
|
|
"cpus":4,
|
|
"salt":"Xfc5ScS8tCLrdbt6jtyWsBjCwAn3Msn\/enOYaAq8PEo="
|
|
},
|
|
"af":{
|
|
"type":"luks1",
|
|
"hash":"sha256",
|
|
"stripes":4000
|
|
},
|
|
"area":{
|
|
"type":"raw",
|
|
"encryption":"aes-xts-plain64",
|
|
"key_size":32,
|
|
"offset":"32768",
|
|
"size":"131072"
|
|
}
|
|
}
|
|
},
|
|
"tokens":{
|
|
"0":{
|
|
"type":"luks2-keyring",
|
|
"keyslots":[
|
|
"0"
|
|
],
|
|
"key_description":"my-token"
|
|
}
|
|
},
|
|
"segments":{
|
|
"0":{
|
|
"type":"crypt",
|
|
"offset":"4194304",
|
|
"iv_tweak":"0",
|
|
"size":"dynamic",
|
|
"encryption":"aes-xts-plain64",
|
|
"sector_size":512
|
|
}
|
|
},
|
|
"digests":{
|
|
"0":{
|
|
"type":"pbkdf2",
|
|
"keyslots":[
|
|
"0"
|
|
],
|
|
"segments":[
|
|
"0"
|
|
],
|
|
"hash":"sha256",
|
|
"iterations":155298,
|
|
"salt":"WgMOideLECc5hfnmFVu3bwttJpkfnpf2RayE2WhP8zU=",
|
|
"digest":"olobPk9pc0GItqofH78aMPmRaOZIbRevlvSlTZ91NLI="
|
|
}
|
|
},
|
|
"config":{
|
|
"json_size":"12288",
|
|
"keyslots_size":"4161536",
|
|
"flags":[
|
|
"allow-discards"
|
|
]
|
|
}
|
|
}
|