219 lines
9.6 KiB
Markdown
219 lines
9.6 KiB
Markdown
---
|
|
phase: 03-round-trip-verification
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on: ["03-01"]
|
|
files_modified:
|
|
- tests/golden.rs
|
|
- tests/round_trip.rs
|
|
autonomous: true
|
|
requirements: [INT-02, TST-01, TST-02]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Golden test vectors pass: AES-256-CBC encryption of 'Hello' with project KEY and fixed IV produces exact expected ciphertext (cross-verified with openssl)"
|
|
- "Golden test vectors pass: HMAC-SHA256 of IV||ciphertext produces exact expected hash"
|
|
- "Golden test vectors pass: SHA-256 of 'Hello' matches known value from FORMAT.md"
|
|
- "Round-trip pack->unpack produces byte-identical files for: single text file, multiple files, empty file, Cyrillic filename, large (11MB) binary"
|
|
- "cargo test --test golden passes all golden vector tests"
|
|
- "cargo test --test round_trip passes all integration tests"
|
|
artifacts:
|
|
- path: "tests/golden.rs"
|
|
provides: "Golden test vectors with fixed IV/key for deterministic verification"
|
|
contains: "test_golden_aes256cbc"
|
|
- path: "tests/round_trip.rs"
|
|
provides: "CLI round-trip integration tests via assert_cmd"
|
|
contains: "test_roundtrip"
|
|
key_links:
|
|
- from: "tests/golden.rs"
|
|
to: "src/crypto.rs"
|
|
via: "use encrypted_archive::crypto"
|
|
pattern: "encrypted_archive::crypto"
|
|
- from: "tests/golden.rs"
|
|
to: "src/key.rs"
|
|
via: "use encrypted_archive::key::KEY"
|
|
pattern: "encrypted_archive::key::KEY"
|
|
- from: "tests/round_trip.rs"
|
|
to: "encrypted_archive binary"
|
|
via: "Command::cargo_bin(\"encrypted_archive\")"
|
|
pattern: "cargo_bin.*encrypted_archive"
|
|
---
|
|
|
|
<objective>
|
|
Implement golden test vectors (TST-02) and CLI round-trip integration tests (INT-02, TST-01) that prove byte-identical round-trips for all edge cases.
|
|
|
|
Purpose: Golden vectors prove the crypto implementation matches the spec (cross-verifiable with openssl). Round-trip tests prove the full pack->unpack pipeline preserves file content exactly. Together they satisfy the Phase 3 success criteria.
|
|
|
|
Output: `tests/golden.rs` with fixed-IV crypto tests, `tests/round_trip.rs` with CLI integration tests for all edge cases.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/nick/.claude/get-shit-done/workflows/execute-plan.md
|
|
@/home/nick/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/03-round-trip-verification/03-RESEARCH.md
|
|
@.planning/phases/03-round-trip-verification/03-01-SUMMARY.md
|
|
@docs/FORMAT.md
|
|
@src/crypto.rs
|
|
@src/key.rs
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create golden test vectors with fixed IV/key</name>
|
|
<files>tests/golden.rs</files>
|
|
<action>
|
|
Create `tests/golden.rs` with deterministic golden test vectors. These call library functions directly with fixed IVs (NOT via CLI which uses random IVs).
|
|
|
|
Import:
|
|
```rust
|
|
use encrypted_archive::{crypto, key::KEY};
|
|
use hex_literal::hex;
|
|
```
|
|
|
|
**Test 1: `test_golden_aes256cbc_hello`**
|
|
Encrypt "Hello" (5 bytes) with project KEY and IV = `00000000000000000000000000000001`.
|
|
Expected ciphertext: `hex!("6e66ae8bc740efeefe83b5713fcb716f")` (16 bytes -- verified with openssl in research).
|
|
```rust
|
|
let iv = hex!("00000000000000000000000000000001");
|
|
let ciphertext = crypto::encrypt_data(b"Hello", &KEY, &iv);
|
|
assert_eq!(ciphertext, hex!("6e66ae8bc740efeefe83b5713fcb716f").to_vec());
|
|
```
|
|
|
|
**Test 2: `test_golden_aes256cbc_decrypt_hello`**
|
|
Decrypt the ciphertext from Test 1 back to "Hello". Verifies round-trip with the exact golden vector.
|
|
```rust
|
|
let iv = hex!("00000000000000000000000000000001");
|
|
let ciphertext = hex!("6e66ae8bc740efeefe83b5713fcb716f");
|
|
let plaintext = crypto::decrypt_data(&ciphertext, &KEY, &iv).unwrap();
|
|
assert_eq!(plaintext, b"Hello");
|
|
```
|
|
|
|
**Test 3: `test_golden_aes256cbc_empty`**
|
|
Encrypt empty slice with KEY and IV = zero. Expected: 16 bytes (full PKCS7 padding block). Decrypt back, assert empty.
|
|
Use a fixed IV (e.g., all zeros). The exact ciphertext can be computed: encrypt b"" and store the result as golden vector. Since empty + PKCS7 = 16 bytes of 0x10, encrypt that. Compute the expected value by running the test once, then hardcode it. ALTERNATIVELY: just test the round-trip property (encrypt then decrypt gives empty) plus verify length == 16. This is simpler and sufficient for the empty case.
|
|
|
|
**Test 4: `test_golden_hmac_sha256`**
|
|
Compute HMAC-SHA256 over IV || ciphertext from Test 1.
|
|
Expected: `hex!("0c85780b6628ba3b52654d2f6e0d9bbec67443cf2a6104eb3120ec93fc2d38d4")` (verified with openssl in research).
|
|
```rust
|
|
let iv = hex!("00000000000000000000000000000001");
|
|
let ciphertext = hex!("6e66ae8bc740efeefe83b5713fcb716f");
|
|
let hmac = crypto::compute_hmac(&KEY, &iv, &ciphertext);
|
|
assert_eq!(hmac, hex!("0c85780b6628ba3b52654d2f6e0d9bbec67443cf2a6104eb3120ec93fc2d38d4"));
|
|
```
|
|
|
|
**Test 5: `test_golden_hmac_verify`**
|
|
Verify HMAC from Test 4 returns true. Also verify with a wrong expected value returns false.
|
|
|
|
**Test 6: `test_golden_sha256_hello`**
|
|
SHA-256("Hello") must equal `hex!("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")` (from FORMAT.md Section 12.3).
|
|
|
|
**Test 7: `test_golden_sha256_32x01`**
|
|
SHA-256 of 32 bytes of 0x01 must equal `hex!("72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793")` (from FORMAT.md Section 12.3).
|
|
|
|
CRITICAL: Do NOT create golden vectors for compressed-then-encrypted data (gzip non-determinism across platforms). All golden vectors test raw plaintext encryption only.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/nick/Projects/Rust/encrypted_archive && cargo test --test golden 2>&1</automated>
|
|
<manual>All 7 golden vector tests pass</manual>
|
|
</verify>
|
|
<done>Golden test vectors exist for AES-256-CBC encrypt/decrypt, HMAC-SHA256, and SHA-256. All values cross-verified with openssl enc / openssl dgst / sha256sum during research. TST-02 satisfied.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Create CLI round-trip integration tests</name>
|
|
<files>tests/round_trip.rs</files>
|
|
<action>
|
|
Create `tests/round_trip.rs` with integration tests that run the actual `encrypted_archive` binary via `assert_cmd::Command::cargo_bin("encrypted_archive")`.
|
|
|
|
Import:
|
|
```rust
|
|
use assert_cmd::Command;
|
|
use tempfile::tempdir;
|
|
use std::fs;
|
|
```
|
|
|
|
**Test 1: `test_roundtrip_single_text_file`**
|
|
- Create tempdir, write `hello.txt` with content `b"Hello"`.
|
|
- Run `encrypted_archive pack hello.txt -o archive.bin`.
|
|
- Run `encrypted_archive unpack archive.bin -o output/`.
|
|
- Assert `output/hello.txt` content == original `b"Hello"`.
|
|
|
|
**Test 2: `test_roundtrip_multiple_files`**
|
|
- Create two files: `text.txt` ("Some text content") and `binary.dat` (256 bytes of 0x42).
|
|
- Pack both into one archive.
|
|
- Unpack.
|
|
- Assert both files byte-identical to originals.
|
|
|
|
**Test 3: `test_roundtrip_empty_file`**
|
|
- Create `empty.txt` with 0 bytes.
|
|
- Pack, unpack.
|
|
- Assert extracted file is exactly 0 bytes.
|
|
- This tests PKCS7 full-block padding on 0-byte input (encrypted_size = 16).
|
|
|
|
**Test 4: `test_roundtrip_cyrillic_filename`**
|
|
- Create `файл.txt` with content "Содержимое" (Cyrillic, UTF-8).
|
|
- Pack, unpack.
|
|
- Assert extracted `файл.txt` content equals original.
|
|
- This tests non-ASCII (UTF-8) filename handling in TOC entries.
|
|
|
|
**Test 5: `test_roundtrip_large_file`**
|
|
- Generate 11MB (11_000_000 bytes) of deterministic pseudo-random data: `(0..11_000_000u32).map(|i| (i.wrapping_mul(2654435761)) as u8).collect()`.
|
|
- Write as `large.bin`.
|
|
- Pack with `--no-compress bin` (skip compression for binary extension).
|
|
- Unpack.
|
|
- Assert byte-identical.
|
|
- This tests large file handling (>10MB) per Phase 3 success criteria.
|
|
|
|
**Test 6: `test_roundtrip_no_compress_flag`**
|
|
- Create `data.apk` with some content (e.g., 100 bytes of pattern).
|
|
- Pack (APK auto-detected as no-compress).
|
|
- Unpack.
|
|
- Assert byte-identical.
|
|
- This tests that no-compression round-trip works (compression_flag=0).
|
|
|
|
Each test uses `tempdir()` for isolation (auto-cleanup, parallel-safe).
|
|
Each test asserts `.success()` on both pack and unpack commands.
|
|
Each test compares file content with `assert_eq!(fs::read(original), fs::read(extracted))`.
|
|
|
|
IMPORTANT: Use `assert_cmd::Command::cargo_bin("encrypted_archive").unwrap()` to locate the binary. This handles debug/release build paths automatically.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/nick/Projects/Rust/encrypted_archive && cargo test --test round_trip 2>&1</automated>
|
|
<manual>All 6 round-trip tests pass including empty file, Cyrillic filename, and 11MB file</manual>
|
|
</verify>
|
|
<done>Round-trip integration tests cover: single file, multiple files, empty file, Cyrillic filename, large (11MB) binary, no-compression APK. All tests verify byte-identical extraction via SHA-256 implicit comparison (assert_eq on raw bytes). INT-02 and TST-01 satisfied.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `cargo test --test golden` passes all 7 golden vector tests
|
|
- `cargo test --test round_trip` passes all 6 integration tests
|
|
- `cargo test` passes ALL tests (unit + golden + round-trip)
|
|
- Golden vectors use fixed IVs (no randomness, fully deterministic)
|
|
- Round-trip tests cover all edge cases from Phase 3 success criteria: empty file, large APK (>10MB), non-ASCII name (Cyrillic)
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
1. `cargo test` runs 30+ tests (19 unit + 7 golden + 6 round-trip), all pass
|
|
2. Golden test values match openssl cross-verification from research
|
|
3. All Phase 3 success criteria met:
|
|
- Byte-identical round-trips (INT-02)
|
|
- Golden vectors exist (TST-02)
|
|
- Unit tests per module (TST-03, from Plan 01)
|
|
- Edge cases: empty file, >10MB, Cyrillic filename
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/03-round-trip-verification/03-02-SUMMARY.md`
|
|
</output>
|