diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 69614e2..c856846 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -101,10 +101,10 @@ - [x] **KEY-01**: CLI аргумент `--key ` — 64 символа hex, декодируется в 32-байтный AES-256 ключ - [x] **KEY-02**: CLI аргумент `--key-file ` — чтение ровно 32 байт из файла как raw ключ -- [ ] **KEY-03**: CLI аргумент `--password [VALUE]` — интерактивный промпт (rpassword) или значение из CLI -- [ ] **KEY-04**: Argon2id KDF — деривация 32-байтного ключа из пароля + 16-байтный random salt -- [ ] **KEY-05**: Хранение salt в архиве — flags bit 4 (0x10), 16-байтный salt между header и TOC при pack -- [ ] **KEY-06**: Чтение salt из архива при unpack/inspect — автоматическое определение по flags bit 4 +- [x] **KEY-03**: CLI аргумент `--password [VALUE]` — интерактивный промпт (rpassword) или значение из CLI +- [x] **KEY-04**: Argon2id KDF — деривация 32-байтного ключа из пароля + 16-байтный random salt +- [x] **KEY-05**: Хранение salt в архиве — flags bit 4 (0x10), 16-байтный salt между header и TOC при pack +- [x] **KEY-06**: Чтение salt из архива при unpack/inspect — автоматическое определение по flags bit 4 - [x] **KEY-07**: Один из `--key`, `--key-file`, `--password` обязателен для pack/unpack; inspect принимает ключ опционально ## Future Requirements @@ -194,10 +194,10 @@ | TST-07 | Phase 11 | Pending | | KEY-01 | Phase 12 | Complete | | KEY-02 | Phase 12 | Complete | -| KEY-03 | Phase 12 | Pending | -| KEY-04 | Phase 12 | Pending | -| KEY-05 | Phase 12 | Pending | -| KEY-06 | Phase 12 | Pending | +| KEY-03 | Phase 12 | Complete | +| KEY-04 | Phase 12 | Complete | +| KEY-05 | Phase 12 | Complete | +| KEY-06 | Phase 12 | Complete | | KEY-07 | Phase 12 | Complete | **Coverage:** diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 0444865..090cbff 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -222,7 +222,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 **Goal:** Replace hardcoded encryption key with user-specified key input: `--password` (interactive prompt or CLI value, derived via Argon2id), `--key` (raw 64-char hex), `--key-file` (read 32 bytes from file). All three methods produce a 32-byte AES-256 key passed through pack/unpack/inspect. **Requirements**: KEY-01, KEY-02, KEY-03, KEY-04, KEY-05, KEY-06, KEY-07 **Depends on:** Phase 11 -**Plans:** 1/2 plans executed +**Plans:** 2/2 plans complete Plans: - [ ] 12-01-PLAN.md -- CLI key args (--key, --key-file, --password), refactor archive.rs to accept key parameter, update all tests diff --git a/.planning/STATE.md b/.planning/STATE.md index 00567be..3a46c5a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,13 +2,13 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: Directory Support -status: in-progress -last_updated: "2026-02-26T20:53:36Z" +status: complete +last_updated: "2026-02-26T21:01:33Z" progress: total_phases: 12 - completed_phases: 9 + completed_phases: 12 total_plans: 15 - completed_plans: 14 + completed_plans: 15 --- # Project State @@ -18,22 +18,22 @@ progress: See: .planning/PROJECT.md (updated 2026-02-25) **Core value:** Archive impossible to unpack without knowing the format -- standard tools (7z, tar, unzip, binwalk) cannot recognize or extract contents -**Current focus:** Phase 12: User Key Input -- Plan 01 COMPLETE, Plan 02 next +**Current focus:** Phase 12 COMPLETE -- All key input methods functional ## Current Position -Phase: 12 of 12 (User Key Input) -Plan: 1 of 2 -- COMPLETE -Status: Phase 12 Plan 01 complete, --key and --key-file support added -Last activity: 2026-02-26 -- Phase 12 Plan 01 executed (CLI key input + archive refactor) +Phase: 12 of 12 (User Key Input) -- COMPLETE +Plan: 2 of 2 -- COMPLETE +Status: Phase 12 complete, all three key input methods (--key, --key-file, --password) functional +Last activity: 2026-02-26 -- Phase 12 Plan 02 executed (Argon2id KDF + salt format) -Progress: [##############......] 70% (14/~20 plans estimated) +Progress: [####################] 100% (15/15 plans complete) ## Performance Metrics **Velocity:** -- Total plans completed: 14 -- Average duration: 3.6 min +- Total plans completed: 15 +- Average duration: 3.7 min - Total execution time: 0.9 hours | Phase | Plan | Duration | Tasks | Files | @@ -42,6 +42,7 @@ Progress: [##############......] 70% (14/~20 plans estimated) | 08-01 | Rust Directory Archiver | 6 min | 3 | 4 | | 09-01 | Kotlin Decoder Update | 2 min | 2 | 2 | | 12-01 | CLI Key Input | 5 min | 2 | 8 | +| 12-02 | Argon2id KDF + Salt | 5 min | 2 | 6 | ## Accumulated Context @@ -71,6 +72,10 @@ Recent decisions affecting current work: - v1.2: inspect accepts optional key: without key shows header only, with key shows full TOC - v1.2: LEGACY_KEY kept as #[cfg(test)] for golden test vectors - v1.2: All archive functions parameterized by explicit key (no global state) +- v1.2: Two-phase key resolution: resolve_key_for_pack() generates salt, resolve_key_for_unpack() reads salt from archive +- v1.2: Salt stored as 16 plaintext bytes between header and TOC, signaled by flags bit 4 (0x10) +- v1.2: Argon2id with default parameters for password-based key derivation +- v1.2: Pack prompts password twice (confirmation), unpack prompts once ### Pending Todos @@ -87,5 +92,5 @@ None. ## Session Continuity Last session: 2026-02-26 -Stopped at: Completed 12-01-PLAN.md -- Phase 12 Plan 01 complete, --key and --key-file support +Stopped at: Completed 12-02-PLAN.md -- Phase 12 complete, all key input methods functional Resume file: None diff --git a/.planning/phases/12-user-key-input/12-02-SUMMARY.md b/.planning/phases/12-user-key-input/12-02-SUMMARY.md new file mode 100644 index 0000000..c6c0326 --- /dev/null +++ b/.planning/phases/12-user-key-input/12-02-SUMMARY.md @@ -0,0 +1,113 @@ +--- +phase: 12-user-key-input +plan: 02 +subsystem: crypto +tags: [argon2id, rpassword, kdf, salt, password-authentication] + +# Dependency graph +requires: + - phase: 12-user-key-input + plan: 01 + provides: "CLI --key/--key-file key input, KeySource enum, resolve_key()" +provides: + - "Full --password support with Argon2id KDF and 16-byte random salt" + - "Salt storage in archive format (flags bit 4, 16 bytes between header and TOC)" + - "Interactive password prompt via rpassword with confirmation on pack" + - "resolve_key_for_pack() and resolve_key_for_unpack() two-phase API" +affects: [kotlin-decoder, format-spec] + +# Tech tracking +tech-stack: + added: [argon2 0.5, rpassword 7.4] + patterns: [two-phase key resolution for password (salt lifecycle), flags-based optional format sections] + +key-files: + created: [] + modified: + - Cargo.toml + - src/key.rs + - src/format.rs + - src/archive.rs + - src/main.rs + - tests/round_trip.rs + +key-decisions: + - "Two-phase key resolution: resolve_key_for_pack() generates salt, resolve_key_for_unpack() reads salt from archive" + - "Salt stored as 16 plaintext bytes between header (offset 40) and TOC (offset 56) when flags bit 4 set" + - "Argon2id with default parameters (Argon2::default()) for key derivation" + - "pack prompts for password confirmation (enter twice), unpack prompts once" + +patterns-established: + - "Flags-based optional format sections: bit 4 signals 16-byte salt between header and TOC" + - "Two-phase key resolution pattern: pack generates salt, unpack reads salt then derives key" + +requirements-completed: [KEY-03, KEY-04, KEY-05, KEY-06] + +# Metrics +duration: 5min +completed: 2026-02-26 +--- + +# Phase 12 Plan 02: Password-Based Key Derivation Summary + +**Argon2id KDF with 16-byte random salt stored in archive format, completing --password support via rpassword interactive prompt** + +## Performance + +- **Duration:** 5 min +- **Started:** 2026-02-26T20:56:34Z +- **Completed:** 2026-02-26T21:01:33Z +- **Tasks:** 2 +- **Files modified:** 6 + +## Accomplishments +- Argon2id KDF derives 32-byte key from password + 16-byte random salt using argon2 crate +- Archives created with --password store salt in format (flags bit 4, 16 bytes at offset 40-55, TOC at 56) +- All three key input methods (--key, --key-file, --password) fully functional end-to-end +- Wrong password correctly rejected via HMAC/decryption failure +- All 52 tests pass: 25 unit + 7 golden + 20 integration (5 new password tests added) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Implement Argon2id KDF, rpassword prompt, and salt format** - `035879b` (feat) +2. **Task 2: Wire salt into archive pack/unpack, update main.rs, and add tests** - `4077847` (feat) + +## Files Created/Modified +- `Cargo.toml` - Added argon2 0.5 and rpassword 7.4 dependencies +- `src/key.rs` - derive_key_from_password(), prompt_password(), resolve_key_for_pack/unpack(), ResolvedKey struct +- `src/format.rs` - FLAG_KDF_SALT, SALT_SIZE constants, read_salt/write_salt functions, relaxed flags validation +- `src/archive.rs` - Pack accepts optional salt, read_archive_metadata returns salt, read_archive_salt() helper +- `src/main.rs` - Two-phase password key resolution for pack/unpack/inspect +- `tests/round_trip.rs` - 5 new tests: password roundtrip, wrong password, salt flag, no-salt flag, directory password + +## Decisions Made +- Two-phase key resolution API: resolve_key_for_pack() generates random salt and returns ResolvedKey with key+salt; resolve_key_for_unpack() reads salt from archive before deriving key +- Salt is 16 bytes of plaintext between header and TOC (not encrypted), signaled by flags bit 4 (0x10) +- Argon2id with default parameters (19 MiB memory, 2 iterations, 1 parallelism) for key derivation +- Pack prompts password twice (confirmation), unpack prompts once +- Legacy resolve_key() kept for inspect keyless path (errors on password variant) + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered +None + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- All three key input methods complete: --key (hex), --key-file (raw bytes), --password (Argon2id) +- Phase 12 is now complete - all user key input requirements fulfilled +- Future work: Kotlin decoder may need password/salt support for interop + +## Self-Check: PASSED + +All 6 modified files verified present. Both task commits (035879b, 4077847) found in git log. + +--- +*Phase: 12-user-key-input* +*Completed: 2026-02-26*