Add full-disk encryption (FDE) to a Linux install you already have. LinuxLocker encrypts the root filesystem of an already-installed system in place — without reinstalling, and without a second copy of your data. One tool, any distro family it can chroot into, x86_64 and ARM alike: Fedora, RHEL, Rocky, AlmaLinux, Debian, Ubuntu, Linux Mint, Pop!_OS, Raspberry Pi OS, Arch, Manjaro, EndeavourOS and openSUSE. Converts LUKS1 to a LUKS2 container.
Use AsahiLocker instead — not this tool. Same job, with the Fedora Asahi Remix boot guards LinuxLocker deliberately drops. Apple Silicon boots iBoot → m1n1 → U-Boot → GRUB, and its stub partitions are read by the Apple firmware itself; nothing here understands that chain.
You do not have to remember this.
linuxlocker.shandluks-deploy.shboth detect Fedora Asahi Remix — fromVARIANT_ID, an Asahi kernel, m1n1 boot components, or an Apple Silicon device tree — and exit before touching any device, with a link to AsahiLocker. The check runs against the live environment and against the partition you select, because an Asahi disk can be read from another machine.
luks-deploy.sh converts your existing root (or data) partition into a LUKS2
container holding that same filesystem. Your files and the filesystem UUID
survive; the partition simply gains an encryption layer. It then rewrites every
piece of boot configuration that has to change — crypttab, fstab, GRUB
defaults, BLS entries, cmdline.txt, extlinux.conf, initramfs generator
config, all initramfs images — and refuses to let you reboot until a full
verification gate passes.
The front door, linuxlocker.sh, first identifies the live environment's OS
and package manager, installs any tools the run needs, and only then hands
off to the encrypter — which resolves filesystem-specific tools the moment it
knows what the target actually uses.
This is destructive-by-nature tooling. It rewrites a live root filesystem. Read
docs/INSTALL.mdbefore running anything, and have a verified backup. See Risks.
# 1. On the installed system: get the kit onto a USB drive
git clone https://github.com/doug445/LinuxLocker.git
# 2. Boot ANY live Linux for your machine (the target distro's own live ISO
# is the safest choice) with that USB plugged in.
# 3. From the live environment:
sudo ./LinuxLocker/bin/linuxlocker.sh # detects OS, installs deps,
# runs the encrypter
# 4. Reboot, enter your passphrase, then finish up on the encrypted system:
sudo ./LinuxLocker/bin/post-encryption-setup.shThe deploy script auto-detects your disk layout, target OS, filesystem and
boot machinery, and shows you what it found. You confirm the selection, type
ENCRYPT, and choose a passphrase. Everything after that is automated,
including recovery if a step fails partway.
--dry-run runs the entire read-only half — detection, cross-checks, KDF
benchmark, the exact cryptsetup command it would issue — and exits before
the point of no return.
Behaviour is keyed off what is actually installed on the target, never off the distro's name — so derivatives inherit support from their family.
| Family | Package manager | Initramfs | Boot config handled |
|---|---|---|---|
| Fedora / RHEL / Rocky / Alma | dnf / yum | dracut | GRUB defaults, BLS entries (grubby or direct patch), /etc/kernel/cmdline, rd.luks.* args |
| Debian / Ubuntu / Mint / Pop!_OS | apt | initramfs-tools | crypttab with initramfs flag, update-grub (installs cryptsetup-initramfs in the chroot if missing) |
| Raspberry Pi OS | apt | initramfs-tools | cmdline.txt root= rewrite, auto_initramfs=1, crypttab-driven unlock |
| Arch / Manjaro / EndeavourOS | pacman | mkinitcpio | HOOKS gets encrypt (busybox) or sd-encrypt (systemd), cryptdevice=/rd.luks.* args, grub-mkconfig |
| openSUSE | zypper | dracut | GRUB defaults + grub2-mkconfig, rd.luks.* args |
| ARM boards with U-Boot distro-boot | — | any of the above | extlinux.conf APPEND rewrite |
Alpine, Void and Gentoo are recognised by the dependency installer; their boot stacks are handled to the extent they use the machinery above.
Handled as of 1.2.0, having previously been refused outright.
| Boot stack | What happens |
|---|---|
| systemd-boot, Type #1 entries | Detected from the loader binary on the ESP, not guessed from /boot/loader/entries. Entries are patched; check V13 confirms something bootable points at the encrypted root. Works with the ESP at /efi, /boot/efi or /boot, with or without a separate XBOOTLDR partition. |
Unified Kernel Image (EFI/Linux/*.efi) |
The .efi is rebuilt with the post-encryption kernel command line, using whichever backend the target actually uses: an mkinitcpio preset with _uki=, kernel-install with layout=uki, dracut --uki-file, or ukify. Check V11 reads the rebuilt .cmdline section back and fails the run if the LUKS arguments are not in it. |
| Secure Boot + UKI | The rebuilt .efi is re-signed with sbctl or sbsign. Check V12 fails the run if Secure Boot is enabled and any UKI came out unsigned. |
| Secure Boot, no UKI (shim + GRUB, shim + systemd-boot) | No interaction. The initramfs is not part of the verified chain, and nothing here touches shim, the bootloader binary or vmlinuz. |
Signing has to be explicit, because distro automation does not fire from a
chroot: Arch's zz-sbctl.hook is a libalpm hook, so mkinitcpio -P run by
hand rebuilds the UKI and leaves it unsigned — which a Secure Boot machine then
refuses to load. LinuxLocker signs it itself and verifies the signature before
allowing the reboot.
A UKI target is still refused before the shrink in two cases: no rebuild
backend exists, or Secure Boot is on and no signing backend exists. Both are
overridable with LUKS_ALLOW_UKI=1.
This is verified by 45 fixture assertions in CI across every ESP layout, backend and signer combination — verified end to end on Manjaro w/ systemd-boot/UKI. BOOTLOADERS.md has the full detail, the environment knobs, and the hardware checklist.
Everything gnome-disks can format is classified; a filesystem is supported
in place when it can be shrunk by 32 MiB for the LUKS2 header (or already
has that much slack). Full matrix and workarounds:
docs/FILESYSTEMS.md.
| In place | How |
|---|---|
| ext4 / ext3 / ext2 | resize2fs shrink → encrypt → grow |
| btrfs | online btrfs filesystem resize (subvolume layouts auto-detected) |
| xfs | cannot shrink — accepted only with ≥ 32 MiB pre-existing slack |
| f2fs | resize.f2fs (needs f2fs-tools ≥ 1.16 to shrink) |
| ntfs | ntfsresize (data partitions) |
| vfat | fatresize (data partitions) |
| exfat / udf / swap | not in place — see docs/FILESYSTEMS.md |
- Detects partitions (scored menu, live-USB disk deprioritised), target
OS (
/etc/os-release), filesystem, subvolumes, and the boot partitions — resolved from the target's own fstab, not guessed. - Installs missing tools with the live distro's package manager (dnf, apt, pacman, zypper, apk, xbps, emerge).
- Shrinks the filesystem by 32 MiB (idempotently — a re-run detects the gap and skips).
- Encrypts in place:
cryptsetup reencrypt --encryptwith AES-256-XTS, argon2id, sha512, checksum resilience. - Verifies the LUKS header, opens the container, checks the inner filesystem type and UUID are unchanged, grows the filesystem back.
- Rewrites boot configuration for whatever this target uses, then
rebuilds every initramfs image in a chroot, self-repairing images that
come out without
cryptsetupordm-crypt. - Rebuilds and re-signs the Unified Kernel Image, if the target boots one —
after the kernel command line is final, then signed with
sbctl/sbsignwhen Secure Boot is enabled. - Gates the reboot behind a verification pass over every applicable component — a check that doesn't apply to this target is reported as SKIP, never silently passed.
| The script finds | What happens |
|---|---|
| plain filesystem | normal encryption run |
LUKS2 header with online-reencrypt flag |
a previous run was interrupted → finishes it (--resume-only, with automatic cryptsetup repair after a hard kill), then redoes config |
| complete LUKS2 header | shows a truncated luksDump, then offers: tune (launches luks-tune.sh to raise the KDF), config (redo boot config + verification), or quit |
| LUKS1 header | offers in-place conversion to LUKS2 (cryptsetup convert), then re-costs each keyslot to argon2id using the same three profiles — with an explicit warning gate for GRUB-unlocked (cryptomount) volumes, which cannot open argon2id slots |
no /etc/fstab inside |
offers data-partition mode: encrypt + recovery key + header backup, no boot config |
Three presets. All argon2id; there is deliberately no pbkdf2 profile, and the
fast profile is a hard floor — the tool refuses to write anything
cheaper, with no override flag.
| Profile | Memory | Iterations | Unlock time* | argon2id CPU-seconds |
|---|---|---|---|---|
| aggressive | 4 GiB | 10 | ~16 s | 35.3 s (measured, 56 boots) |
| moderate (default) | 2 GiB | 8 | ~8 s | ~14.6 s (extrapolated) |
| fast | 1 GiB | 9 | ~4 s | ~9.4 s (extrapolated) |
* Reference machine: ASUS ZenBook UX534FTC — Intel Core i7-10510U
(4 cores / 8 threads, 1.80 GHz base, 4.90 GHz turbo), 16 GiB RAM, NVMe,
powersave governor, Linux 6.18 LTS, cryptsetup 2.8.7. AES-XTS throughput on
this box is 2188 MiB/s encrypt / 2267 MiB/s decrypt at a 512-bit key, so the
cipher is never the bottleneck — the KDF is the whole of the wait.
How these were measured. The aggressive row is not an estimate: that
machine runs aggressive in production, and systemd records the cost of every
unlock. Across 56 real boots, the journal's per-unit resource accounting for
systemd-cryptsetup@…service reports a mean of 35.73 CPU seconds (median
35.34, min 34.65, max 39.05) at a 4 GiB memory peak:
journalctl -g 'Consumed .* CPU time over' | grep cryptsetup
# ...service: Consumed 35.366s CPU time over 28.681s wall clock time, 4G memory peak.CPU time is the honest signal here. The unit's wall clock time also covers the human typing the passphrase, which is why it ranges from 22 s to over 3 minutes across those same boots and cannot be compared between machines. CPU time is pure argon2id — typing consumes none of it.
The unlock time column is wall clock: how long you actually wait after the
last keystroke. It was measured directly, by formatting loop-backed LUKS2
volumes with each profile's pinned parameters and timing
cryptsetup open --test-passphrase (best of three: 16.4 s / 8.2 s / 4.2 s).
That reconciles with the journal at a CPU-to-wall ratio of ~2.2 — argon2id at
4 GiB is memory-bandwidth bound, so four threads do not buy four times the
speed. The other two rows' CPU-second figures are extrapolated from the measured
aggressive cost, using ratios confirmed independently with the reference
argon2 CLI at the same parameters (32.3 s / 13.2 s / 8.5 s).
For scale: cryptsetup's own auto-tuning on this machine picks argon2id at
727 MiB and 4 iterations to hit its 2000 ms default target. The fast floor
is over three times that much work.
None of this is configuration. The installer benchmarks the machine it is running on and shows live estimates in the menu; these numbers exist so you know what shape of answer to expect, and they will differ on your hardware — roughly linearly with single-thread performance and memory bandwidth.
Two guards run before anything is written:
- The floor: nothing below
fast(1 GiB × 9) is accepted — cryptsetup's own default is argon2id at ~1 GiB tuned to 2000 ms, and this tool exists to beat a bareluksFormat, not to undercut it. - The stock-strength check: the installer measures what
cryptsetupwould have chosen unaided on this machine and, if a named profile falls short (very fast hardware), raises the iteration count 25% past stock. PinnedLUKS_PBKDF_*values below stock are fatal instead — pinning exists for fleet reproducibility, so the tool never silently edits pinned numbers.
The aggressive profile needs ~6 GiB of free RAM at every unlock — the
installer warns on small-memory machines (Raspberry Pi class) and refuses any
profile whose memory cost exceeds the machine's RAM outright.
Already encrypted? sudo ./bin/luks-tune.sh (or linuxlocker.sh tune) is an
ncurses UI that re-costs existing keyslots — shows the measured unlock time
and what each cost buys against a GPU fleet, backs the header up first, and
never touches data, passphrases, or keyslot existence. It also converts
leftover pbkdf2 keyslots to argon2id.
| Path | What it is |
|---|---|
bin/linuxlocker.sh |
Start here. Detects the live OS + package manager, installs core dependencies, dispatches to the other scripts (deploy / tune / post / bundle). |
bin/luks-deploy.sh |
The main event. In-place LUKS2 encryption, run from a live USB. Auto-detects everything, resolves boot partitions from the target's fstab, self-repairs failed initramfs steps, fixes SELinux labels, and gates the reboot behind verification. Fully resumable. |
bin/lib-deps.sh |
Shared OS / package-manager detection, dependency installer, and the Fedora Asahi Remix guard (sourced, not run). |
bin/lib-uki.sh |
UKI / systemd-boot / Secure Boot support (sourced, not run): finds EFI/Linux/*.efi across every ESP layout, picks the rebuild backend and the signer, rebuilds and signs, and reads the .cmdline and .initrd sections back out of a PE binary. UKI_DRY=1 prints the commands instead of running them. |
bin/luks-tune.sh |
ncurses KDF re-costing for existing LUKS2 volumes. --dry-run prints the command and changes nothing. |
bin/post-encryption-setup.sh |
Run once on the newly-encrypted system: recovery bundle, snapper subvolumes (btrfs roots), splash-argument restore, verification. Idempotent. |
bin/save-luks-recovery-bundle.sh |
Labeled recovery bundle: fresh header backup + crypttab/fstab/boot state + a README with distro-specific repair commands. Key material — never attach it to a bug report. |
bin/linuxlocker-diag.sh |
Read-only diagnostic bundle for bug reports, as Markdown you can paste straight into an issue: tool inventory, lsblk -f, Secure Boot state, the target's boot configuration, the baked-in .cmdline of every UKI and its signature status, what LinuxLocker's own detection thinks it found, public LUKS header metadata, and the relevant journal lines. UUIDs truncated by default. Also reachable as linuxlocker.sh diag. |
extras/ |
Optional: luks-fetch-cache, a disk-encryption status readout for fastfetch (LUKS and BitLocker volumes — KDF, cipher, protectors; public header metadata only). Its install.sh also installs fastfetch itself if missing. |
tests/loopback-core-test.sh |
CI-safe loopback test of the whole core: shrink guards, reencrypt, resume, hard-kill repair, recovery keys, the ext4 path, and LUKS1→LUKS2 conversion. Touches no real disk, and runs on every push against x86_64 and aarch64 runners. |
tests/uki-fixture-test.sh |
CI-safe fixture test of the UKI / systemd-boot / Secure Boot logic: every ESP layout, every rebuild backend, every signer, the refusal matrix, .cmdline round-trips through a real PE binary, and the Asahi guard. Needs no root and no disk. Run it as root on a UKI machine and section 10 also self-checks detection against that real system. |
docs/ |
ABOUT · INSTALL · FILESYSTEMS · RECOVERY |
SECURITY.md |
What is in scope, what is not, and what never to attach to a bug report — the artefacts this tool produces can be the keys themselves. |
.github/rulesets/ |
Branch and tag protection as JSON, not as settings someone clicked once: main and every v* tag are protected from deletion and force-push. |
- Cipher:
aes-xts-plain64, 512-bit key (AES-256-XTS) — the modern default for disk encryption, hardware-accelerated on both x86_64 (AES-NI) and aarch64 (ARMv8 Crypto Extensions). - KDF: argon2id, pinned per profile (
--pbkdf-force-iterations, no time-benchmark drift between fleet machines). - Hash: sha512 (AF splitter + LUKS2 digest).
- Resilience:
checksum— the in-place re-encryption is journaled, so power loss mid-run is recoverable by re-running the script.
LUKS_PROFILE=aggressive|moderate|fast pick a KDF preset, skip the menu
LUKS_PBKDF_MEMORY / _ITER / _PARALLEL pin exact KDF numbers (floor-checked)
LUKS_TARGET_ROOT / _BOOT / _EFI pin partitions, skip the menus
LUKS_PASSPHRASE_FILE=<path> non-interactive passphrase
LUKS_RECOVERY_KEY=yes|no recovery keyslot without prompting
LUKS_MAPPER_NAME=<name> device-mapper name (default root_crypt)
LUKS_KEEP_SPLASH=1 don't strip rhgb/quiet/splash
LUKS_DRY_RUN=1 (or --dry-run) plan only, change nothing
LUKS_SKIP_VERSION_CHECK=1 bypass the cryptsetup >= 2.4 floor
LUKS_ALLOW_UKI=1 proceed past the two UKI refusals
LUKS_UKI_REGEN=<backend> force the UKI rebuild backend:
mkinitcpio|kernel-install|dracut|ukify
LUKS_UKI_SIGN=<backend> force the signer: sbctl|sbsign|none
LUKS_SB_KEY / LUKS_SB_CERT explicit sbsign key + certificate
LUKS_SKIP_UKI_SIGN=1 rebuild the UKI but do not sign it
LUKS_SB_STATE=enabled|disabled override Secure Boot autodetection
The UKI and Secure Boot knobs are documented in full, with detection order and key-discovery paths, in BOOTLOADERS.md.
- A live/rescue Linux environment for the target machine (the target distro's own live ISO is the safest bet). The script hard-refuses to run from the installed system without a typed override.
cryptsetup≥ 2.4 in the live environment (in-place reencryption).- On a UKI target:
binutils(forobjcopy) in the live environment, so the.cmdlineand.initrdsections can be read back and verified. Without it those checks report SKIP rather than passing silently. - AC power for laptops — the script checks and warns.
- A verified backup. In-place encryption is irreversible the moment it starts.
The manual route — cryptsetup reencrypt followed by editing crypttab,
fstab, the kernel cmdline and your bootloader's config yourself — works, and
there are guides for it. What this kit adds is the part those guides leave to
you, and the part that differs on every distro:
Manual cryptsetup reencrypt |
LinuxLocker | |
|---|---|---|
| Partition selection | You identify root/boot/EFI yourself | Auto-detected and fstype-checked; boot and ESP resolved from the target's own fstab, and your pick cross-checked against it |
| Filesystem shrink | You pick the right resize tool and the right size | Per-filesystem handler (ext2/3/4, btrfs, xfs, f2fs, ntfs, vfat), 32 MiB gap, idempotent re-run detection |
| Which distro is this? | You already know, and follow the matching guide | Detected from the target's own artefacts — derivatives inherit support without being named |
| KDF parameters | cryptsetup auto-benchmarks — machine-dependent, and picks sha256 |
Pinned argon2id + sha512, identical on every box, chosen from a menu benchmarked on your hardware, with a hard floor |
| Boot config | You edit crypttab, fstab, cmdline, GRUB defaults, BLS entries, cmdline.txt or extlinux.conf by hand |
All of them rewritten, for whichever ones this target actually uses |
| Initramfs | dracut -f / mkinitcpio -P / update-initramfs -u, and hope the module is in |
Every image rebuilt in a chroot, then checked for cryptsetup/dm-crypt and self-repaired if missing |
| UKI / Secure Boot | You discover after the reboot that the .efi still has the old command line baked in, or that rebuilding it broke the signature |
The .efi is rebuilt with the right backend after the cmdline is final, re-signed with sbctl/sbsign, and its .cmdline section read back to prove it |
| Did it work? | You find out at reboot | Verification gate refuses the reboot until it passes; a check that does not apply reports SKIP, never a silent pass |
| Interrupted run | You debug the header state yourself | Detected and resumed automatically; cryptsetup repair path handled |
| Undo / recovery | Whatever you thought to save | Header backups plus a labeled bundle of every changed file, with distro-specific repair commands |
If you want to understand what it changes before trusting it, --dry-run
prints every action, including the exact cryptsetup invocation, and changes
nothing.
- Power loss or a crash mid-encryption leaves a half-encrypted disk. The LUKS2 journal + checksum resilience make this recoverable — re-run the script — but only if you don't panic-format anything first.
- A wrong partition selection is catastrophic. The script cross-checks your
selection against the target's own fstab and makes you type
ENCRYPT, but the final authority is you. - Forgetting the passphrase (or a Caps-Locked passphrase — the script checks the LED state and warns) with no recovery key enrolled means the data is gone. That is the feature working as designed.
- On LUKS1 systems where GRUB itself unlocks the disk (encrypted
/boot,cryptomount), converting keyslots to argon2id would make the system unbootable — the conversion flow warns and gates on this explicitly.
Yes — that is the entire point of this tool. cryptsetup reencrypt --encrypt
converts an existing filesystem into a LUKS2 container in place. LinuxLocker
automates that plus every boot-configuration change it forces, and refuses to
let you reboot until the result verifies.
Yes. The partition gains an encryption layer; the filesystem inside it is the same filesystem, with the same UUID. btrfs subvolumes and snapshots come through untouched. The script re-reads the inner filesystem type and UUID after encryption and fails the run if either changed.
Support is keyed off what is actually installed on the target, never off the distro's name, so derivatives inherit it from their family: Fedora / RHEL / Rocky / AlmaLinux (dnf, dracut, BLS), Debian / Ubuntu / Mint / Pop!_OS (apt, initramfs-tools), Arch / Manjaro / EndeavourOS (pacman, mkinitcpio), openSUSE (zypper, dracut), and Raspberry Pi OS. Alpine, Void and Gentoo are recognized by the dependency installer. See Supported systems.
Yes. Raspberry Pi OS is handled as a first-class target — the root= line in
cmdline.txt is rewritten and auto_initramfs=1 set — and ARM boards using
U-Boot distro-boot get their extlinux.conf APPEND line rewritten. Note that
the aggressive KDF profile wants ~6 GiB of free RAM at every unlock; the
installer warns on small-memory machines and refuses outright any profile whose
memory cost exceeds the machine's RAM.
Because it rewrites the filesystem it would otherwise be running from. The
script hard-refuses to run from the installed system without a typed override.
Any live or rescue Linux for your machine works; the target distro's own live
ISO is the safest choice, since its cryptsetup and filesystem tools already
match the target.
pbkdf2 is CPU-only, which is exactly what a GPU cracking fleet is good at.
argon2id is memory-hard, so an attacker has to buy RAM per guess, not just
cores. All three profiles are argon2id, and the cheapest of them is a hard
floor with no override flag — the tool exists to beat a bare luksFormat, not
to undercut it. luks-tune.sh also converts leftover pbkdf2 keyslots on
volumes you encrypted earlier.
The root volume is unlocked by the initramfs, which can afford a real argon2id
cost. An encrypted /boot has to be unlocked by GRUB, which is far more
constrained — and weakening the KDF to fit the bootloader trades a strong
defence for a partial one. If your system already has GRUB unlocking an
encrypted /boot (cryptomount), the LUKS1 conversion flow explicitly gates
on that, because argon2id keyslots are ones GRUB cannot open at all.
LUKS2 re-encryption is journaled with checksum resilience. Re-run the script:
it detects the online-reencrypt flag, runs cryptsetup repair first if the
journal is dirty, finishes the re-encryption, and then redoes the configuration
work. The one way to lose the disk here is to panic-format it before re-running.
Yes, both, as of 1.2.0.
systemd-boot is detected from the loader binary on the ESP rather than
inferred from /boot/loader/entries, so it works with the ESP mounted at
/efi, /boot/efi or /boot, with or without a separate XBOOTLDR partition.
Type #1 entries get the LUKS arguments, and check V13 refuses the reboot unless
something systemd-boot can actually boot points at the encrypted root.
A UKI is rebuilt. The kernel command line and the initramfs are baked into
the .efi, so editing /etc/kernel/cmdline and rebuilding the standalone
initramfs — which is all any generic guide does — changes nothing about what the
firmware loads. LinuxLocker detects which tool owns the .efi on your target
(an mkinitcpio preset with _uki=, kernel-install with layout=uki,
dracut --uki-file, or ukify), rebuilds it after the kernel command line
is final, and then reads the .cmdline section back out to prove the LUKS
arguments are in there. That last check, V11, is the one whose absence made the
old failure silent.
It still refuses before touching the disk if no rebuild backend exists, or if Secure Boot is on and nothing can sign the result. See BOOTLOADERS.md.
Yes, and it handles the part that is easy to get wrong.
Without a UKI — shim + GRUB, or shim + systemd-boot — there is nothing to do:
the initramfs is not part of the verified chain, and LinuxLocker never touches
shim, the bootloader binary or vmlinuz. Rebuilding the initramfs is invisible
to Secure Boot.
With a UKI, the .efi is the signed object, so rebuilding it invalidates the
signature and the firmware will refuse to load the result. LinuxLocker re-signs
it with sbctl or sbsign, then verifies the signature before allowing the
reboot (check V12). This matters more than it sounds: on Arch and Manjaro,
signing normally happens through zz-sbctl.hook, which is a libalpm hook —
it fires on pacman transactions, not when something runs mkinitcpio -P
directly. Any tool that rebuilds your UKI without being a package manager leaves
it unsigned unless it signs it deliberately.
pesign/NSS signing is detected but not implemented: the certificate nickname
and NSS database cannot be discovered reliably from a chroot, and a silently
unsigned .efi is exactly the failure this is meant to prevent. Those targets
are refused with an explanation.
No. LinuxLocker enrolls a passphrase and, optionally, a recovery keyslot. TPM2 enrollment, PCR sealing and network-bound unlock are features it does not implement — you type the passphrase at boot. Secure Boot signing (above) is a separate thing and is handled.
No — use AsahiLocker. It does the
same job with the Apple Silicon boot guards LinuxLocker deliberately drops.
Both linuxlocker.sh and luks-deploy.sh detect Fedora Asahi Remix and exit
with a link before touching any device, so running the wrong one by mistake
costs you nothing.
Yes. Every prompt has an LUKS_* environment variable behind it — see
Environment knobs. Pin
LUKS_PBKDF_MEMORY / _ITER / _PARALLEL for reproducible KDF cost across a
fleet rather than per-machine benchmark drift; pinned values below the floor are
fatal rather than silently raised, precisely so the numbers you pinned are the
numbers you get.
Yes. If the selected partition has no /etc/fstab inside it, the script offers
data-partition mode: encrypt, enroll a recovery key, back up the header, and
skip all boot configuration.
Only if it already has at least 32 MiB of free space at the end of the
partition, because xfs cannot be shrunk. The script checks for that slack and
declines rather than guessing. docs/FILESYSTEMS.md has
the full matrix and the workarounds for xfs, exfat, udf and swap.
Yes, without re-encrypting anything. sudo ./bin/luks-tune.sh re-costs existing
keyslots to a stronger argon2id profile, backs the header up first, and never
touches data, passphrases or keyslot existence. A LUKS1 volume is offered an
in-place conversion to LUKS2 first.
sudo cryptsetup luksDump /dev/<your-root-partition> prints the cipher, the
KDF and its parameters. It shows no key material and is safe to paste into a
bug report — unlike --dump-master-key, which is not. extras/luks-fetch-cache
turns the same information into a one-line-per-volume fastfetch readout.
| Doc | Covers |
|---|---|
| ABOUT.md | What the project is, who it is for, what it deliberately does not do |
| INSTALL.md | Step-by-step install, start to finish, with what each prompt means |
| FILESYSTEMS.md | Every filesystem classified: shrinkable in place, slack-only, or not at all — with workarounds |
| RECOVERY.md | Interrupted encryption, unbootable system, corrupt header, undoing a shrink |
| BOOTLOADERS.md | Which boot machinery is actually written, and where systemd-boot, UKIs and Secure Boot stand |
| SECURITY.md | Scope, reporting, and what never to attach to a bug report |
| CODE_OF_CONDUCT.md | Expected conduct in issues and pull requests |
| CONTRIBUTING.md | What this project accepts, the diagnostic bundle, and what a filesystem handler must do |
This project takes serious bugs and new filesystem support, and nothing else. Refactors, new options and general feature requests will be declined regardless of quality — every added code path here is a path that can lose someone's disk, and there is one maintainer to be sure it does not. CONTRIBUTING.md has the full scope, the read-only diagnostic bundle, and what a filesystem handler has to do to merge.
Test reports are wanted as much as bug reports. Every UKI, systemd-boot and Secure Boot path is verified by fixtures in CI but has not been through a full encrypt-and-reboot cycle on real hardware, and neither have xfs, f2fs, ntfs, the Raspberry Pi and U-Boot boot stacks, or aarch64 hardware. CONTRIBUTING.md has the table of what is still unconfirmed; a report that a configuration worked is the only way a row gets ticked.
Because this tooling rewrites a live root filesystem and its bootloader, a description of what went wrong is rarely enough to act on. Say which distro you ran it from and which distro you ran it against — those are different code paths through the same script — and attach the diagnostic bundle:
sudo ./bin/linuxlocker-diag.sh -o linuxlocker-report.mdIt is read-only, it redacts UUIDs by default, and it deliberately excludes everything that would be key material. Read it before posting anyway.
Before opening a pull request, run what CI runs:
shellcheck -S warning $(git ls-files '*.sh') extras/bin/luks-fetch-cache
sudo bash tests/loopback-core-test.sh
bash tests/uki-fixture-test.shExpect 29 passed, 0 failed from the loopback suite and 0 failed from the
fixture suite. The loopback suite exercises the whole encryption core — shrink
guards, in-place re-encryption, --resume-only, a hard kill mid-re-encrypt
followed by cryptsetup repair, recovery keys, the ext4 path and LUKS1 → LUKS2
conversion — against file-backed loop devices. The fixture suite exercises the
UKI, systemd-boot and Secure Boot decision logic against synthetic target trees.
Neither touches a real disk, and both run on every push against x86_64 and
aarch64 runners. A SKIP in loopback stage 5b is normal and lowers the count
without any failure; 0 failed is the invariant.
Every shell script in the repository is shellcheck -S warning clean and must
stay that way — this is a pure shell-script project with no runtime
dependencies beyond the tools a sysadmin already has on a rescue USB, and
that is deliberate: a recovery tool that needs a language runtime installed is a
recovery tool you cannot use from a minimal live environment.
Security issues do not belong in the issue tracker. Read SECURITY.md first: the recovery key, the header backups and the recovery bundle are key material, not diagnostics.
MIT — see LICENSE.
- Version: 1.2.0
- Author: William MacKinnon (doug445)
- Email: spilled-bowline0j@icloud.com
- Repository: https://github.com/doug445/LinuxLocker
Copyright (c) 2026 William MacKinnon <spilled-bowline0j@icloud.com>