Skip to content

Latest commit

 

History

History
547 lines (446 loc) · 17 KB

File metadata and controls

547 lines (446 loc) · 17 KB

AGENTS.md - Guide for AI Agents Working in EncFS

This document provides comprehensive information for AI agents working in the EncFS codebase. It covers commands, patterns, conventions, gotchas, and project-specific context.

Project Overview

EncFS is an encrypted virtual filesystem that runs in userspace using FUSE. This is a Rust port of the original C++ implementation, aiming for compatibility with existing EncFS filesystems while providing memory safety and modern code practices.

  • Language: Rust (Edition 2024)
  • Primary Goal: Read/write compatibility with legacy EncFS filesystems
  • Status: Alpha (v2.0.0-alpha.3) - functional for read/write but still maturing

Key Characteristics

  • Encrypts individual files (not block devices)
  • Uses FUSE for filesystem operations
  • Supports multiple config formats (V4, V5, V6)
  • OpenSSL for legacy cryptographic operations
  • Modern cryptography (AES-GCM-SIV, Argon2) for new setups
  • Internationalization support

Essential Commands

Build Commands

# Build debug binaries
cargo build
# or using task runner
task build

# Build release binaries
cargo build --release
# or
task build-release

# Clean build artifacts
cargo clean
# or
task clean

Testing Commands

# Run all tests (unit + integration, excluding live mount tests)
cargo test
# or
task test

# Run live mount tests (requires FUSE, Linux, and ENCFS_LIVE_TESTS=1)
ENCFS_LIVE_TESTS=1 cargo test --test live_mount -- --ignored --test-threads=1
# or
task test-live

# Run specific test
cargo test test_name

# Run tests with output
cargo test -- --nocapture

Important: Live mount tests (live_mount.rs) are marked with #[ignore] and require:

  • ENCFS_LIVE_TESTS=1 environment variable
  • FUSE kernel module loaded (sudo modprobe fuse)
  • Single-threaded execution (--test-threads=1)
  • Linux or FreeBSD (macOS support via fuse-t)

Code Quality Commands

# Format code
cargo fmt
# or
task fmt

# Check formatting (CI-friendly, doesn't modify files)
cargo fmt -- --check
# or
task fmt-check

# Run clippy lints (fails on warnings in CI)
cargo clippy --all-targets --all-features -- -D warnings
# or
task clippy

Running the Binaries

# Mount an encrypted filesystem
./target/debug/encfs /path/to/encrypted /path/to/mountpoint

# With options
./target/debug/encfs -f -v /path/to/encrypted /path/to/mountpoint

# Control utility
./target/debug/encfsctl info /path/to/encrypted
./target/debug/encfsctl decode /path/to/encrypted encrypted_filename
./target/debug/encfsctl cat /path/to/encrypted encrypted_filename

Installation

# Install to ~/.cargo/bin
cargo install --path .

Project Structure

encfs/
├── src/                      # Rust source code
│   ├── main.rs              # Main encfs binary (FUSE mount)
│   ├── encfsctl.rs          # Control utility binary
│   ├── lib.rs               # Library entry point
│   ├── config.rs            # Config file parsing (V4/V5/V6)
│   ├── config_binary.rs     # Binary config format parser
│   ├── constants.rs         # Global constants
│   ├── fs.rs                # FUSE filesystem implementation
│   └── crypto/              # Cryptographic operations
│       ├── mod.rs           # Crypto module exports
│       ├── ssl.rs           # OpenSSL cipher wrapper
│       └── file.rs          # File encryption/decryption
├── tests/                   # Integration tests
│   ├── fixtures/            # Test data (encrypted files)
│   ├── live_mount.rs        # Live FUSE mount tests (ignored by default)
│   └── *.rs                 # Other integration tests
├── locales/                 # i18n translation files (YAML)
│   ├── main.yml            # Main binary translations
│   ├── ctl.yml             # encfsctl translations
│   └── help.yml            # Help text translations
├── Cargo.toml              # Rust dependencies
├── Taskfile.yml            # Task runner config (alternative to make)
└── .github/workflows/      # CI configuration

Code Organization

