Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Linux Unified Key Setup (LUKS) Disk Encryption format

Linux Unified Key Setup (LUKS) Disk Encryption is commonly used by Linux to encrypt storage media volumes.

Overview

There are 2 versions of the Linux Unified Key Setup (LUKS) Disk Encryption format, each with a separate layout.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsASCII string with an end-of-string character

Layout version 1

A LUKS version 1 encrypted volume consist of:

The total reserved size of the LUKS metadata (volume header and split master key material) seems to commonly be 2 MiB.

The number of bytes per sector is 512.

Layout version 2

A LUKS version 2 encrypted volume consist of:

  • metadata area
  • backup metadata area
    • backup volume header
    • backup JSON area
  • keyslots area
  • encrypted (volume) data

The number of bytes per sector is stored in the JSON metadata and can be 512, 1024, 2048, or 4096.

Keys

To encrypt storage media LUKS Disk Encryption uses different kind of keys.

Master Key (MK)

The Master Key (MK) is derived from the Split Master Key (SMK). The size of the MK is dependent on the master key size value in the volume header. Commonly the MK is 128-bit or 256-bit of size. The MK is used to de/encrypt the encrypted (volume) data.

Split Master Key (SMK)

The Split Master Key (SMK) is stored encrypted with a specific user key (UK) in the split master key material. The size of the key material and hence the SMK is the size of the Master Key (MK) times the number of stripes.

The MK is determined from the SMK using the anti-forensic (AF) diffuser using the hashing method.

The resulting MK can be validated with the master key validation hash stored in the volume header. The validation hash can be calculated using the PBKDF2 algorithm with:

  • The hashing method stored in the volume header (format version 1) or metadata (format version 2).
  • The number of iterations as stored in the volume header.
  • A salt, as stored in the volume header.
  • The master key as the input data.

User Key (UK)

The User Key (UK) is derived from the user password. The UK is used to de/encrypt the corresponding split master key material.

The user key is calculated using the PBKDF2 algorithm with:

  • The hashing method stored in the volume header (format version 1) or metadata (format version 2).
  • The number of iterations as stored in the corresponding key slot.
  • A salt, as stored in the corresponding key slot.
  • The password string as the input data (bytes).
  • A (output) key size that is the same as that of the Master Key (MK).

Encryption methods

LUKS supports multiple encryption methods, different encryption chaining modes and initialization vector modes.

Initialization vector modes

The null initialization vector mode

In the null initialization vector mode the initialization vector (IV) is filled with 0‑byte values.

The plain initialization vector modes

In the plain and plain64 initialization vector mode the initialization vector (IV) is filled with respectively a 32-bit or 64-bit little-endian representation of the corresponding sector number padded with 0-byte values.

The sector number is relative to the start of the data not relative to the start of the volume header.

The encrypted sector-salt initialization vector (ESSIV) mode

Int the encrypted sector-salt initialization vector (ESSIV) mode the initialization vector (IV) is determined by:

  1. hashing the encryption key with hashing method defined in the initialization vector mode options.
  2. encrypting the little-endian representation of the corresponding sector number padded with 0-byte values with the hash of the encryption key.

Note that the sector number is relative to the start of the data not relative to the start of the volume header.

The benbi initialization vector mode

In the benbi initialization vector mode the initialization vector (IV) is filled with a 64-bit big-endian representation of the corresponding cipher block (or narrow block)-count (starting at 1) padded with 0-byte values.

The sector number is relative to the start of the data not relative to the start of the volume header.

The cipher block-count is calculated as:

cipher_block_count = (sector_number << (log2(bytes_per_sectory) - log2(iv_size))) + 1

Benbi is presumably the abbreviation of big-endian numeric block index, or equivalent.

The lmk initialization vector mode

TODO: complete section

AES-CBC

Decryption uses:

  • AES-CBC with Master Key (MK) decryption of sector data
  • The initialization vector of the AES-CBC is dependent on the initialization vector mode defined in the volume header. In recent versions of Linux, AES-CBC is combined with the ESSIV initialization vector mode by default.
  • The initialization vector is 16 bytes in size.

AES-ECB

Decryption uses:

  • AES-ECB with Master Key (MK) decryption of sector data
  • No initialization vector is used.
  • The initialization vector is 16 bytes in size.

AES-XTS

TODO: complete section

  • The initialization vector is 16 bytes in size.

Anubis

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Blowfish

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Cast5

TODO: complete section

RFC 2144 Size of initialization vector?

Cast6

TODO: complete section

RFC 2612 Default encryption mode is cbc-plain Size of initialization vector?

