#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CipherMode {
Cbc,
Xts,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncryptionMethod {
pub raw: u16,
pub key_bits: u16,
pub mode: CipherMode,
pub diffuser: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectorCipherKind {
Cbc128Diffuser,
Cbc128,
Cbc256,
Xts128,
Xts256,
}
impl EncryptionMethod {
#[must_use]
pub fn decode(raw: u16) -> Option<EncryptionMethod> {
let index = raw.checked_sub(0x8000)?;
if index > 5 {
return None;
}
let key_bits = if index & 1 == 1 { 256 } else { 128 };
let (mode, diffuser) = match index >> 1 {
0 => (CipherMode::Cbc, true),
1 => (CipherMode::Cbc, false),
_ => (CipherMode::Xts, false),
};
Some(EncryptionMethod {
raw,
key_bits,
mode,
diffuser,
})
}
#[must_use]
pub fn validated_kind(self) -> Option<SectorCipherKind> {
match (self.mode, self.key_bits, self.diffuser) {
(CipherMode::Cbc, 128, true) => Some(SectorCipherKind::Cbc128Diffuser),
(CipherMode::Cbc, 128, false) => Some(SectorCipherKind::Cbc128),
(CipherMode::Cbc, 256, false) => Some(SectorCipherKind::Cbc256),
(CipherMode::Xts, 128, false) => Some(SectorCipherKind::Xts128),
(CipherMode::Xts, 256, false) => Some(SectorCipherKind::Xts256),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decodes_all_six_axes() {
let cases = [
(0x8000u16, 128, CipherMode::Cbc, true),
(0x8001, 256, CipherMode::Cbc, true),
(0x8002, 128, CipherMode::Cbc, false),
(0x8003, 256, CipherMode::Cbc, false),
(0x8004, 128, CipherMode::Xts, false),
(0x8005, 256, CipherMode::Xts, false),
];
for (raw, key_bits, mode, diffuser) in cases {
let m = EncryptionMethod::decode(raw).unwrap();
assert_eq!(m.raw, raw);
assert_eq!(m.key_bits, key_bits);
assert_eq!(m.mode, mode);
assert_eq!(m.diffuser, diffuser);
}
}
#[test]
fn unrecognized_methods_decode_none() {
for raw in [0x0000u16, 0x7fff, 0x8006, 0x8007, 0x8010, 0x1234, 0xffff] {
assert!(EncryptionMethod::decode(raw).is_none(), "{raw:#06x}");
}
}
#[test]
fn validated_kinds_match_oracle_backed_methods() {
assert_eq!(
EncryptionMethod::decode(0x8000).unwrap().validated_kind(),
Some(SectorCipherKind::Cbc128Diffuser)
);
assert_eq!(
EncryptionMethod::decode(0x8002).unwrap().validated_kind(),
Some(SectorCipherKind::Cbc128)
);
assert_eq!(
EncryptionMethod::decode(0x8003).unwrap().validated_kind(),
Some(SectorCipherKind::Cbc256)
);
assert_eq!(
EncryptionMethod::decode(0x8004).unwrap().validated_kind(),
Some(SectorCipherKind::Xts128)
);
assert_eq!(
EncryptionMethod::decode(0x8005).unwrap().validated_kind(),
Some(SectorCipherKind::Xts256)
);
assert_eq!(
EncryptionMethod::decode(0x8001).unwrap().validated_kind(),
None,
"0x8001 has no oracle yet"
);
}
}