#![allow(clippy::unwrap_used, clippy::expect_used)]
mod common;
use std::fs::File;
use std::path::Path;
use bitlocker::BitLockerVolume;
use common::{sha256_hex, OffsetReader};
const VOLUME_OFFSET: u64 = 65_536;
#[test]
fn tier2_startupkey_xts128_matches_pybde() {
let Ok(path) = std::env::var("BDE_STARTUPKEY_ORACLE") else {
eprintln!("BDE_STARTUPKEY_ORACLE unset — skipping Tier-2 startup-key oracle");
return;
};
let dir = Path::new(&path).parent().expect("raw path has a parent");
let bek_path = std::fs::read_dir(dir)
.expect("read oracle dir")
.filter_map(|e| e.ok().map(|e| e.path()))
.find(|p| p.extension().is_some_and(|x| x.eq_ignore_ascii_case("bek")))
.expect("a .BEK file next to sk8004.raw");
let bek = std::fs::read(&bek_path).expect("read .BEK");
let file = File::open(&path).expect("open sk8004.raw");
let reader = OffsetReader::new(file, VOLUME_OFFSET).expect("window volume");
let mut vol = BitLockerVolume::unlock_with_startup_key(reader, &bek).expect("unlock via .BEK");
assert_eq!(
vol.metadata().encryption_method,
0x8004,
"oracle must be XTS-AES-128"
);
let cases: [(u64, &str); 6] = [
(
0,
"343e0202d4c45a9c7d4f753f7b0f9bf5c19492f634bf12ded6d81957e367f53e",
),
(
1,
"ef6d6118087d7849e66c32de9859dc5a74b98aa2d28b3f2e6e87275b537eb546",
),
(
2,
"e845941331aaf16324636abd0c499908757d12eaf947c841e02164c4b9e1edad",
),
(
16,
"94f1d42602ae60a6bc0af6af26b623181f1530d8bea27b803d67d50a0fb65f67",
),
(
100,
"a23c6ada5be04b4f1ffcc694843fb07f549f72bd9cd61b418be86549a7397c9b",
),
(
200,
"ad9b47e60ca28ec76ee35d6c4e1ac008a2911d2fc4107d3c70e74f2919808945",
),
];
for (lba, want) in cases {
let mut buf = [0u8; 512];
vol.read_at(lba * 512, &mut buf).expect("read_at");
let got = sha256_hex(&buf);
println!("sector {lba}: {got}");
assert_eq!(got, want, "decrypted sector {lba} does not match pybde");
}
let mut boot = [0u8; 512];
vol.read_at(0, &mut boot).unwrap();
assert_eq!(&boot[3..11], b"NTFS ");
assert_eq!(&boot[510..512], &[0x55, 0xaa]);
}