Skip to main content

bitlocker/
error.rs

1//! Error type for the BitLocker reader/decryptor.
2//!
3//! The reader never panics on malformed input: out-of-range reads yield safe
4//! defaults through the bounds-checked helpers. Genuine failures — a non-BitLocker
5//! image, an unsupported cipher, a wrong password (CCM tag mismatch), or missing
6//! key material — surface as loud, specific errors that carry the offending value,
7//! never a silent empty result.
8
9/// An error decoding or unlocking a BitLocker (BDE) volume.
10#[derive(Debug, thiserror::Error)]
11pub enum BdeError {
12    /// An I/O error reading the underlying volume.
13    #[error("i/o error reading BitLocker volume: {0}")]
14    Io(#[from] std::io::Error),
15
16    /// The volume header carries neither a BitLocker `-FVE-FS-` signature nor a
17    /// BitLocker To Go `MSWIN4.1` signature. The offending bytes at offset 3 are
18    /// included so the caller can identify what was actually there.
19    #[error("not a BitLocker volume: signature at offset 3 is {signature:02x?} (expected \"-FVE-FS-\" or \"MSWIN4.1\")")]
20    NotBitLocker {
21        /// The 8 bytes found at offset 3 of the volume header.
22        signature: [u8; 8],
23    },
24
25    /// No FVE metadata block carried a valid `-FVE-FS-` block-header signature at
26    /// any of the three candidate offsets read from the volume header.
27    #[error("no valid FVE metadata block found at candidate offsets {offsets:?}")]
28    NoValidMetadata {
29        /// The three candidate byte offsets tried.
30        offsets: [u64; 3],
31    },
32
33    /// The encryption-method value is not one of the six defined BitLocker
34    /// ciphers (`0x8000`–`0x8005`). The raw value is included.
35    #[error("unsupported encryption method 0x{method:04x} (not a recognized BitLocker cipher; this build decrypts 0x8000 AES-128-CBC + Elephant Diffuser and 0x8002 AES-128-CBC)")]
36    UnsupportedEncryptionMethod {
37        /// The raw 16-bit encryption-method value from the metadata header.
38        method: u16,
39    },
40
41    /// The encryption method is a recognized BitLocker cipher but this build has
42    /// no oracle-validated decrypt for it yet (AES-256-CBC `0x8003`, or AES-XTS
43    /// `0x8004`/`0x8005`, or AES-256-CBC + diffuser `0x8001`). It is refused
44    /// rather than decrypted by construction. The raw value is named.
45    #[error("recognized but unvalidated encryption method 0x{method:04x} (no oracle yet; this build decrypts only 0x8000 and 0x8002)")]
46    UnvalidatedEncryptionMethod {
47        /// The raw 16-bit encryption-method value from the metadata header.
48        method: u16,
49    },
50
51    /// The metadata carries no VMK for the protector the caller tried to unlock
52    /// with (password `0x2000` or recovery password `0x0800`). The protector
53    /// types that *were* present are listed to guide the examiner toward the
54    /// right unlock path.
55    #[error("no {protector} protector present; protectors found: {found:?}")]
56    NoUnlockProtector {
57        /// The protector the caller attempted (e.g. "password", "recovery password").
58        protector: &'static str,
59        /// The key-protection types that were present.
60        found: Vec<u16>,
61    },
62
63    /// The supplied recovery password is not a valid 48-digit BitLocker recovery
64    /// key (wrong group count, a non-digit, a failed divisible-by-11 checksum, or
65    /// an out-of-range group). The specific reason is named.
66    #[error("invalid recovery password: {reason}")]
67    InvalidRecoveryPassword {
68        /// Why the recovery password was rejected.
69        reason: &'static str,
70    },
71
72    /// The password-protected VMK is missing its stretch key or AES-CCM key
73    /// entry, so the VMK cannot be derived. Names which part is absent.
74    #[error("password protector is malformed: missing {what}")]
75    MissingKeyMaterial {
76        /// Which required sub-entry was absent (e.g. "stretch key", "AES-CCM key").
77        what: &'static str,
78    },
79
80    /// The AES-CCM authentication tag did not verify — for a password unlock this
81    /// means the supplied password is wrong; for FVEK it means the VMK is wrong.
82    #[error(
83        "AES-CCM authentication failed unwrapping the {what} (wrong password or corrupt metadata)"
84    )]
85    AuthenticationFailed {
86        /// Which key was being unwrapped ("volume master key" or "FVEK").
87        what: &'static str,
88    },
89
90    /// A decrypted key container was shorter than the fixed layout requires, or a
91    /// key field ran past the end of the plaintext.
92    #[error("decrypted {what} key container is malformed (got {got} bytes, need at least {need})")]
93    MalformedKeyContainer {
94        /// Which container ("volume master key" or "FVEK").
95        what: &'static str,
96        /// Bytes actually present.
97        got: usize,
98        /// Minimum bytes the layout requires.
99        need: usize,
100    },
101}
102
103/// Convenience alias for reader results.
104pub type Result<T> = std::result::Result<T, BdeError>;