Serpent

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Twofish

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Volume header

Volume header - format version 1

The volume header - format version 1 is 4096 bytes in size and consists of:

OffsetSizeValueDescription
06"LUKS\xba\xbe"Signature
621Format version
832Encryption method (Cipher name), which contains an ASCII string with an end-of-string character
4032Encryption mode (Cipher mode), which contains an ASCII string with an end-of-string character
7232Hashing method, which contains an ASCII string with an end-of-string character
1044Encrypted data start sector
1084Master key size, in number of bytes
11220Master key validation hash
13232Master key derivation salt
1644Master key derivation number of iterations
16840Volume identifier, which contains an ASCII string with an end-of-string character that consists of a lower-case UUID
2088 x 48Array of key slots
5923504Unknown (empty values)

The hashing method is used for the user key calculation and the anti-forensic (AF) diffuser.

Volume header - format version 2

The volume header - format version 2 (or binary header) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
06"LUKS\xba\xbe"Signature
622Format version
88Metadata area size, which consists of the size of the volume header and JSON area
168Epoch (or sequence identifier)
2448Volume label, which contains an ASCII string with an end-of-string character
7232Metadata area checksum method (or algorithm), which contains an ASCII string with an end-of-string character
10464Salt
16840Volume identifier, which contains an ASCII string with an end-of-string character that consists of a lower-case UUID
20848Unknown (subsystem), which contains an ASCII string with an end-of-string character
2568Metadata area offset, which is relative from the start of the storage media in which the LUKS volume is stored
264184Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values
44864Metadata area checksum
5127 x 512 = 3584Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values

JSON area

The JSON area is stored directly after the volume header and must be 4096-byte aligned. The JSON area is of variable size and constists of:

OffsetSizeValueDescription
0...JSON string, which contains an ASCII string with an end-of-string character
......Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values

Example

{
  "keyslots": {
    "0": {
      "type": "luks2",
      "key_size": 32,
      "af": {
        "type": "luks1",
        "stripes": 4000,
        "hash": "sha1"
      },
      "area": {
        "type": "raw",
        "offset": "32768",
        "size": "131072",
        "encryption": "aes-ecb",
        "key_size": 32
      },
      "kdf": {
        "type": "argon2i",
        "time": 6,
        "memory": 1048576,
        "cpus": 4,
        "salt": "X3OghBqUPLPkYuaFlSu4w/4VsRlRNDBzN+IW5Y5JQSU="
      }
    }
  },
  "tokens": {},
  "segments": {
    "0": {
      "type": "crypt",
      "offset": "16777216",
      "size": "dynamic",
      "iv_tweak": "0",
      "encryption": "aes-ecb",
      "sector_size": 512
    }
  },
  "digests": {
    "0": {
      "type": "pbkdf2",
      "keyslots": [
        "0"
      ],
      "segments": [
        "0"
      ],
      "hash": "sha1",
      "iterations": 154931,
      "salt": "wxT97+jYHKhAat3rZb6XXuwXVRn3DM7tvGy8+ZukM38=",
      "digest": "WHT1SoOLP3tummIDhiNTxP39dfw="
    }
  },
  "config": {
    "json_size": "12288",
    "keyslots_size": "16744448"
  }
}

Top level properties

ValueDescription
"config"Config object
"digests"One or more digests object
"keyslots"One or more keyslots object
"segments"One ore more segments object
"tokens"Zero or more tokens object

Config object

ValueDescription
"flags"List of strings
"json_size"String containing an integer
"keyslots_size"String containing an integer
"requirements"

Digests object

TODO: complete section

ValueDescription
"digest"
"hash"type "pbkdf2"
"iterations"type "pbkdf2"
"keyslots"
"salt"
"segments"
"type"

Keyslots object

Contains zero or more keyslot object.

Keyslot object

TODO: complete section

ValueDescription
"af"Anti-forensics (diffuser) object, which should only be present in type "luks2"
"area"Key slot area object
"direction"Re-encryption direction, which should only be present in type "reencrypt"
"kdf"Key derivation object, which should only be present in type "luks2"
"key_size"Key size, in number of bytes
"mode"Re-encryption mode, which should only be present in type "reencrypt"
"priority"Priority, where 0 represents "ignore", 1 "normal" and 2 "high"
"type"Keyslot type, which can be "luks2" or "reencrypt"

Anti-forensics (diffuser) object

TODO: complete section

ValueDescription
"hash"type "luks1"
"stripes"type "luks1"
"type"Anti-forensics type, which can be "luks1"

