docs(12-02): complete password-based key derivation plan
- Add 12-02-SUMMARY.md with execution results - Update STATE.md: Phase 12 complete, 15/15 plans done - Update ROADMAP.md: Phase 12 progress to complete - Mark KEY-03, KEY-04, KEY-05, KEY-06 requirements complete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -101,10 +101,10 @@
|
|||||||
|
|
||||||
- [x] **KEY-01**: CLI аргумент `--key <HEX>` — 64 символа hex, декодируется в 32-байтный AES-256 ключ
|
- [x] **KEY-01**: CLI аргумент `--key <HEX>` — 64 символа hex, декодируется в 32-байтный AES-256 ключ
|
||||||
- [x] **KEY-02**: CLI аргумент `--key-file <PATH>` — чтение ровно 32 байт из файла как raw ключ
|
- [x] **KEY-02**: CLI аргумент `--key-file <PATH>` — чтение ровно 32 байт из файла как raw ключ
|
||||||
- [ ] **KEY-03**: CLI аргумент `--password [VALUE]` — интерактивный промпт (rpassword) или значение из CLI
|
- [x] **KEY-03**: CLI аргумент `--password [VALUE]` — интерактивный промпт (rpassword) или значение из CLI
|
||||||
- [ ] **KEY-04**: Argon2id KDF — деривация 32-байтного ключа из пароля + 16-байтный random salt
|
- [x] **KEY-04**: Argon2id KDF — деривация 32-байтного ключа из пароля + 16-байтный random salt
|
||||||
- [ ] **KEY-05**: Хранение salt в архиве — flags bit 4 (0x10), 16-байтный salt между header и TOC при pack
|
- [x] **KEY-05**: Хранение salt в архиве — flags bit 4 (0x10), 16-байтный salt между header и TOC при pack
|
||||||
- [ ] **KEY-06**: Чтение salt из архива при unpack/inspect — автоматическое определение по flags bit 4
|
- [x] **KEY-06**: Чтение salt из архива при unpack/inspect — автоматическое определение по flags bit 4
|
||||||
- [x] **KEY-07**: Один из `--key`, `--key-file`, `--password` обязателен для pack/unpack; inspect принимает ключ опционально
|
- [x] **KEY-07**: Один из `--key`, `--key-file`, `--password` обязателен для pack/unpack; inspect принимает ключ опционально
|
||||||
|
|
||||||
## Future Requirements
|
## Future Requirements
|
||||||
@@ -194,10 +194,10 @@
|
|||||||
| TST-07 | Phase 11 | Pending |
|
| TST-07 | Phase 11 | Pending |
|
||||||
| KEY-01 | Phase 12 | Complete |
|
| KEY-01 | Phase 12 | Complete |
|
||||||
| KEY-02 | Phase 12 | Complete |
|
| KEY-02 | Phase 12 | Complete |
|
||||||
| KEY-03 | Phase 12 | Pending |
|
| KEY-03 | Phase 12 | Complete |
|
||||||
| KEY-04 | Phase 12 | Pending |
|
| KEY-04 | Phase 12 | Complete |
|
||||||
| KEY-05 | Phase 12 | Pending |
|
| KEY-05 | Phase 12 | Complete |
|
||||||
| KEY-06 | Phase 12 | Pending |
|
| KEY-06 | Phase 12 | Complete |
|
||||||
| KEY-07 | Phase 12 | Complete |
|
| KEY-07 | Phase 12 | Complete |
|
||||||
|
|
||||||
**Coverage:**
|
**Coverage:**
|
||||||
|
|||||||
@@ -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.
|
**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
|
**Requirements**: KEY-01, KEY-02, KEY-03, KEY-04, KEY-05, KEY-06, KEY-07
|
||||||
**Depends on:** Phase 11
|
**Depends on:** Phase 11
|
||||||
**Plans:** 1/2 plans executed
|
**Plans:** 2/2 plans complete
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 12-01-PLAN.md -- CLI key args (--key, --key-file, --password), refactor archive.rs to accept key parameter, update all tests
|
- [ ] 12-01-PLAN.md -- CLI key args (--key, --key-file, --password), refactor archive.rs to accept key parameter, update all tests
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: Directory Support
|
milestone_name: Directory Support
|
||||||
status: in-progress
|
status: complete
|
||||||
last_updated: "2026-02-26T20:53:36Z"
|
last_updated: "2026-02-26T21:01:33Z"
|
||||||
progress:
|
progress:
|
||||||
total_phases: 12
|
total_phases: 12
|
||||||
completed_phases: 9
|
completed_phases: 12
|
||||||
total_plans: 15
|
total_plans: 15
|
||||||
completed_plans: 14
|
completed_plans: 15
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -18,22 +18,22 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-02-25)
|
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
|
**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
|
## Current Position
|
||||||
|
|
||||||
Phase: 12 of 12 (User Key Input)
|
Phase: 12 of 12 (User Key Input) -- COMPLETE
|
||||||
Plan: 1 of 2 -- COMPLETE
|
Plan: 2 of 2 -- COMPLETE
|
||||||
Status: Phase 12 Plan 01 complete, --key and --key-file support added
|
Status: Phase 12 complete, all three key input methods (--key, --key-file, --password) functional
|
||||||
Last activity: 2026-02-26 -- Phase 12 Plan 01 executed (CLI key input + archive refactor)
|
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
|
## Performance Metrics
|
||||||
|
|
||||||
**Velocity:**
|
**Velocity:**
|
||||||
- Total plans completed: 14
|
- Total plans completed: 15
|
||||||
- Average duration: 3.6 min
|
- Average duration: 3.7 min
|
||||||
- Total execution time: 0.9 hours
|
- Total execution time: 0.9 hours
|
||||||
|
|
||||||
| Phase | Plan | Duration | Tasks | Files |
|
| Phase | Plan | Duration | Tasks | Files |
|
||||||
@@ -42,6 +42,7 @@ Progress: [##############......] 70% (14/~20 plans estimated)
|
|||||||
| 08-01 | Rust Directory Archiver | 6 min | 3 | 4 |
|
| 08-01 | Rust Directory Archiver | 6 min | 3 | 4 |
|
||||||
| 09-01 | Kotlin Decoder Update | 2 min | 2 | 2 |
|
| 09-01 | Kotlin Decoder Update | 2 min | 2 | 2 |
|
||||||
| 12-01 | CLI Key Input | 5 min | 2 | 8 |
|
| 12-01 | CLI Key Input | 5 min | 2 | 8 |
|
||||||
|
| 12-02 | Argon2id KDF + Salt | 5 min | 2 | 6 |
|
||||||
|
|
||||||
## Accumulated Context
|
## 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: 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: LEGACY_KEY kept as #[cfg(test)] for golden test vectors
|
||||||
- v1.2: All archive functions parameterized by explicit key (no global state)
|
- 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
|
### Pending Todos
|
||||||
|
|
||||||
@@ -87,5 +92,5 @@ None.
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-02-26
|
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
|
Resume file: None
|
||||||
|
|||||||
113
.planning/phases/12-user-key-input/12-02-SUMMARY.md
Normal file
113
.planning/phases/12-user-key-input/12-02-SUMMARY.md
Normal file
@@ -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*
|
||||||
Reference in New Issue
Block a user