Skip to content

Instantly share code, notes, and snippets.

@Guillawme
Forked from cyberanchor/LUKS_cheatsheet.md
Created February 24, 2026 13:43
Show Gist options
  • Select an option

  • Save Guillawme/8f3c98e1c020397bb9e83e00ff47b88d to your computer and use it in GitHub Desktop.

Select an option

Save Guillawme/8f3c98e1c020397bb9e83e00ff47b88d to your computer and use it in GitHub Desktop.
CryptSetup | LUKS cryptocontainer CheatSheet

CryptSetup | LUKS cryptocontainer CheatSheet

Simple guide for creating and managing a LUKS container (5 GB, ext4). Сontainer creation, key management, slot operations, testing keys, creating custom key files from images, managing detached headers, handling complex passphrases, and generating passphrases from BIP-39 seed phrases.


Prerequisites

  • System: Used Arch Linux.
  • Packages: Install cryptsetup and e2fsprogs:
    sudo pacman -S cryptsetup e2fsprogs --noconfirm

Container operations

Create a LUKS container

  1. Create a 5 GB container file:

    dd if=/dev/urandom of=/home/user/luks_container.img bs=1M count=5000 status=progress
  2. Fast LUKS container setup

This configuration prioritizes speed while maintaining reasonable security, suitable for quick setups or less sensitive data.

cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --key-size 256 --hash sha256 --pbkdf pbkdf2 --pbkdf-force-iterations 1000000 --use-random /home/user/luks_container.img --debug --verbose
  • Cryptography: AES-XTS (AES with XTS mode), 256-bit key (128-bit AES keys split for XTS).
  • Hash: SHA-256 for key derivation.
  • PBKDF: PBKDF2 with 1,000,000 iterations, balancing speed and security.

2.1 Secure LUKS container setup

This configuration maximizes security for sensitive data, using stronger cryptographic parameters and Argon2id for key derivation, at the cost of slower setup and unlocking.

cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --key-size 512 --hash sha512 --pbkdf argon2id --pbkdf-memory 4194304 --pbkdf-parallel 8 --iter-time 5000 --use-random --sector-size 4096 --keyslot-cipher aes-xts-plain64 --keyslot-key-size 512 --luks2-keyslots-size 16m --luks2-metadata-size 256k /home/user/luks_container.img --debug --verbose
  • Cryptography: AES-XTS, 512-bit key (256-bit AES keys split for XTS); keyslots also use AES-XTS with 512-bit keys.
  • Hash: SHA-512 for key derivation.
  • PBKDF: Argon2id with 4 GiB memory, 8 threads, and 5-second iteration time.
  • Header: 16 MiB keyslot area, 256 KiB metadata per copy, optimized for security and flexibility.
  • Note: Uses --pbkdf-memory 1048576 (1 GiB) instead of 4 GiB for better compatibility with systems having limited RAM (e.g., 4–8 GiB).
  1. Open container:

    sudo cryptsetup luksOpen /home/user/luks_container.img luks_container
  2. Format with ext4:

    sudo mkfs.ext4 /dev/mapper/luks_container
  3. Mount:

    sudo mkdir /mnt/luks_container
    sudo mount /dev/mapper/luks_container /mnt/luks_container
    sudo chown $USER:$USER /mnt/luks_container

Close container

  1. Unmount:

    sudo umount /mnt/luks_container
  2. Close:

    sudo cryptsetup luksClose luks_container --verbose --debug

Key Management

Add key file

  1. Create key file:

    dd if=/dev/urandom of=/path/to/keyfile bs=4096 count=1
  2. Add to slot 3 using passphrase:

    echo -n "your_passphrase" | cryptsetup luksAddKey /home/user/luks_container.img /path/to/keyfile --key-slot 3 --verbose --debug --key-file=-
  3. Add to slot 0 using key file from slot 3:

    dd if=/dev/urandom of=/path/to/new_keyfile bs=4096 count=1
    cryptsetup luksKillSlot /home/user/luks_container.img 0 --key-file /path/to/keyfile_slot3 --verbose --debug
    cryptsetup luksAddKey /home/user/luks_container.img --key-slot 0 /path/to/new_keyfile --key-file /path/to/keyfile_slot3 --verbose --debug

Add Passphrase to specific slot

  • Add complex passphrase to slot 4 using existing key file:

    echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | cryptsetup luksAddKey /home/user/luks_container.img --key-slot 4 --key-file /path/to/keyfile --verbose --debug --new-keyfile=-
    • Replace /path/to/keyfile with the path to your existing key file.
    • --new-keyfile=- reads the new passphrase from stdin.
  • Add to LUKS with escaped passphrase:

    echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | cryptsetup luksAddKey /home/user/luks_container.img --key-slot 4 --key-file /path/to/keyfile --verbose --debug --new-keyfile=-
  • Test complex passphrase:

    echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | cryptsetup open --test-passphrase --key-slot 4 /home/user/luks_container.img --verbose --debug --key-file=-

Generate passphrase from BIP-39 seed phrase