Module Hierarchy

  1. lib.rs: Library entry point

    • Exports all public modules
    • Initializes i18n system
    • Contains integration tests
  2. config.rs: Configuration file handling

    • EncfsConfig: Main config struct
    • ConfigType: Enum for V3/V4/V5/V6 formats
    • Interface: Cipher/naming algorithm interface
    • Supports XML (V6) and binary (V4/V5) formats
    • XML uses Boost Serialization format for compatibility
  3. config_binary.rs: Binary config parser

    • ConfigReader: Reads V4/V5 binary configs
    • ConfigVar: Variable-length encoded values
  4. crypto/ namespace: Cryptographic operations

    • ssl.rs: OpenSSL cipher wrapper (legacy modes)
    • aead.rs / block.rs: Modern authenticated encryption (AES-GCM-SIV)
    • file.rs: File-level encryption, handles block boundaries, MACs, headers
  5. fs.rs: FUSE filesystem implementation

    • EncFs: Main filesystem struct
    • Implements FilesystemMT trait from fuse_mt
    • Path encryption/decryption with IV chaining
    • File handle management
    • All FUSE operations (read, write, readdir, etc.)
  6. main.rs: Main encfs binary

    • CLI argument parsing with clap
    • Password handling (prompt, stdin, extpass)
    • Daemonization support
    • FUSE mount setup
  7. encfsctl.rs: Control utility

    • Subcommands: info, passwd, decode, encode, cat, ls, showkey, export
    • Standalone utility for inspecting/manipulating encrypted filesystems

Naming Conventions

Rust Standard Conventions

  • Types/Structs/Enums: PascalCase (e.g., EncfsConfig, SslCipher)
  • Functions/Variables: snake_case (e.g., decrypt_filename, block_size)
  • Constants: SCREAMING_SNAKE_CASE (e.g., DEFAULT_SALT_SIZE)
  • Modules: snake_case (e.g., config_binary)

Project-Specific Naming

  • IV: Initialization Vector (used throughout crypto code)
  • MAC: Message Authentication Code
  • KDF: Key Derivation Function (PBKDF2)
  • Volume Key: The master key used to encrypt files (encrypted by user password)
  • User Key: Key derived from user password
  • File IV: Per-file initialization vector (stored in file header if unique_iv enabled)
  • Path IV: IV derived from path components (used with chained_name_iv)

File Naming

  • Test files: *_test.rs (e.g., write_test.rs)
  • Integration tests: Top-level in tests/ directory
  • Fixtures: tests/fixtures/ for test data

Testing Patterns

Test Organization

  1. Unit tests: #[cfg(test)] mod tests at bottom of source files
  2. Integration tests: Separate files in tests/ directory
  3. Live mount tests: tests/live_mount.rs with #[ignore] attribute

Common Test Patterns

// Integration test with fixtures
#[test]
fn test_decrypt_filenames() -> anyhow::Result<()> {
    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");
    let config_path = root.join("encfs6-std.xml");
    let config = EncfsConfig::load(&config_path)?;
    // ... test logic
    Ok(())
}

// Live mount test (ignored by default)
#[test]
#[ignore]
fn live_smoke_mount_unmount_standard() -> Result<()> {
    require_live();  // Checks ENCFS_LIVE_TESTS env var
    if !live_enabled() {
        return Ok(());
    }
    // ... test logic
    Ok(())
}

Test Fixtures

  • tests/fixtures/encfs6-std.xml: Standard mode config
  • tests/fixtures/encfs6-paranoia.xml: Paranoia mode config
  • tests/fixtures/MhAO8Ckgt67m1cSrFU9HHiNT: Encrypted file (decrypts to "DESIGN.md")
  • tests/fixtures/U,-Aj0Ha7VZMhbnuv-vx1DZu/: Encrypted directory (paranoia mode)

Running Tests in CI

  • GitHub Actions: .github/workflows/ci.yml
  • Cirrus CI: .cirrus.yml (FreeBSD testing)
  • CI runs: clippy, build, test, live_mount tests

Important Gotchas and Non-Obvious Patterns

1. Config Format Compatibility

  • V6 (XML): Current format, .encfs6.xml file
  • V5 (Binary): Legacy format, .encfs5 file - READ ONLY (save not implemented)
  • V4 (Binary): Older format, .encfs4 file - READ ONLY
  • V3: Not supported (will error)

The code must maintain compatibility with all three formats for reading existing filesystems.

2. IV Chaining Modes

Two types of IV chaining affect how paths are encrypted:

  • chained_name_iv: Each directory's IV is derived from parent's IV + encrypted name

    • Standard mode: enabled
    • Affects path encryption/decryption order
  • external_iv_chaining: File IVs are derived from path IV

    • Paranoia mode: enabled
    • Means file headers must be decrypted with path IV, not just 0

