Before you start#
Review device mapper, block I/O, cryptographic interfaces, and filesystem durability. This chapter inspects cryptsetup 2.7.5 commit 3c3a8210e4927b5ce06481f91468c6ad9779b3aa. It is a historical source baseline, not a current security recommendation or a tested kernel/userspace pairing.
Learning goals#
Distinguish LUKS metadata, passphrases, keyslot derivation, volume keys and the kernel dm-crypt mapping. Explain metadata locks, failure cleanup and the limits of encryption without operating on any real volume or secret.
Source walkthrough#
- Header
Read and lock LUKS2 metadata or return an error.
- Keyslot
Derive and unwrap candidate material under slot parameters.
- Validate
Check recovered volume-key material against the relevant metadata.
- Mapping
Request dm-crypt configuration and clean temporary state.
cryptsetup is a userspace tool and library for configuring supported encrypted storage formats and device-mapper mappings. LUKS is a disk encryption metadata format with versions and options; dm-crypt is a kernel device-mapper target that processes I/O through an active mapping. The passphrase is not simply used as the data encryption key. A keyslot can derive material from a passphrase and its parameters to unlock protected key material; the recovered volume key is checked against the relevant metadata before it is used for an appropriate mapping. Exact algorithms, metadata and supported modes depend on the format and configuration.
Keep the lifecycle in view: credential → keyslot processing → recovered volume key → metadata validation → mapping activation → kernel dm-crypt I/O. This is a teaching-level summary; supported formats and advanced configurations can add token handling, multiple segments or other steps. In particular, KDF output participates in keyslot processing; it should not be assumed to be the volume key itself.
The following exact excerpt from cryptsetup 2.7.5 lib/luks2/luks2_keyslot.c, LUKS2_keyslot_open, is GPL-2.0-or-later under its SPDX identifier. Later slot-selection and error handling are omitted:
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
if (!hdr)
return -EINVAL;
cd is a cryptsetup device context and hdr is the LUKS2 header representation requested from it. If no appropriate header is available, the function returns an invalid-argument error before proceeding with keyslot selection. A caller must not treat this as a successfully unlocked volume key. The surrounding code distinguishes a request to try eligible slots from a request for one specific slot, checks return values and may report errors such as memory failure or an unsuccessful unlock. The pointer and any recovered key material have lifetimes and cleanup requirements beyond this short branch.
The next exact excerpt from lib/luks2/luks2_json_metadata.c, LUKS2_hdr_read, is also GPL-2.0-or-later. The following conditional recovery path is omitted:
r = device_read_lock(cd, crypt_metadata_device(cd));
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
The code requests a read lock on the metadata device and reports and returns an error if it cannot obtain it. That protects a particular metadata access under the implementation's locking protocol; it does not make every later device or filesystem operation atomic. The surrounding function reads the disk header and, on a selected recovery condition, releases the read lock before attempting a write lock. A lock or metadata-read failure must be handled without claiming that a volume was opened.
Header, keyslot and active mapping#
LUKS1 and LUKS2 have different metadata formats and capabilities. LUKS2 uses structured metadata including JSON-described objects such as keyslots, digests and segments, with binary header information and redundant metadata areas under the format's rules. A keyslot describes how a candidate credential can be processed to recover protected key material; a digest can help verify the recovered key against metadata; a segment describes data layout and encryption parameters. A token is metadata used by a compatible token mechanism, not a promise that every installed system supports every token type. Never assume that a LUKS1 header has LUKS2's JSON structure.
Select a field to connect its position, bytes, and meaning.
40 bytes in file order. Offsets start at zero.
Selected: magic. ASCII LUKS then 0xba 0xbe; the LUKS2_MAGIC_1ST string.
Read the byte table
| Offset | Field | Hex bytes | Interpretation |
|---|---|---|---|
| 0 | magic | 4c 55 4b 53 ba be | ASCII LUKS then 0xba 0xbe; the LUKS2_MAGIC_1ST string |
| 6 | version | 00 02 | uint16 stored big-endian; the LUKS2 reader checks for 2 |
| 8 | hdr_size | 00 00 00 00 00 00 00 00 | Placeholder; uint64 size in bytes, including the JSON area |
| 16 | seqid | 00 00 00 00 00 00 00 00 | Placeholder; increased on every header update |
| 104 | salt | 00 00 00 00 00 00 00 00 | Placeholder for the first 8 of 64 salt bytes |
| 448 | csum | 00 00 00 00 00 00 00 00 | Placeholder for the first 8 of 64 checksum bytes |
A passphrase is processed by a key derivation function under the keyslot's parameters. PBKDF2 and Argon2 are examples supported in relevant cryptsetup configurations and formats; availability, parameter limits and implementation vary. The derived material is used in the slot-unwrapping process, and the result is checked against the relevant key validation metadata. The volume key used by the encrypted data mapping is conceptually distinct from the user's passphrase. Multiple slots can protect access to the same volume key under their configuration; a failed slot need not establish that every eligible slot fails.
On successful unlock and activation, cryptsetup configures a device-mapper mapping and the kernel dm-crypt target handles subsequent block I/O for that mapping. Userspace does not need to encrypt each individual filesystem read and write in the CLI process. The Linux v6.12 device-mapper chapter provides the kernel-side bridge; the actual kernel configuration and active table determine runtime behavior. An open mapping can exist while no filesystem is mounted, and a mounted filesystem can have additional caches and open files. A successful metadata parse does not prove that a mapping was created or that data is readable.
The cryptsetup context, header, keyslot metadata, temporary buffers, volume-key object and device-mapper request have distinct ownership. A failed allocation, inaccessible device, invalid header, wrong credential, unsupported algorithm or kernel mapping error can stop the process at different points. Sensitive buffers need the implementation's secure-memory and cleanup handling; an application must not log passphrases or volume keys while diagnosing an error. A returned error does not authorize repeated guesses against someone else's storage.
A synthetic two-slot case#
Suppose a fictional LUKS2 header describes slot 0 as disabled and slot 1 as enabled. The caller supplies an invented credential token X to a source-only model; no actual passphrase or hash is computed. In the first case X does not unlock slot 1, so the model returns a generic unsuccessful-unlock result and retains no recovered key. In the second case a different invented token Y represents a matching credential, and the modeled slot returns a volume-key object V whose digest check succeeds. Only after that validation would an actual program proceed toward constructing an appropriate mapping, subject to all other checks and permissions.
The model has states header-read, slot-selected, candidate-unwrapped, digest-verified, mapping-requested and cleanup. If header locking fails, the program never reaches the slot stage. If a candidate fails validation, it must not be used to construct a mapping. If mapping creation later fails, the unlocked temporary key object and other resources still require cleanup. A header reference or lock does not by itself retain a physical device; removal or I/O failure can occur between metadata reading and a later operation. These are hypothetical transitions, not observed cryptographic operations.
- header-read
Metadata is read under a lock; a failure never reaches slot selection.
- slot-selected
A named slot or the any-slot priority path is chosen.
- candidate-unwrapped
Candidate key material is derived from the supplied credential.
- digest-verified
Only a recovered key that passes the digest check may continue.
- mapping-requested
A verified key leads to a mapping plan; a later failure still needs cleanup.
- cleanup
Temporary key objects and buffers are released on every exit path.
For the specific source, LUKS2_keyslot_open tries preferred and then normal-priority eligible slots in an ANY_SLOT branch under its return-code conditions; a named slot takes a different path. It preserves an incorrect-password result over one particular no-entry result in the documented code. Do not generalize those exact priority decisions to every format, token plugin or future release. Report the actual operation and error without exposing which secret was supplied.
In lib/luks2/luks2_keyslot.c, cryptsetup 2.7.5, LUKS2_keyslot_open, GPL-2.0-or-later (the header and the named-slot branch are omitted):
if (keyslot == CRYPT_ANY_SLOT) {
r_prio = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
password, password_len, segment, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
password, password_len, segment, vk);
/* Prefer password wrong to no entry from priority slot */
if (r_prio == -EPERM && r == -ENOENT)
r = r_prio;
} else
The any-slot path tries the preferred priority first, and the normal priority only when that attempt returns -EPERM (wrong password) or -ENOENT (no entry). The final comment keeps a wrong-password result over a missing entry. The excerpt does not show the slot loop inside the priority function.
Metadata recovery and secret lifetime#
LUKS2 redundant metadata areas, sequence information and checksums support identifying and handling certain interrupted or damaged metadata states under the format and tool's recovery rules. They do not make arbitrary corruption harmless and do not authenticate the identity of a disk owner. LUKS2_hdr_read uses a lock and has a conditional path that can switch from reading to a write lock for recovery. Automatic repair is a storage-changing operation and is deliberately outside this lesson's practice. A source reading of that branch is not a successful repair experiment.
In lib/luks2/luks2_json_metadata.c, cryptsetup 2.7.5, LUKS2_hdr_read, GPL-2.0-or-later (the initial read and the rollback copy are omitted):
if (r == -EAGAIN) {
/* unlikely: auto-recovery is required and failed due to read lock being held */
device_read_unlock(cd, crypt_metadata_device(cd));
/* Do not use LUKS2_device_write lock. Recovery. */
r = device_write_lock(cd, crypt_metadata_device(cd));
if (r < 0) {
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
When the first read reports -EAGAIN, the code releases the read lock before it requests a write lock for recovery. The excerpt does not show the recovery read or the write unlock, and it does not show that any header was repaired.
A header backup can contain keyslot material and metadata needed to attempt unlocking the data. It should be treated as sensitive and protected with an explicit retention and access policy. Deleting or changing a keyslot on the current device does not necessarily invalidate an older backup that still contains the old keyslot material, especially if it can be combined with unchanged encrypted data and a credential. Key rotation, backups and disposal require an actual threat model and verified procedures; this chapter does not instruct a learner to alter a real header.
An active mapping exposes decrypted block contents to authorized users of that mapping. Encryption at rest does not protect data from a process already permitted to read the unlocked mapping, from secrets in memory or swap under inappropriate conditions, or from compromised endpoints. Filesystem snapshots, backup copies, hibernation images and application logs can create additional copies with their own protection requirements. Discard/TRIM behavior can reveal allocation patterns depending on configuration and underlying storage. Cipher mode and optional integrity mechanisms matter: confidentiality alone does not imply authenticated integrity or resistance to every modification.
LUKS2 reencryption is a separate stateful operation with version-specific resilience, metadata and failure behavior. It must not be treated as a harmless keyslot edit or simulated on a real device by a beginner. A recovery plan and tested backups are needed for actual operations; this source-only course does not perform reencryption, repair, erase or mapping creation. The practice does not calculate a password hash, benchmark a KDF or handle real keys.
Separating cost, validation and access#
A key derivation function deliberately consumes resources so that deriving candidate material has a cost. Its configured memory, time and parallelism parameters are part of a keyslot's metadata and can affect whether a particular machine can unlock a volume within its available resources. PBKDF2 and Argon2 have different parameters and properties; a time estimate from one machine or implementation does not translate directly to another. A memory-allocation failure while deriving candidate material is not proof that the credential was incorrect. The source's distinct ENOMEM, EPERM and missing-entry handling illustrates why a program should preserve an error category internally while avoiding disclosure of sensitive details to an unauthorized observer.
Suppose the synthetic slot's declared KDF parameters require more memory than a small recovery environment can supply. The metadata may be readable and the user's credential may be correct, but the attempt can fail before a candidate key is validated. Changing the parameters or formatting the device in response would be a destructive operation, not a harmless diagnostic. A real recovery process would need the correct metadata, authorized credentials, compatible software, adequate resources and a verified backup procedure. The exercise below calculates none of those costs and does not offer password guessing.
The digest and segment relationships matter because a candidate volume key is meaningful only for the relevant data configuration. In LUKS2, metadata can describe more than one keyslot or segment under supported operations. An implementation must not mix a key recovered for one context with unrelated segment parameters merely because the same slot number appears in a log. The selected function receives a segment argument and a volume-key output pointer; its surrounding callers and metadata determine the meaning. A source-only model should show these objects separately instead of treating the entire header as an opaque Boolean “unlocked.”
Temporary key material has multiple possible copies: a passphrase input buffer, derivation output, a volume-key object and data passed to a kernel mapping interface. Each copy has an owner and lifetime. A secure-memory allocation or explicit clearing routine can reduce exposure under its documented assumptions, but it cannot prove that no copy exists in application memory, crash dumps, swap or another component. Avoid placing actual credentials in shell arguments, terminal history or teaching logs. This lesson's labels X and Y are not secrets and do not represent a real cryptographic computation.
- Passphrase
- The user credential; a KDF processes it, and it is not the dm-crypt data key.
- Derived material
- KDF output used to unwrap a keyslot; the chapter treats it as distinct from the volume key.
- Volume key
- Recovered key material; a digest in the metadata can validate it before use.
- dm-crypt mapping
- The kernel mapping that uses the validated key for block I/O after activation.
An unlocked mapping is a separate authorization boundary. Once created, filesystem and device permissions govern who can access it, and an authorized program can read plaintext without knowing the original passphrase. Closing a user interface or deleting a passphrase variable does not automatically remove every open mapping or revoke all open file descriptors. Conversely, a failed mapping request can leave temporary userspace state that must be cleared even though no block device was exposed. A real incident record must distinguish the unlock result, device-mapper operation, mount state and application access without recording the volume key.
The examples deliberately omit algorithm parameters and real secret bytes. Their only purpose is to distinguish ownership and state transitions; they cannot validate a storage format or establish the safety of any cryptographic configuration.
Practice#
This private model uses labels only, with no passwords, devices or cryptographic functions:
python3 - <<'PY'
def model(header_ok, slot_ok, digest_ok):
if not header_ok: return 'header error; cleanup'
if not slot_ok: return 'slot failed; cleanup'
if not digest_ok: return 'digest failed; cleanup'
return 'mapping plan only; cleanup temporary state'
for case in [(False, True, True), (True, False, True),
(True, True, False), (True, True, True)]:
print('synthetic:', model(*case))
PY
Expected output shows three distinct failure stages and one mapping plan. It does not parse LUKS, validate a header, derive a key, measure KDF cost or touch a device. If Python is absent, evaluate the same four rows by hand. No passphrase, keyring, block device, loop device or host cryptsetup configuration is accessed.
Source-only alternative: draw the synthetic state transitions and mark the exact read-lock failure and absent-header return. Explain why a successful model branch is only a mapping plan, why a passphrase is not the data key, and why an old header backup can remain sensitive. Deliver the state table with all credentials and key objects represented by labels only.
Knowledge check#
- Why is a passphrase not simply the dm-crypt data key in the described LUKS path?
- What does
LUKS2_keyslot_opendo when it cannot obtain a LUKS2 header? - Why does
LUKS2_hdr_readacquire a metadata lock, and why is that not a guarantee of a successful mapping? - How can an old header backup remain relevant after a current keyslot is removed?
- Why do confidentiality and integrity require separate analysis?
Answers#
- A keyslot uses a derivation and unwrapping process to recover and validate volume-key material. The active dm-crypt mapping uses the appropriate recovered key and parameters under its own interface.
- It returns
-EINVALbefore proceeding through the slot-selection branch. The caller cannot treat that path as an unlocked volume. - The lock coordinates access to metadata under cryptsetup's protocol. Later reads, validation, keyslot work, device availability or kernel mapping can still fail.
- The backup can retain old keyslot material and metadata. Removing a slot from the current header does not necessarily erase older copies or make them harmless with respect to unchanged data.
- Encryption can hide data at rest under its assumptions without authenticating every modification. Integrity, key exposure, unlocked mappings and backup copies need their own controls and threat model.
Checkpoint#
Submit the header-to-slot-to-mapping state table and either the private label-model output or supplied source-only analysis. Ready means explaining both source failure branches, distinguishing a passphrase from the volume key, and naming a backup and active-mapping limitation. Retry with a single synthetic slot before adding redundancy and failure cleanup.