Generate passphrase from a 12-word BIP-39 seed phrase using a deterministic password generator (7w) and add it to a LUKS key slot. This method allows passphrase recovery from the seed phrase alone.

Steps

  1. Generate a 12-word BIP-39 seed phrase:

    • Use a secure BIP-39 seed phrase generator, preferably offline, to create a 12-word mnemonic compliant with the BIP-39 standard. Example tool: https://cryptony.app/seed-phase-generator/

    • Example seed phrase:

      property iron shove feature tide parent army neglect stable lab ostrich zone
      
  2. Convert seed phrase to passphrase:

    • Use the 7w deterministic password generator (https://dlepex.github.io/7w/index.html) to convert the seed phrase into a complex passphrase. The tool operates client-side in the browser and does not store or transmit data.
    • Configuration:
      • Set w=12 (12 words).
      • Set mod=v (visible mode).
    • Steps:
    • Example Output:
      <0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{
      

    Sceenshot 1: Convert seed phrase to passphrase 1

  3. Add passphrase to LUKS key slot:

    • Add the generated passphrase to slot 4 using an existing key file for authentication.

    • Command:

      echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | cryptsetup luksAddKey /home/user/luks_container.img --key-slot 4 --key-file /path/to/keyfile --verbose --debug --new-keyfile=-
      • Replace /path/to/keyfile with the path to your existing key file.
      • Ensure proper escaping (e.g., \\ for \, \`` for ```, \nfor\n`).
    • Verify output:

      echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | hexdump -C

      Expected output:

      00000000  3c 30 62 6e 7d 30 58 39  4f 3c 52 55 66 3a 74 52  |<0bn}0X9O<RUf:tR|
      00000010  5f 43 5a 3b 6d 61 38 22  2c 3a 5c 44 51 2a 7d 39  |_CZ;ma8",:\DQ*}9|
      00000020  41 2a 78 42 34 38 53 2d  4c 50 36 4c 37 48 4a 28  |A*xB48S-LP6L7HJ(|
      00000030  4b 69 48 60 36 30 4c 0a  49 33 4f 41 48 6a 7b     |KiH`60L.I3OAHj{|
      0000003f
      
    • Test passphrase:

      echo -n '<0bn}0X9O<RUf:tR_CZ;ma8",:\DQ*}9A*xB48S-LP6L7HJ(KiH`60L\nI3OAHj{' | cryptsetup open --test-passphrase --key-slot 4 /home/user/luks_container.img --verbose --debug --key-file=-

Test keys

  • Test passphrase:

    cryptsetup open --test-passphrase /home/user/luks_container.img --verbose --debug
  • Test key file:

    cryptsetup open --test-passphrase --key-file /path/to/keyfile /home/user/luks_container.img --verbose --debug
  • Test specific slot:

    cryptsetup open --test-passphrase --key-slot 4 /home/user/luks_container.img --verbose --debug

Remove key slot

  • Remove slot 0:
    cryptsetup luksKillSlot /home/user/luks_container.img 0 --key-file /path/to/keyfile_slot3 --verbose --debug

Custom key from image

Create a key file from an image by downloading it, verifying its SHA512 hash, modifying it with binary data (prepend 10 0x31 bytes, append 10 0x2E bytes), and adding it to a LUKS container.

Steps

  1. Download and modify image: Use this script to download image file, verify hash, and create a key file.

Bash script

#!/bin/bash

set -e

# Log function with timestamp (Python-style)
log() {
    local level="$1"
    local message="$2"
    local extra="${3:-}"
    printf "[%s] [%-5s] %s %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$message" "$extra"
}

# Error exit with cleanup
error_exit() {
    log "ERROR" "$1"
    rm -f "$TMP_FILE" "$OUTPUT_KEY"
    exit 1
}

# Check dependencies
for cmd in wget sha512sum printf; do
    command -v "$cmd" &>/dev/null || error_exit "missing $cmd"
done

URL="https://upload.wikimedia.org/wikipedia/commons/2/2c/TerryFoxToronto19800712.JPG"
EXPECTED_HASH="f1db6ca08d665e29e4462a5384ee7cb440345d7147fd6589a2515b876f053b6f048de0bdb6507443336fcee51552e571ea2af3bc4e180472ccddf608ee06fc6f"
EXPECTED_MODIFIED_HASH="726f581b49461e5d48de1d94f2c64cd2510afd312bb093fe3a4ec106f7b035e1eaf10233112e8aeb04a5eeaf0bedacce503cfcd27a8c70b107538528a802301d"
TMP_FILE="/tmp/tmp_key"
OUTPUT_KEY="/tmp/luks_key"

# Download image
log "INFO" "downloading file" "$URL"
wget --no-check-certificate -O "$TMP_FILE" "$URL" 2>/dev/null || error_exit "download failed"

# Verify original file hash
log "INFO" "verifying original file hash"
HASH=$(sha512sum "$TMP_FILE" | cut -d' ' -f1)
[ "$HASH" = "$EXPECTED_HASH" ] || error_exit "hash mismatch: got $HASH, expected $EXPECTED_HASH"

# Modify: prepend 10 '1' (0x31), append 10 '.' (0x2E)
log "INFO" "modifying key file"
{ printf "\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31"; cat "$TMP_FILE"; printf "\x2E\x2E\x2E\x2E\x2E\x2E\x2E\x2E\x2E\x2E"; } > "$OUTPUT_KEY" || error_exit "modification failed"
log "INFO" "key file modification completed"

# Verify modified file hash
log "INFO" "verifying modified file hash"
MODIFIED_HASH=$(sha512sum "$OUTPUT_KEY" | cut -d' ' -f1)
[ "$MODIFIED_HASH" = "$EXPECTED_MODIFIED_HASH" ] || error_exit "modified file hash mismatch: got $MODIFIED_HASH, expected $EXPECTED_MODIFIED_HASH"
log "INFO" "modified file hash verified successfully"

# Cleanup
log "INFO" "cleaning up temporary file"
rm -f "$TMP_FILE" || error_exit "cleanup failed"

log "INFO" "created $OUTPUT_KEY"

Prepend 10 0x31 bytes:

   00000000: 3131 3131 3131 3131 3131 ffd8 ffe0 0010  1111111111......
   00000010: 4a46 4946 0001 0101 0060 0060 0000 ffe1  JFIF.....`.`....
   00000020: 1b02 4578 6966 0000 4949 2a00 0800 0000  ..Exif..II*.....
   00000030: 0700 1201 0300 0100 0000 0100 0000 1a01  ................
   00000040: 0500 0100 0000 6200 0000 1b01 0500 0100  ......b.........
   00000050: 0000 6a00 0000 2801 0300 0100 0000 0200  ..j...(.........
   00000060: 0000 3101                                ..1.

Append 10 0x2E bytes:

   00000000: d618 dff8 6ecf ff00 9353 e81f 2fff 00ae  ....n....S../...
   00000010: 8fff 007c 8fff 00c1 f51c f2af f5f1 dffd  ...|............
   00000020: e13f fd7f a7e7 10ff 00a3 e9ff 00f8 1a7f  .?..............
   00000030: fd7b 1f4d dd8f fa2c 7ff0 f57f f5a3 e9a4  .{.M...,........
   00000040: effa e74b ff00 88ff 00fe ad6f a6cb 3fea  ...K.......o..?.
   00000050: ec6f fdca 7ff9 87f5 ffd9 2e2e 2e2e 2e2e  .o..............
   00000060: 2e2e 2e2e                                ....
  1. Add key to LUKS:

    sudo cryptsetup luksAddKey /home/user/luks_container.img /tmp/luks_key --key-slot 3 --verbose --debug
  2. Test key:

    cryptsetup open --test-passphrase --key-file /tmp/luks_key /home/user/luks_container.img --verbose --debug

Header backup

  • Backup header:

    cryptsetup luksHeaderBackup /home/user/luks_container.img --header-backup-file /path/to/luks_header_backup --verbose --debug
  • Restore header:

    cryptsetup luksHeaderRestore /home/user/luks_container.img --header-backup-file /path/to/luks_header_backup --verbose --debug

Detached header management

Manage a LUKS container with a detached header for enhanced security by storing the header separately from the container data. This can be done by extracting the header from an existing container or creating a new one with a detached header.

Create container with detached header

  1. Create container and header:

    dd if=/dev/urandom of=/home/user/luks_container.img bs=1M count=5000 status=progress
    cryptsetup luksFormat --type luks2 --header /path/to/header.bin /home/user/luks_container.img --verbose --debug

    Set a strong passphrase.

  2. Open container:

cryptsetup luksOpen --header /path/to/header.bin /home/user/luks_container.img luks_container
  1. Format and mount:
    sudo mkfs.ext4 /dev/mapper/luks_container
    sudo mkdir /mnt/luks_container                                     
    sudo mount /dev/mapper/luks_container /mnt/luks_container
    sudo chown $USER:$USER /mnt/luks_container

Extract header from existing container

  1. Backup existing header:

    cryptsetup luksHeaderBackup /home/user/luks_container.img --header-backup-file /path/to/header.bin --verbose --debug
  2. Verify header:

    cryptsetup luksDump --header /path/to/header.bin /home/user/luks_container.img
  3. Remove header from container (optional, for security):

    dd if=/dev/zero of=/home/user/luks_container.img bs=1M count=4 conv=notrunc

    This overwrites the first 4 MB (typical LUKS header size) to remove the header from the container.

Mount with detached header

  1. Open container:
cryptsetup luksOpen --header /path/to/header.bin /home/user/luks_container.img luks_container
  1. Mount:

    sudo mount /dev/mapper/luks_container /mnt/luks_container
  2. Unmount and close:

    sudo umount /mnt/luks_container
    sudo cryptsetup luksClose luks_container

Backup and restore detached header

  • Backup header:

    cryptsetup luksHeaderBackup --header /path/to/header.bin /home/user/luks_container.img --header-backup-file /path/to/header_backup.bin --verbose --debug
  • Restore header:

    cryptsetup luksHeaderRestore --header /path/to/header.bin /home/user/luks_container.img --header-backup-file /path/to/header_backup.bin --verbose --debug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment