test(core): backup error paths
Covers bad magic, unsupported version, wrong passphrase, truncation, and tampered ciphertext. The wrong-passphrase / tampered-tag pair both collapse to RelicarioError::Decrypt — same opaque-failure contract as the live vault.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
//! Backup container round-trip + error-path coverage.
|
//! Backup container round-trip + error-path coverage.
|
||||||
|
|
||||||
use relicario_core::backup::{pack_backup, unpack_backup, BackupInput, BackupOutput};
|
use relicario_core::backup::{pack_backup, unpack_backup, BackupInput};
|
||||||
|
|
||||||
fn empty_input() -> BackupInput<'static> {
|
fn empty_input() -> BackupInput<'static> {
|
||||||
BackupInput {
|
BackupInput {
|
||||||
@@ -131,3 +131,58 @@ fn no_history_produces_strict_subset() {
|
|||||||
with.len(), without.len()
|
with.len(), without.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use relicario_core::RelicarioError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bad_magic_rejected() {
|
||||||
|
let mut bytes = pack_backup(empty_input(), "p").unwrap();
|
||||||
|
bytes[0] = b'X';
|
||||||
|
match unpack_backup(&bytes, "p") {
|
||||||
|
Err(RelicarioError::BackupBadMagic) => {}
|
||||||
|
other => panic!("expected BackupBadMagic, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsupported_version_rejected() {
|
||||||
|
let mut bytes = pack_backup(empty_input(), "p").unwrap();
|
||||||
|
bytes[4] = 0xFF;
|
||||||
|
match unpack_backup(&bytes, "p") {
|
||||||
|
Err(RelicarioError::BackupUnsupportedVersion { found, expected }) => {
|
||||||
|
assert_eq!(found, 0xFF);
|
||||||
|
assert_eq!(expected, 0x01);
|
||||||
|
}
|
||||||
|
other => panic!("expected BackupUnsupportedVersion, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrong_passphrase_rejected_as_decrypt_error() {
|
||||||
|
let bytes = pack_backup(empty_input(), "right-passphrase").unwrap();
|
||||||
|
match unpack_backup(&bytes, "wrong-passphrase") {
|
||||||
|
Err(RelicarioError::Decrypt) => {}
|
||||||
|
other => panic!("expected Decrypt (opaque), got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn truncated_file_rejected() {
|
||||||
|
let bytes = pack_backup(empty_input(), "p").unwrap();
|
||||||
|
let truncated = &bytes[..bytes.len().min(60)]; // shorter than HEADER_LEN + TAG_LEN
|
||||||
|
match unpack_backup(truncated, "p") {
|
||||||
|
Err(RelicarioError::Format(_)) => {}
|
||||||
|
other => panic!("expected Format(truncated), got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tampered_ciphertext_rejected_as_decrypt_error() {
|
||||||
|
let mut bytes = pack_backup(empty_input(), "p").unwrap();
|
||||||
|
let last = bytes.len() - 1;
|
||||||
|
bytes[last] ^= 0xFF; // flip a byte in the auth-tag region
|
||||||
|
match unpack_backup(&bytes, "p") {
|
||||||
|
Err(RelicarioError::Decrypt) => {}
|
||||||
|
other => panic!("expected Decrypt for tampered tag, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user