#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum VolumeEncryption {
BitLocker,
BitLockerToGo,
}
const FVE_SIGNATURE: &[u8; 8] = b"-FVE-FS-";
pub const BITLOCKER_IDENTIFIER_GUID: [u8; 16] = [
0x3B, 0xD6, 0x67, 0x49, 0x29, 0x2E, 0xD8, 0x4A, 0x83, 0x99, 0xF6, 0xA3, 0x39, 0xE3, 0xD0, 0x01,
];
#[must_use]
pub fn detect_encryption(volume: &[u8]) -> Option<VolumeEncryption> {
if volume.len() >= 11 && &volume[3..11] == FVE_SIGNATURE {
return Some(VolumeEncryption::BitLocker);
}
if volume
.windows(BITLOCKER_IDENTIFIER_GUID.len())
.any(|w| w == BITLOCKER_IDENTIFIER_GUID)
{
return Some(VolumeEncryption::BitLockerToGo);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
const TO_GO_GUID_OFFSET: usize = 424;
#[test]
fn fixed_drive_bitlocker_is_detected_by_the_fve_signature() {
let mut vbr = vec![0u8; 512];
vbr[0..3].copy_from_slice(&[0xEB, 0x58, 0x90]); vbr[3..11].copy_from_slice(b"-FVE-FS-");
assert_eq!(detect_encryption(&vbr), Some(VolumeEncryption::BitLocker));
}
#[test]
fn bitlocker_to_go_is_detected_by_the_identifier_guid_on_a_fat_volume() {
let mut vbr = vec![0u8; 512];
vbr[0..3].copy_from_slice(&[0xEB, 0x58, 0x90]);
vbr[3..11].copy_from_slice(b"MSWIN4.1");
vbr[0x52..0x5A].copy_from_slice(b"FAT32 ");
vbr[TO_GO_GUID_OFFSET..TO_GO_GUID_OFFSET + 16].copy_from_slice(&BITLOCKER_IDENTIFIER_GUID);
assert_eq!(
detect_encryption(&vbr),
Some(VolumeEncryption::BitLockerToGo)
);
}
#[test]
fn the_fve_signature_takes_precedence_over_the_guid() {
let mut vbr = vec![0u8; 512];
vbr[3..11].copy_from_slice(b"-FVE-FS-");
vbr[160..176].copy_from_slice(&BITLOCKER_IDENTIFIER_GUID);
assert_eq!(detect_encryption(&vbr), Some(VolumeEncryption::BitLocker));
}
#[test]
fn a_plaintext_fat_volume_is_not_flagged() {
let mut vbr = vec![0u8; 512];
vbr[3..11].copy_from_slice(b"MSDOS5.0");
vbr[0x52..0x5A].copy_from_slice(b"FAT32 ");
assert_eq!(detect_encryption(&vbr), None);
}
#[test]
fn a_plaintext_ntfs_volume_is_not_flagged() {
let mut vbr = vec![0u8; 512];
vbr[3..11].copy_from_slice(b"NTFS ");
assert_eq!(detect_encryption(&vbr), None);
}
#[test]
fn a_short_slice_does_not_panic() {
assert_eq!(detect_encryption(&[]), None);
assert_eq!(detect_encryption(&[0u8; 4]), None);
assert_eq!(detect_encryption(b"-FVE-FS"), None); }
}