Critical: When decrypting files in paranoia mode, you MUST use the path IV from decrypt_path(), not 0!

3. File Structure

Encrypted files have this structure:

[Header: 8 bytes if unique_iv] [Block 0] [Block 1] ... [Block N]

Each block (if MACs enabled):

[MAC: block_mac_bytes] [Random: block_mac_rand_bytes] [Data: remaining]

Note: block_mac_rand_bytes is not yet supported (must be 0).

4. Filename Encryption

  • Base64 encoded (URL-safe variant without padding)
  • Uses stream cipher mode
  • IV is derived from HMAC of plaintext name (deterministic)
  • With chained_name_iv, also depends on parent directory's IV

5. Error Handling

  • Use anyhow::Result for application code
  • Use libc::c_int error codes for FUSE operations
  • Map Rust errors to errno values in fs.rs

6. Internationalization

  • Uses rust-i18n crate
  • Translations in locales/*.yml files
  • Macro: t!("key.subkey", param = value)
  • Locale initialized from LANG environment variable
  • Help text functions must return String (evaluated at runtime after locale init)

7. FUSE Integration

  • Uses fuse_mt crate (multi-threaded FUSE)
  • Implements FilesystemMT trait
  • File handles stored in HashMap<u64, Arc<FileHandle>>
  • Thread-safe via Mutex guards
  • Single-threaded mode available via -s flag

8. Password Handling

Three methods (in order of precedence):

  1. --extpass <program>: Run external program, read stdout
  2. --stdinpass: Read from stdin
  3. Default: Interactive prompt via rpassword

9. Validation Requirements

The EncfsConfig::validate() method enforces:

  • plain_data must be false (not supported)
  • unique_iv may be true or false (filesystem supports both)
  • block_mac_rand_bytes must be 0 (not implemented yet)
  • key_size must be positive and multiple of 8
  • block_size must be positive
  • block_mac_bytes must be 0-8
  • Block size must be larger than MAC overhead

10. Legacy C++ Code

  • Located in legacy/ directory
  • Uses CMake build system
  • May be removed in future
  • Useful for reference but not actively maintained
  • Do NOT modify legacy code unless explicitly requested

11. Logging

  • Uses env_logger crate
  • Controlled by RUST_LOG environment variable
  • -v flag sets debug level
  • -d flag sets debug + foreground mode

12. Daemonization

  • Uses daemonize crate
  • Automatic unless -f (foreground) or -d (debug) flag
  • Happens after password validation, before FUSE mount

Dependencies

Core Dependencies

  • fuse_mt (0.6.3): Multi-threaded FUSE bindings
  • openssl (0.10.75): Cryptographic operations
  • clap (4.5.57): CLI argument parsing
  • anyhow (1.0.101): Error handling
  • serde (1.0.228): Serialization/deserialization
  • quick-xml (0.39.0): XML parsing for V6 configs
  • base64 (0.22.1): Base64 encoding for filenames
  • rust-i18n (3): Internationalization
  • log (0.4.29) + env_logger (0.11.8): Logging
  • rpassword (7.4.0): Password prompts
  • daemonize (0.5): Background daemon support
  • libc (0.2.180): POSIX system calls
  • chrono (0.4): Date/time handling
  • argon2 (0.5) / aes-gcm-siv (0.11.1) / sha2 (0.10): Modern cryptography
  • prost (0.14.3): Protobuf serialization support

System Dependencies

  • FUSE: libfuse-dev (Linux), fusefs-libs (FreeBSD), fuse-t (macOS)
  • OpenSSL: libssl-dev
  • pkg-config: For finding system libraries

CI/CD

GitHub Actions (.github/workflows/ci.yml)

Runs on: ubuntu-latest Steps:

  1. Install dependencies (fuse, libfuse-dev, pkg-config, libssl-dev)
  2. Load fuse module
  3. Run clippy (fails on warnings)
  4. Build release
  5. Run tests
  6. Run live mount tests

Cirrus CI (.cirrus.yml)

Runs on: FreeBSD 15.0 Steps:

  1. Install Rust, FUSE, OpenSSL
  2. Load fusefs kernel module
  3. Build release
  4. Run tests
  5. Run live mount tests Status: allow_failures: true

Common Workflows

Adding a New Feature

  1. Implement in appropriate module (src/*.rs)
  2. Add unit tests in same file
  3. Add integration test in tests/ if needed
  4. Update translations in locales/*.yml if user-facing
  5. Run cargo fmt and cargo clippy
  6. Run cargo test
  7. Test manually with real encrypted filesystem

Fixing a Bug

  1. Add a failing test that reproduces the bug
  2. Fix the bug
  3. Verify test passes
  4. Check for similar issues elsewhere
  5. Run full test suite

Updating Dependencies

  1. Edit Cargo.toml
  2. Run cargo update
  3. Run full test suite
  4. Check for deprecation warnings with clippy

Adding Translations

  1. Add keys to locales/main.yml, locales/ctl.yml, or locales/help.yml
  2. Provide translations for en, fr, de
  3. Use t!("key.subkey") macro in code
  4. For clap help text, create helper function returning String

Security Considerations

Known Weaknesses (Inherited from EncFS Design)

See ISSUES.md for detailed analysis. Key issues:

  • 64-bit IVs (should be 128-bit)
  • 64-bit MACs (should be 128-bit+)
  • Same key for encryption and authentication
  • Stream cipher for last file block
  • File holes not authenticated
  • Information leakage between decryption and MAC check

Note: These are protocol-level issues that can't be fixed without breaking compatibility. The Rust port inherits these limitations.

Implementation Security

  • Rust's memory safety prevents many C++ vulnerabilities
  • Use anyhow::Result to ensure errors are handled
  • Avoid unwrap() in production code paths
  • Use ? operator for error propagation
  • Validate all config values in EncfsConfig::validate()

Performance Notes

  • Block size affects performance (default 4096 bytes for new filesystems)
  • MACs/Tags add overhead per block + performance penalty (~16 bytes for AES-GCM-SIV)
  • Multi-threaded FUSE by default (use -s for single-threaded debugging)
  • File buffer size: 128 KB (FILE_BUFFER_SIZE)
  • Performance over NFS is known to be poor (upstream issue)

Debugging Tips

Enable Debug Logging

RUST_LOG=debug ./target/debug/encfs -f /encrypted /mount

Run in Foreground

./target/debug/encfs -f /encrypted /mount

Single-threaded Mode (easier debugging)

./target/debug/encfs -s -f /encrypted /mount

Inspect Config

./target/debug/encfsctl info /encrypted

Decode Filenames

./target/debug/encfsctl decode /encrypted encrypted_filename

Decrypt File Contents

./target/debug/encfsctl cat /encrypted encrypted_filename

Check FUSE Module

lsmod | grep fuse
sudo modprobe fuse  # if not loaded

Unmount

fusermount -u /mount  # Linux
umount /mount         # macOS/FreeBSD

Code Style

General Rust Style

  • Follow Rust standard style (enforced by cargo fmt)
  • Use rustfmt.toml if present (currently uses defaults)
  • Max line length: 100 characters (Rust default)
  • Use clippy recommendations (CI fails on warnings)

Project-Specific Style

  • Prefer anyhow::Result over Result<T, E> in application code
  • Use ? operator for error propagation
  • Add context to errors: .context("description")?
  • Log errors before returning them from FUSE operations
  • Use debug!, info!, warn!, error! macros for logging
  • Document public APIs with /// doc comments
  • Use // for implementation comments

Error Handling in FUSE Operations

fn some_fuse_op(&self, path: &Path) -> ResultEntry {
    let (encrypted_path, iv) = self.encrypt_path(path).map_err(|e| {
        error!("Failed to encrypt path: {}", e);
        e  // Return errno
    })?;
    // ... rest of implementation
}

Additional Resources

  • README.md: Project overview and status
  • DESIGN.md: Technical overview of EncFS encryption
  • INSTALL.md: Build and installation instructions
  • Cargo.toml: Dependencies and metadata
  • Taskfile.yml: Available task commands

Quick Reference

Most Common Commands

cargo build              # Build
cargo test               # Test
cargo clippy             # Lint
cargo fmt                # Format
task test-live           # Live mount tests

Most Important Files

  • src/fs.rs: FUSE implementation
  • src/config.rs: Config parsing
  • src/crypto/ssl.rs: Cryptography
  • tests/live_mount.rs: Integration tests

Most Common Issues

  1. Live tests fail: Check ENCFS_LIVE_TESTS=1 and FUSE module loaded
  2. Build fails on OpenSSL: Install libssl-dev
  3. Build fails on FUSE: Install libfuse-dev

Last Updated: February 21, 2026 EncFS Version: 2.0.0-alpha.3 Rust Edition: 2024