Files
relicario/CLAUDE.md

3.1 KiB

CLAUDE.md — idfoto

What is this

idfoto is a git-backed, self-hostable password manager with a Rust core. Two-factor vault decryption: passphrase + a reference JPEG carrying a 256-bit secret embedded via DCT steganography. The server only ever sees opaque ciphertext.

Build and test

cargo build                    # build everything
cargo test                     # run all tests (unit + integration)
cargo test -p idfoto-core      # core library tests only
cargo run -- --help            # CLI help
cargo run -- generate -l 32   # quick smoke test

Project structure

crates/
├── idfoto-core/        # Platform-agnostic library (no filesystem, no git, no network)
│   ├── src/
│   │   ├── lib.rs      # Re-exports public API
│   │   ├── error.rs    # IdfotoError enum (thiserror)
│   │   ├── crypto.rs   # Argon2id KDF + XChaCha20-Poly1305 encrypt/decrypt
│   │   ├── entry.rs    # Entry, ManifestEntry, Manifest structs (serde)
│   │   ├── vault.rs    # encrypt_entry, decrypt_entry, encrypt_manifest, decrypt_manifest
│   │   └── imgsecret.rs # DCT-based 256-bit secret embedding in JPEGs
│   └── tests/
│       └── integration.rs  # Full-workflow and two-factor independence tests
└── idfoto-cli/         # CLI binary
    └── src/
        └── main.rs     # clap CLI: init, add, get, list, edit, rm, sync, generate, device

Key design decisions

  • idfoto-core is bytes-in/bytes-out. No filesystem, no network, no git operations. Makes it portable to WASM, Android, iOS.
  • XChaCha20-Poly1305 over AES-GCM — 192-bit nonce eliminates collision risk, fast in WASM/ARM without AES-NI.
  • Single master_key (no per-entry subkeys) — simpler, sufficient for family vault sizes.
  • imgsecret uses central-embed DCT — embeds only in the middle 70% of the image (15% crumple zone for crop tolerance), with majority voting across 5-50 redundant copies.
  • QUANT_STEP = 50.0 — higher than typical (25) to survive JPEG recompression down to Q85.
  • Device ed25519 keys are separate from the KDF. Revoking a device doesn't require rotating the passphrase or reference image.

Crypto pipeline

passphrase (UTF-8 bytes) || image_secret (32 bytes from reference JPEG)
  → Argon2id(salt=vault_salt, m=64MiB, t=3, p=4)
  → master_key (32 bytes)
  → XChaCha20-Poly1305(nonce=random 24 bytes)
  → encrypted entry/manifest

Conventions

  • Tests use fast Argon2id params (m=256, t=1, p=1) so they don't take forever.
  • Test JPEGs are generated synthetically via make_test_jpeg() — no binary test fixtures.
  • Entry IDs are random 8-char hex strings.
  • Git history is preserved as an audit log — no squashing.
  • The CLI shells out to git for sync — no libgit2/gitoxide dependency.

Remote

Source code: ssh://git@git.adlee.work:2222/alee/idfoto.git

Design spec

Full threat model, entropy analysis, and architecture: docs/superpowers/specs/2026-04-11-idfoto-design.md

Roadmap

Next: WASM build + Chrome MV3 browser extension (Plan 2). Then mobile (Rust core compiles to ARM).