CryptoFS is a Linux kernel module that provides transparent, per-file AES-256-GCM encryption at the VFS layer. Inspired by Thales CipherTrust Transparent Encryption (CTE), it allows applications to read and write files normally while all data is encrypted on the underlying storage — no application changes required.
Authorized processes see plaintext. Unauthorized processes see raw ciphertext or are blocked from writing. Access is governed by per-process policies based on UID, GID, binary path, binary hash, or process name.
- Key Features
- Architecture
- Project Structure
- How It Works
- Encryption Details
- Prerequisites
- Building
- Quick Start
- Key Management
- Access Policies
- Docker Integration
- Testing
- Benchmarking
- Development Environment (macOS)
- Configuration Reference
- Security Considerations
- Troubleshooting
- License
- Transparent encryption — applications need no modifications; encryption and decryption happen at the VFS layer, invisible to userspace
- AES-256-GCM — authenticated encryption via the Linux kernel Crypto API; detects tampering through per-extent GCM authentication tags
- Per-file encryption keys — each file gets a unique 256-bit File Encryption Key (FEK), wrapped by a master key; compromising one FEK does not expose other files
- 4 KB extent-based processing — encryption operates on page-aligned 4096-byte extents, enabling efficient random access without decrypting entire files
- Per-process access control — fine-grained policies by UID, GID, executable path, binary SHA-256 hash, or process name
- Full VFS operation support — sequential I/O, random-access reads/writes, append, truncate, mmap, rename, symlinks, hardlinks
- Stacked filesystem — mounts on top of any existing filesystem (ext4, xfs, btrfs, etc.) without reformatting
- Docker compatible — mount encrypted volumes into containers via host bind mounts
- Key management daemon — local keystore with Argon2id-protected master keys; architecture supports extension to external KMS (HashiCorp Vault, AWS KMS, etc.)
- Audit logging — kernel ring-buffer audit trail for all access events, policy changes, and key operations
- Comprehensive test suite — integration tests, multi-section stress test with SHA-256 data integrity verification, fio benchmarks, and Docker container tests
┌─────────────────────────────────────────────────────────────────┐
│ Userspace │
│ │
│ ┌──────────────┐ ┌───────────────┐ ┌─────────────────┐ │
│ │ cryptofs- │ │ cryptofs-keyd │ │ Applications │ │
│ │ admin (CLI) │ │ (daemon) │ │ (any process) │ │
│ └──────┬───────┘ └──────┬────────┘ └───────┬─────────┘ │
│ │ netlink │ keyring │ syscalls │
│ ═══════╪═══════════════════╪═════════════════════╪═══════════ │
│ │ Kernel │ │ │
│ ┌──────┴───────────────────┴─────────────────────┴──────────┐ │
│ │ cryptofs.ko (stacked filesystem) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
│ │ │ Policy │ │ Crypto │ │ Netlink │ │ │
│ │ │ Engine │ │ Engine │ │ Interface │ │ │
│ │ └─────────────┘ └──────────────┘ └─────────────────┘ │ │
│ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │
│ │ │ VFS Ops │ │ Inode/File │ │ Audit Ring │ │ │
│ │ │ (stacked) │ │ Management │ │ Buffer │ │ │
│ │ └─────────────┘ └──────────────┘ └─────────────────┘ │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ Lower Filesystem (ext4 / xfs / btrfs / ...) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- Applications issue normal POSIX file operations (
open,read,write, etc.) - cryptofs.ko intercepts these via VFS and checks the policy engine against the calling process
- For authorized processes: data passes through the crypto engine (AES-256-GCM encrypt on write, decrypt on read) before reaching the lower filesystem
- For unauthorized processes: reads return raw ciphertext; writes are denied with
EACCES - cryptofs-keyd manages master keys in userspace, injecting them into the kernel keyring via the netlink interface
- cryptofs-admin provides the administrator CLI for key lifecycle, policy management, mount/unmount, status, and audit queries
encrypted_fs/
├── kernel/ # Linux kernel module (C)
│ ├── cryptofs.h # Main header — data structures, constants, prototypes
│ ├── main.c # Module init/exit, filesystem type registration
│ ├── super.c # Superblock operations (mount, umount, statfs)
│ ├── dentry.c # Dentry operations (revalidate, release)
│ ├── lookup.c # Lookup and inode instantiation
│ ├── file.c # File operations (read, write, open, release, fsync, llseek)
│ ├── inode.c # Inode operations (create, mkdir, unlink, rename, etc.)
│ ├── crypto.c # AES-256-GCM encrypt/decrypt, FEK wrap/unwrap, nonce derivation
│ ├── mmap.c # Memory-mapped I/O support (readpage, writepage)
│ ├── policy.c # Per-process access control policy engine
│ ├── netlink.c # Generic netlink interface for userspace communication
│ ├── audit.c # Kernel ring-buffer audit logging
│ └── Makefile # Out-of-tree kernel module build
│
├── daemon/ # Key management daemon (Rust)
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # Daemon entry point, signal handling, socket server
│ ├── keystore.rs # Encrypted key storage with Argon2id key derivation
│ ├── provider.rs # KMS provider trait + local implementation
│ ├── keyring.rs # Linux kernel keyring integration
│ ├── api.rs # Unix socket API (JSON-RPC style)
│ └── audit.rs # Daemon-side audit logging
│
├── cli/ # Admin CLI (Rust)
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # CLI entry point, argument parsing (clap)
│ └── commands/
│ ├── mod.rs # Command dispatch
│ ├── mount.rs # mount / umount subcommands
│ ├── key.rs # key generate / list / unlock / activate / rotate / session-unlock
│ ├── policy.rs # policy add / list / remove
│ ├── status.rs # status display
│ └── audit.rs # audit log query
│
├── tools/
│ ├── set_key.c # Inject master key into kernel via netlink
│ └── add_policy.c # Add access policy via netlink (with key_id + access_mode)
│
├── tests/
│ ├── integration/
│ │ ├── test_basic_ops.sh # 18 tests: CRUD, permissions, symlinks, large files
│ │ ├── test_random_access.sh # 6 tests: seek, partial reads, extent boundaries
│ │ ├── test_append.sh # 5 tests: append, mixed append+read
│ │ ├── test_concurrent.sh # 4 tests: parallel writes/reads, file locking
│ │ ├── test_policy_uid.sh # UID policy enforcement
│ │ ├── test_guarded_key.sh # 9 tests: guarded access mode (session keyring)
│ │ ├── test_docker.sh # 5 tests: container access, auth/unauth
│ │ └── test_stress.sh # 10-section exhaustive data integrity validation
│ └── bench/
│ ├── run_fio.sh # fio sequential/random read/write benchmarks
│ └── compare_results.py # Encrypted vs. baseline performance comparison
│
├── docker/
│ ├── Dockerfile.test # Test container (Ubuntu 24.04 + fio + tools)
│ ├── docker-compose.yml # Services: test-basic, test-bench, baseline, auth/unauth
│ └── test_entrypoint.sh # Container test entry point
│
├── vagrant/
│ ├── Vagrantfile # QEMU ARM64 Ubuntu 24.04 VM with HVF
│ └── provision.sh # Installs kernel headers, Rust, Docker, fio, convenience scripts
│
├── docs/
│ ├── encryption-format.md # On-disk format specification (header, extents, nonces)
│ └── admin-guide.md # Administration guide (keys, policies, Docker, troubleshooting)
│
├── Makefile # Top-level build orchestration (40+ targets)
├── build_and_test.sh # Full pipeline: build → test → stress → report
└── how_to_run_and_test.md # Detailed testing and run guide
CryptoFS is a stacked (or overlay) filesystem, similar to eCryptfs and wrapfs. It registers as a Linux filesystem type (cryptofs) and mounts on top of an existing directory:
sudo mount -t cryptofs /data/encrypted /mnt/decryptedThe lower directory (/data/encrypted) contains the actual encrypted files. The upper mount (/mnt/decrypted) presents the decrypted view to authorized processes. CryptoFS intercepts all VFS operations and transforms data between the two layers.
Authorized write:
write() → VFS → cryptofs → policy check ✓ → split into 4 KB extents
→ AES-256-GCM encrypt each extent → write ciphertext + GCM tags to lower filesystem
Authorized read:
read() → VFS → cryptofs → policy check ✓ → read encrypted extents from lower filesystem
→ AES-256-GCM decrypt + verify GCM tag → return plaintext to application
Unauthorized read:
read() → VFS → cryptofs → policy check ✗ → return raw ciphertext (no decryption)
Unauthorized write:
write() → VFS → cryptofs → policy check ✗ → return -EACCES (denied)
- Cipher: AES-256-GCM (via Linux kernel Crypto API)
- Key size: 256 bits (32 bytes)
- Nonce size: 96 bits (12 bytes)
- Auth tag: 128 bits (16 bytes) per extent
Master Key (256-bit, stored encrypted by daemon with Argon2id)
└── wraps (AES-256-GCM) → File Encryption Key (FEK, 256-bit, unique per file)
└── derives (HMAC-SHA256) → Per-extent nonce (96-bit)
- Master key is stored on disk encrypted with a passphrase via Argon2id key derivation. It is unlocked into daemon memory, then injected into the kernel keyring when activated.
- FEK is randomly generated when a file is created. It is stored in the file header, wrapped (encrypted) by the master key.
- Per-extent nonce is derived deterministically:
HMAC-SHA256(FEK, inode_number || extent_index)truncated to 12 bytes. This guarantees nonce uniqueness without storing nonces on disk.
┌────────────────────────────┐ Offset 0
│ File Header (128 B) │
├────────────────────────────┤ Offset 128
│ Extent 0: Ciphertext │ 4096 bytes
│ Extent 0: Auth Tag │ 16 bytes
├────────────────────────────┤ Offset 4240
│ Extent 1: Ciphertext │ 4096 bytes
│ Extent 1: Auth Tag │ 16 bytes
├────────────────────────────┤
│ ... │
├────────────────────────────┤
│ Extent N: Ciphertext │ ≤ 4096 bytes (last may be partial)
│ Extent N: Auth Tag │ 16 bytes
└────────────────────────────┘
File header fields (128 bytes):
| Offset | Size | Field |
|---|---|---|
| 0 | 8 | Magic: "CRYPTOFS" |
| 8 | 4 | Version (1) |
| 12 | 4 | Flags |
| 16 | 48 | Encrypted FEK (32-byte key + 16-byte GCM tag) |
| 64 | 12 | FEK wrapping nonce |
| 76 | 8 | Logical (plaintext) file size |
| 84 | 44 | Reserved |
Offset translation: For logical offset L, the lower file offset is 128 + (L / 4096) * 4112 + (L % 4096).
Storage overhead: 128 bytes per file + 16 bytes per 4 KB extent (~0.4% for a 1 MB file).
For the complete on-disk format specification, see docs/encryption-format.md.
- Linux kernel 6.1+ with headers installed and
CONFIG_CRYPTO_AES+CONFIG_CRYPTO_GCMenabled - GCC and standard build tools (
build-essential) - Rust 1.75+ (for the daemon and CLI)
- Docker 20.10+ (optional, for container tests)
- fio 3.0+ (optional, for benchmarks)
- Python 3.8+ (optional, for benchmark comparison)
For macOS development, see Development Environment (macOS).
make all # builds kernel module + daemon + CLI (release)make kernel # kernel module (cryptofs.ko)
make daemon # key daemon (daemon/target/release/cryptofs-keyd)
make cli # admin CLI (cli/target/release/cryptofs-admin)sudo make installInstalls cryptofs.ko to the kernel modules directory, cryptofs-keyd and cryptofs-admin to /usr/local/bin/, and creates configuration directories under /etc/cryptofs/, /var/lib/cryptofs/, /var/run/cryptofs/, and /var/log/cryptofs/.
make clean# 1. Build everything
make all
# 2. Load the kernel module
sudo insmod kernel/cryptofs.ko
# 3. Start the key daemon
sudo daemon/target/release/cryptofs-keyd --foreground &
# 4. Generate and activate a master key
cli/target/release/cryptofs-admin key generate --label my-key
cli/target/release/cryptofs-admin key unlock <key-id>
cli/target/release/cryptofs-admin key activate <key-id>
# 5. Mount
mkdir -p /tmp/cryptofs_lower /tmp/cryptofs_mount
sudo mount -t cryptofs /tmp/cryptofs_lower /tmp/cryptofs_mount
# 6. Use it — files written to /tmp/cryptofs_mount are encrypted on disk
echo "secret data" > /tmp/cryptofs_mount/test.txt
cat /tmp/cryptofs_mount/test.txt # → "secret data" (authorized)
cat /tmp/cryptofs_lower/test.txt # → encrypted binary (on disk)Or use the convenience target:
make quickstartCryptoFS uses a two-tier key architecture managed by the cryptofs-keyd daemon.
# Generate a new master key (stored encrypted on disk)
cryptofs-admin key generate --label production-key-1
# List all keys
cryptofs-admin key list
# Unlock a key (decrypt into daemon memory)
cryptofs-admin key unlock <key-id>
# Activate (inject into kernel keyring — now usable by the module)
cryptofs-admin key activate <key-id>
# Rotate (generate new key material, re-wrap existing FEKs)
cryptofs-admin key rotate <key-id>
# Deactivate (revoke from kernel)
cryptofs-admin key deactivate <key-id> --serial <serial>
# Lock (clear from daemon memory)
cryptofs-admin key lock <key-id>cryptofs-admin key import --label imported --hex <64-char-hex-string>
cryptofs-admin key import --label imported --file /path/to/key.hexcryptofs-keyd [OPTIONS]
--socket <path> Unix socket (default: /var/run/cryptofs/keyd.sock)
--key-dir <path> Key storage (default: /var/lib/cryptofs/keys)
--audit-log <path> Audit log (default: /var/log/cryptofs/keyd.log)
--pid-file <path> PID file (default: /var/run/cryptofs/keyd.pid)
--foreground Don't daemonize
--log-level <level> trace | debug | info | warn | error
When policies are configured, CryptoFS defaults to deny — only explicitly allowed processes get plaintext access. When no policies exist, all processes have access (proof-of-concept convenience mode).
| Type | Matches on | Example |
|---|---|---|
uid |
User ID | --value 1000 |
gid |
Group ID | --value 100 |
binary-path |
Executable path | --value /usr/bin/myapp |
binary-hash |
SHA-256 of executable | --value <hex-hash> |
process-name |
Process comm | --value nginx |
# Allow UID 1000
cryptofs-admin policy add --dir /mnt/decrypted --type uid --value 1000 --perm allow
# Allow a specific binary
cryptofs-admin policy add --dir /mnt/decrypted --type binary-path \
--value /usr/bin/myapp --perm allow
# Allow by tamper-resistant binary hash
SHA=$(sha256sum /usr/bin/myapp | awk '{print $1}')
cryptofs-admin policy add --dir /mnt/decrypted --type binary-hash \
--value $SHA --perm allow
# List all policies
cryptofs-admin policy list
# Remove a policy
cryptofs-admin policy remove <rule-id>CryptoFS v2 supports multiple master keys (up to 64) with two access models that control how the kernel resolves key material at runtime.
| Mode | Key source | Use case |
|---|---|---|
| Transparent (default) | Kernel key table | Admin pre-loads keys; all authorized processes share them automatically |
| Guarded | Process session keyring | Each user unlocks their own key; only that user's processes can decrypt |
The admin activates keys into the kernel key table. Any process matching a policy rule bound to that key gets automatic decryption:
# Admin loads key into the kernel key table
cryptofs-admin key unlock <key-id>
cryptofs-admin key activate <key-id>
# All authorized processes decrypt automatically — no per-user action neededThis is the default behavior and is backward compatible with v1 (single-key) configurations.
The key must be present in the calling process's Linux session keyring. The kernel resolves it at file-open time via request_key():
# Step 1: User unlocks the key into their own session keyring
cryptofs-admin key session-unlock <key-id>
# → CLI prompts for passphrase
# → Daemon validates passphrase, returns key material
# → CLI calls add_key("logon", "cryptofs:<key_id_hex>", key_data, SESSION_KEYRING)
# Step 2: User's processes can now decrypt files bound to that key
cat /mnt/decrypted/secret.txt # → plaintext (key found in session keyring)
# Step 3: Key can be revoked or will expire after optional timeout
cryptofs-admin key session-unlock <key-id> --timeout 3600 # auto-expire in 1 hourHow it works under the hood:
- Process opens a file → kernel's
cryptofs_open()runs - Policy engine matches the process (e.g. by UID) → returns
key_id+access_mode = GUARDED - Kernel calls
request_key(&key_type_logon, "cryptofs:<key_id_hex>", NULL) - Linux keyring subsystem searches the process's session keyring
- If found → FEK is unwrapped → file is decrypted
- If not found →
ENOKEY→ file open fails or returns ciphertext
Each policy rule can optionally specify a key_id and access_mode:
# Transparent: admin manages the key, user auto-decrypts
cryptofs-admin policy add --dir /mnt/decrypted \
--type uid --value 1000 --perm allow \
--key-id a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
--access-mode transparent
# Guarded: user must unlock their own key
cryptofs-admin policy add --dir /mnt/decrypted \
--type uid --value 2000 --perm allow \
--key-id f7e2a1b3-0000-0000-0000-000000000000 \
--access-mode guardedThe kernel maintains an in-memory key table (up to 64 entries). Keys are added via the SET_KEY netlink command (typically by cryptofs-admin key activate). The table maps 16-byte key IDs to 256-bit master keys.
- V1 files have
key_id = all-zerosin their header → maps to the default key - No policies configured → allow-all with default key + transparent mode (PoC convenience)
SET_KEYwithoutkey_id→ stores as the default key (all-zeros ID)
Mount CryptoFS on the host, then bind-mount the decrypted view into containers:
# Host
sudo mount -t cryptofs /data/encrypted /mnt/decrypted
# Container sees decrypted data
docker run -v /mnt/decrypted:/data myappThe docker/ directory provides pre-built test containers:
make docker-build # build test containers
make docker-test # run basic file operation tests in container
make docker-bench # run fio benchmarks (encrypted + baseline)Container services defined in docker/docker-compose.yml:
| Service | Description |
|---|---|
test-basic |
Basic file ops through encrypted mount |
test-bench |
fio benchmarks on encrypted filesystem |
baseline-bench |
fio benchmarks without encryption (baseline) |
authorized |
Container running as UID 1000 (policy-allowed) |
unauthorized |
Container running as UID 65534 (should see ciphertext) |
CryptoFS has an extensive multi-tier test suite. See how_to_run_and_test.md for detailed instructions.
# Unit tests (Rust daemon)
make daemon-test
# All integration tests
make test
# Stress test (data integrity, 10 sections, SHA-256 verified)
make test-stress # medium intensity
make test-stress-light # light
make test-stress-heavy # heavy (up to 500 MB files)
# Docker container tests
make test-docker
# Full automated pipeline (build → unit → mount → integration → stress → report)
make full-test # medium stress
make full-test-heavy # heavy stress
make full-test-all # heavy + Docker + benchmarks| Suite | Tests | What it validates |
|---|---|---|
test_basic_ops.sh |
18 | Create, read, write, truncate, rename, delete, permissions, symlinks, hardlinks, large files |
test_random_access.sh |
6 | Seek, partial reads, overwrite at offset, extent-boundary I/O |
test_append.sh |
5 | Append, mixed append+read, multi-append |
test_concurrent.sh |
4 | Parallel writes, parallel reads, mixed r/w, file locking |
test_policy_uid.sh |
— | UID-based access policy enforcement |
test_guarded_key.sh |
9 | Guarded access mode: session keyring inject/revoke/re-inject |
test_docker.sh |
5 | Container read/write, auth/unauth containers, volume persistence |
test_stress.sh |
10 sections | Graduated sizes (0 B–500 MB), patterns, extent boundaries, overwrites, appends, random-offset patches, concurrent workers, file churn, unmount/remount persistence, large-file streaming |
A single script that orchestrates the complete build-and-test workflow:
- Build kernel module, daemon, CLI
- Run daemon unit tests
- Load module, start daemon, mount CryptoFS
- Run all integration test suites
- Run the data integrity stress test
- (Optional) Docker tests and fio benchmarks
- Tear down mount, unload module, kill daemon
- Print a full pass/fail report
./build_and_test.sh
./build_and_test.sh --stress heavy --include-docker --include-bench# Run fio benchmarks (sequential and random I/O)
make bench
# Compare encrypted vs. baseline performance
make bench-compare
# Docker-based benchmarks (both encrypted and native)
make docker-benchBenchmark results are written to docker/results/ when using Docker Compose.
Since cryptofs.ko is a Linux kernel module, it cannot compile or run on macOS. The project includes a Vagrant-managed QEMU VM for development:
# Prerequisites (Homebrew)
brew install vagrant qemu
vagrant plugin install vagrant-qemu
# Start the VM (ARM64 Ubuntu 24.04, 4 GB RAM, 4 CPUs, HVF acceleration)
make vm-up
# SSH into the VM
make vm-ssh
# Project is synced via rsync to /home/vagrant/cryptofs
# All build dependencies are pre-installedThe Vagrant VM provisions:
- Linux kernel headers for the running kernel
- GCC, make, libelf-dev, libssl-dev, flex, bison, bc
- Rust toolchain (via rustup)
- Docker
- fio, strace, ltrace, jq, tree
- Convenience scripts:
cryptofs-build,cryptofs-load,cryptofs-test-mount
make vm-up # start VM
make vm-ssh # SSH into VM
make vm-halt # suspend VM
make vm-destroy # delete VM| Target | Description |
|---|---|
make all |
Build kernel module + daemon + CLI (release) |
make kernel |
Build kernel module only |
make daemon |
Build daemon (release) |
make cli |
Build CLI (release) |
make daemon-debug |
Build daemon (debug) |
make cli-debug |
Build CLI (debug) |
make install |
Install all components system-wide |
make clean |
Remove all build artifacts |
make test |
Run unit + integration tests |
make test-stress |
Run stress test (medium) |
make test-stress-light |
Run stress test (light) |
make test-stress-heavy |
Run stress test (heavy) |
make test-policy |
Run policy enforcement tests |
make test-docker |
Run Docker container tests |
make full-test |
Full pipeline (build + all tests) |
make full-test-heavy |
Full pipeline with heavy stress |
make full-test-all |
Full pipeline + Docker + benchmarks |
make bench |
Run fio benchmarks |
make bench-compare |
Compare benchmark results |
make docker-build |
Build Docker test containers |
make docker-test |
Run Docker tests |
make docker-bench |
Run Docker benchmarks |
make quickstart |
Load module, start daemon, generate key |
make check |
Static analysis (sparse + clippy) |
make fmt |
Format Rust code |
make vm-up |
Start Vagrant VM |
make vm-ssh |
SSH into Vagrant VM |
make vm-halt |
Suspend Vagrant VM |
make vm-destroy |
Delete Vagrant VM |
| Variable | Default | Used by |
|---|---|---|
LOWER_DIR |
/tmp/cryptofs_lower |
build_and_test.sh, test scripts |
MOUNT_DIR |
/tmp/cryptofs_mount |
build_and_test.sh, test scripts |
STRESS_LEVEL |
medium |
test_stress.sh, build_and_test.sh |
NUM_WORKERS |
8 |
test_stress.sh, build_and_test.sh |
KDIR |
/lib/modules/$(uname -r)/build |
Kernel module Makefile |
CRYPTOFS_MOUNT |
/tmp/cryptofs_mount |
Docker Compose |
BASELINE_DIR |
/tmp/cryptofs_baseline |
Docker Compose |
- Threat model: CryptoFS protects data at rest on the underlying storage. An attacker with access to the raw disk or lower directory sees only ciphertext. It does not protect against a compromised kernel or root access on a running system with keys loaded.
- GCM authentication: Every 4 KB extent has a GCM authentication tag. Tampering with ciphertext is detected at read time, preventing silent corruption.
- Nonce safety: Nonces are derived deterministically via HMAC-SHA256, not stored. This avoids nonce-reuse bugs but means overwriting the same extent with the same data produces the same ciphertext (this is acceptable for a storage encryption layer).
- Key protection: Master keys are stored encrypted on disk with Argon2id key derivation. They are held in daemon memory only while unlocked and in the kernel keyring only while activated.
- Policy enforcement: Policies are enforced in kernel space. Binary-hash policies are resistant to binary replacement attacks. Process-name policies are weaker (processes can set
comm). - Memory safety: The kernel module is written in C and operates in ring 0. The Rust userspace components (daemon, CLI) benefit from Rust's memory safety guarantees.
Module won't load
- Check
dmesg | tail -20for detailed error messages - Verify kernel headers match the running kernel:
uname -rvs.ls /lib/modules/ - Ensure kernel crypto support:
grep -o aes /proc/cpuinfoand checkCONFIG_CRYPTO_AES,CONFIG_CRYPTO_GCMin kernel config
Decryption failures / GCM tag mismatch
- Verify the correct master key is activated:
cryptofs-admin key list - Check
dmesgfor "GCM auth tag mismatch" messages - The lower filesystem may have corruption — run
fsck
Daemon won't start
- Check for existing instances:
pgrep cryptofs-keyd - Remove stale socket:
rm /var/run/cryptofs/keyd.sock - Run with debug logging:
cryptofs-keyd --foreground --log-level debug
Integration tests fail
- Ensure CryptoFS is mounted:
mountpoint /tmp/cryptofs_mount - Use
build_and_test.shwhich handles all setup/teardown automatically
Performance issues
- Verify AES hardware acceleration:
grep aes /proc/cpuinfo - Run
make benchandmake bench-compareto measure overhead - Ensure
CONFIG_CRYPTO_AES_ARM64_CEor equivalent is enabled for hardware-accelerated AES
macOS: "not Linux" warnings
- This is expected — kernel module operations require Linux
- Use
make vm-sshto enter the Vagrant QEMU VM, then run builds and tests there
GPL-2.0 — see individual source file headers for details.