forked from fjall-rs/lsm-tree
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patherror.rs
More file actions
118 lines (106 loc) · 4.78 KB
/
Copy patherror.rs
File metadata and controls
118 lines (106 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026-present, Structured World Foundation
//! Typed errors surfaced by the AAD-bound encrypted block decoder.
//!
//! See `docs/aad-block-format.md` §5.3 and §8: each variant maps to a
//! distinct decode-time failure mode so the caller can react
//! programmatically (e.g. surface `UnknownKeyEpoch` as a key-rotation
//! diagnostic, but `AeadVerificationFailed` as silent corruption /
//! tampering and a forensics trigger).
use core::fmt;
/// Errors raised by the AAD-bound block decoder.
///
/// All variants are decode-side: encode-side failures (AEAD failed
/// to seal, caller-supplied buffer too small, etc.) surface through
/// the existing `crate::Error::Encrypt` channel that the
/// [`super::EncryptionProvider`] trait already uses. The decoder's
/// job is to reject anything that doesn't match the on-disk wire
/// format precisely, before any decryption work happens.
#[derive(Debug)]
#[non_exhaustive]
pub enum DecryptError {
/// `MetadataFrame` failed a structural check before any AEAD work:
/// wrong magic, wrong `PayloadLen`, malformed `WindowLog`, or
/// unknown `BlockType` byte. A non-conformant frame cannot have an
/// AAD constructed against it, so AEAD verification cannot bind any
/// context.
MalformedMetadataFrame(&'static str),
/// `BodyFrame` failed a structural check: wrong magic, zero-length
/// payload, or payload exceeding the 256 MiB spec cap. Rejected
/// before allocating the read buffer to avoid memory amplification
/// on a forged TOC or a header bit-flip.
MalformedBodyFrame(&'static str),
/// `HeaderByte` decoded to a format version this build does not
/// know how to read. Currently the only supported version is v1
/// (high nibble `0b0001`); any other value lands here.
UnsupportedFormatVersion {
/// The raw byte read from `MetadataPayload` offset 0.
header_byte: u8,
},
/// The on-disk `SuiteID` byte is not registered in this build's
/// `§7` suite table. The decoder cannot resolve `NONCE_LEN` and
/// must refuse to read the variable-length tail of the frame.
UnsupportedSuite {
/// The raw byte read from `MetadataPayload` offset 11.
suite_id: u8,
},
/// `KeyEpoch` is outside the caller's key chain. Surfaced as a
/// distinct variant from `AeadVerificationFailed` so an operator
/// can tell key-rotation drift apart from active tampering.
UnknownKeyEpoch {
/// The raw byte read from `MetadataPayload` offset 9.
key_epoch: u8,
},
/// Caller asserted a specific suite expectation (e.g. through a
/// strongly-typed read API) but the on-disk byte disagrees.
/// Distinct from `AeadVerificationFailed` because the caller is
/// reading the wrong contract, not a corrupted block.
SuiteMismatch {
/// Suite the caller said the block was sealed under.
expected: u8,
/// Suite actually read from `MetadataPayload` offset 11.
actual: u8,
},
/// AEAD primitive rejected the (ciphertext, tag, AAD, nonce, key)
/// tuple. This is the catch-all for every AAD-bound tampering
/// attack from `docs/aad-block-format.md` §3: bit-flip, block swap
/// (intra-file / inter-file / cross-tree), block-type relabel,
/// codec relabel, dict substitution, AAD format substitution.
AeadVerificationFailed,
}
impl fmt::Display for DecryptError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MalformedMetadataFrame(reason) => {
write!(f, "malformed AAD `MetadataFrame`: {reason}")
}
Self::MalformedBodyFrame(reason) => {
write!(f, "malformed AAD `BodyFrame`: {reason}")
}
Self::UnsupportedFormatVersion { header_byte } => write!(
f,
"unsupported AAD format version (HeaderByte=0x{header_byte:02X}, \
expected high nibble 0b0001)"
),
Self::UnsupportedSuite { suite_id } => write!(
f,
"unsupported AEAD suite (SuiteID=0x{suite_id:02X}, not in v1 registry)"
),
Self::UnknownKeyEpoch { key_epoch } => write!(
f,
"unknown KeyEpoch 0x{key_epoch:02X} (not present in caller's key chain)"
),
Self::SuiteMismatch { expected, actual } => write!(
f,
"AEAD suite mismatch (expected 0x{expected:02X}, found 0x{actual:02X} on disk)"
),
Self::AeadVerificationFailed => {
f.write_str("AEAD tag verification failed (corruption, tampering, or wrong key)")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecryptError {}
#[cfg(test)]
mod tests;