Skip to main content

forensic_vfs/
encryption.rs

1//! [`EncryptionLayer`] — full-disk-encryption translation, a distinct layer between
2//! volume and filesystem.
3//!
4//! BitLocker/LUKS/FileVault sit between a volume and its filesystem; the resolver
5//! (in the engine) probes for them by on-disk header magic. Credentials are
6//! supplied at resolve time through an injected [`CredentialSource`], never stored
7//! in a [`crate::pathspec::PathSpec`], so a serialized address never leaks keys.
8
9use crate::error::VfsResult;
10use crate::source::DynSource;
11
12/// The FDE scheme.
13#[non_exhaustive]
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum EncryptionScheme {
16    Bitlocker,
17    Luks1,
18    Luks2,
19    FileVault,
20    ApfsEncrypted,
21    /// VeraCrypt / TrueCrypt full-volume encryption (XTS, optional cipher cascade).
22    VeraCrypt,
23}
24
25/// One credential offered to a encryption layer.
26#[non_exhaustive]
27#[derive(Debug, Clone)]
28pub enum Credential {
29    Password(String),
30    /// BitLocker numeric recovery key or LUKS passphrase file contents.
31    RecoveryKey(String),
32    /// Raw key material (FVEK / volume master key).
33    KeyBytes(Vec<u8>),
34    /// A keyfile path the provider will read.
35    KeyFile(std::path::PathBuf),
36}
37
38/// Supplies credentials at resolve time. Injected into the resolve call, kept out
39/// of the serialized address, so a `PathSpec` is safe to persist and re-open
40/// (the caller re-supplies credentials on re-open).
41pub trait CredentialSource: Send + Sync {
42    /// Offer credentials for a target (a volume GUID / label / scheme name). An
43    /// empty slice means "none available" — the layer then errors
44    /// [`crate::error::VfsError::NeedCredentials`] rather than guessing.
45    fn credentials_for(&self, scheme: EncryptionScheme, target: &str) -> Vec<Credential>;
46}
47
48/// An encryption translation over one [`crate::ImageSource`]: consumes credentials +
49/// ciphertext sectors, presents a decrypted [`DynSource`].
50pub trait EncryptionLayer: Send + Sync {
51    fn scheme(&self) -> EncryptionScheme;
52    /// Present the decrypted volume. Errs `NeedCredentials` if keys are absent,
53    /// `Decode` (loud, with the header bytes) on a bad key / unsupported cipher.
54    fn open(&self, creds: &dyn CredentialSource) -> VfsResult<DynSource>;
55
56    /// Findings raised while parsing the FDE header. Behind the `findings`
57    /// feature so a bare reader does not inherit forensicnomicon.
58    #[cfg(feature = "findings")]
59    fn findings(&self) -> VfsResult<Vec<forensicnomicon::report::Finding>> {
60        Ok(Vec::new())
61    }
62}