| 447 | |
| 448 | #[test] |
| 449 | fn preamble_tamper_rejected() { |
| 450 | // binding test: swapping the preamble (different epoch) must |
| 451 | // cause decryption to fail due to AAD mismatch. |
| 452 | let dir = tempfile::tempdir().unwrap(); |
| 453 | let path = dir.path().join("tamper.seg"); |
| 454 | |
| 455 | let data = b"authentic payload"; |
| 456 | let footer = SegmentFooter::new("n", 0, Lsn::new(10), Lsn::new(20)); |
| 457 | let key = test_key(); |
| 458 | write_encrypted_segment(&path, data, &footer, Some(&key)).unwrap(); |
| 459 | |
| 460 | // Flip a byte in the preamble epoch field (bytes 8-11). |
| 461 | let mut raw = std::fs::read(&path).unwrap(); |
| 462 | raw[9] ^= 0xFF; |
| 463 | std::fs::write(&path, &raw).unwrap(); |
| 464 | |
| 465 | // Decryption must fail — preamble bytes are part of AAD. |
| 466 | assert!( |
| 467 | read_encrypted_segment(&path, Some(&key)).is_err(), |
| 468 | "preamble tamper must cause decryption failure" |
| 469 | ); |
| 470 | } |
| 471 | |
| 472 | #[test] |
| 473 | fn unencrypted_segment_roundtrip() { |