Keyslot area object

TODO: complete section

ValueDescription
"encryption"type "raw"
"hash"types "checksum" and "datashift-checksum"
"key_size"type "raw"
"offset"
"sector_size"types "checksum" and "datashift-checksum"
"shift_size"types "datashift", "datashift-checksum" and "datashift-journal"
"size"
"type"Area type, which can be "raw", "checksum", "none", "journal"

Key derivation object

TODO: complete section

ValueDescription
"cpus"types "argon2i" and "argon2id"
"hash"type "pbkdf2"
"iterations"type "pbkdf2"
"memory"types "argon2i" and "argon2id"
"salt"
"time"types "argon2i" and "argon2id"
"type"The PBKDF type, which can be "pbkdf2", "argon2i" and "argon2id"

Segments object

TODO: complete section

ValueDescription
"encryption"type "crypt"
"flags"
"integrity"type "crypt"
"iv_tweak"type "crypt"
"offset"
"sector_size"type "crypt"
"size"
"type"Segment type, which can be "linear" or "crypt"

Segment integrity object

TODO: complete section

ValueDescription
"journal_encryption"
"journal_integrity"
"key_size"
"type"

Tokens object

TODO: complete section

ValueDescription
"key_description"type "luks2-keyring"
"keyslots"
"type"

Backup metadata area

To make recovery easier the backup metadata area starts at a fixed offset:

OffsetMaximum JSON area size
16384 (0x004000)12 KiB
32768 (0x008000)28 KiB
65536 (0x010000)60 KiB
131072 (0x020000)124 KiB
262144 (0x040000)252 KiB
524288 (0x080000)508 KiB
1048576 (0x100000)1020 KiB
2097152 (0x200000)2044 KiB
4194304 (0x400000)4092 KiB

Backup volume header - format version 2

The backup (or secondary) volume header - format version 2 is the same as the Volume header - format version 2 with a different signature: “SKUL\xba\xbe”.

Keyslots

Key slot - format version 1

The key slot - format version 1 is 48 bytes in size and consists of:

OffsetSizeValueDescription
04State (of key slot), where 0x0000dead represents inactive (dead) and 0x00ac71f3 represents active
44Key material number of iterations
832Key material salt
404Key material start sector
444Key material number of (anti-forensic) stripes

String identifiers

LUKS uses various string values as identifiers.

Note that it is assumed that these identifiers are case insensitive.

Encryption method

Known values of encryption method are:

ValueDescription
arc4Alleged RC4 (ARC4)
aesAdvanced Encryption Standard (AES)
anubisAnubis
blowfishBlowfish
cast5Cast5 (RFC 2144)
cast6Cast6 (RFC 2612)
serpentSerpent
tnepresReversed variant of Serpent
twofishTwofish

Encryption mode

The encryption mode consists of a string in the format:

chaining_mode[-initialization_vector_mode[:initialization_vector_options]]

Chaining mode

Known values of chaining mode are:

ValueDescription
cbcCipher-block chaining (CBC)
ecbElectronic codebook (ECB), which should not have a initialization vector mode set
xtsXEX-based tweaked-codebook mode with ciphertext stealing (XTS)

Note that it is assumed that these identifiers are case insensitive.

TODO: determine ctr and lrw

Initialization vector mode and options

Known values of initialization vector mode and options are:

ValueDescription
benbiThe initialization vector is the 64-bit big-endian cipher block (or narrow block)-count (starting at 1)
essivEncrypted sector-salt initialization vector (ESSIV). The "essiv" initialization vector mode requires a hash algorithm to be defined as an initialization vector option. This is specified in the form "essiv:hash", e.g. "essiv:sha256"
lmkCompatible implementation of the block chaining mode used by the Loop-AES block device encryption system
nullThe initialization vector is always zero
plainThe initialization vector is the 32-bit little-endian version of the sector number, padded with zeros if necessary
plain64The initialization vector is the 64-bit little-endian version of the sector number, padded with zeros if necessary
plumbUnknown

Hashing method

Known values of hashing method are:

ValueDescription
ripemd160RIPEMD-160
sha1SHA-1
sha224SHA-224
sha256SHA-256
sha512SHA-512
wd256Unknown

The hashing method must at least produce 20 bytes of hash data. Therefore hashing methods like ghash and MD5 are unsupported.

Format edge cases and corruption scenarios

Uninitialized encrypted volume data

Running “cryptsetup luksFormat” will not initialize the encrypted volume data, the data is initialized on write. The uninitialized encrypted data is treated as-is on decryption.

References