Report
where P: AsRef<[u8]> + Default, { pub fn new() -> Report
{ Report { data: P::default(), crc: 0, } } pub fn is_valid(&self) -> bool { self.crc == crc(self.data.as_ref()) } } impl
AsRef<[u8]> for Report
where P: AsRef<[u8]>, { fn as_ref(&self) -> &[u8] { unsafe { mem::transmute::<&Report
, &[u8; 64]>(self) } } } impl
From
for Report
where P: AsRef<[u8]>, { fn from(payload: P) -> Report
{ let crc = crc(payload.as_ref()); Report { data: payload, crc: crc, } } } impl
AsMut<[u8]> for Report
where P: AsRef<[u8]>, { fn as_mut(&mut self) -> &mut [u8] { unsafe { mem::transmute::<&mut Report
, &mut [u8; 64]>(self) } } } pub struct EmptyPayload { pub data: [u8; 60], } impl Default for EmptyPayload { fn default() -> EmptyPayload { EmptyPayload { data: [0u8; 60], } } } impl AsRef<[u8]> for EmptyPayload { fn as_ref(&self) -> &[u8] { unsafe { mem::transmute::<&EmptyPayload, &[u8; 60]>(self) } } } impl
AsRef {
unsafe { mem::transmute::<&EmptyPayload, &Response >(self) }
}
}
macro_rules! defaultCommandType {
( $name:ident ) => {
#[allow(dead_code)]
#[repr(packed)]
pub struct $name {
command: Command,
padding: [u8; 59],
}
}
}
macro_rules! defaultCommandNew {
( $name:ident, $command:ident ) => {
impl $name {
pub fn new() -> $name {
$name{
command: Command::$command,
padding: [0; 59],
}
}
}
}
}
macro_rules! defaultPayloadAsRef {
( $name:ty ) => {
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
unsafe { mem::transmute::<&$name, &[u8; 60]>(self) }
}
}
}
}
macro_rules! defaultCommand {
( $name:ident, $command:ident ) => {
defaultCommandType!($name);
defaultCommandNew!($name, $command);
defaultPayloadAsRef!($name);
}
}
#[allow(dead_code)]
#[repr(packed)]
pub struct EnableEncryptedVolumeCommand {
command: Command,
// The kind of password. Unconditionally 'P' because the User PIN is
// used to enable the encrypted volume.
kind: u8,
// The password has a maximum length of twenty characters.
password: [u8; 20],
padding: [u8; 38],
}
impl EnableEncryptedVolumeCommand {
pub fn new(password: &[u8]) -> EnableEncryptedVolumeCommand {
let mut report = EnableEncryptedVolumeCommand {
command: Command::EnableEncryptedVolume,
kind: b'P',
password: [0; 20],
padding: [0; 38],
};
debug_assert!(password.len() <= report.password.len());
let len = cmp::min(report.password.len(), password.len());
report.password[..len].copy_from_slice(&password[..len]);
report
}
}
defaultPayloadAsRef!(EnableEncryptedVolumeCommand);
defaultCommand!(DisableEncryptedVolumeCommand, DisableEncryptedVolume);
defaultCommand!(DeviceStatusCommand, GetDeviceStatus);
#[allow(dead_code)]
#[derive(Debug)]
#[derive(PartialEq)]
#[repr(u8)]
pub enum CommandStatus {
Okay = 0,
WrongCrc = 1,
WrongSlot = 2,
SlotNotProgrammed = 3,
WrongPassword = 4,
NotAuthorized = 5,
TimestampWarning = 6,
NoNameError = 7,
}
#[allow(dead_code)]
#[derive(Copy)]
#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
#[repr(u8)]
pub enum StorageStatus {
Idle = 0,
Okay = 1,
Busy = 2,
WrongPassword = 3,
BusyProgressbar = 4,
PasswordMatrixReady = 5,
NoUserPasswordUnlock = 6,
SmartcardError = 7,
SecurityBitActive = 8,
}
#[repr(packed)]
pub struct Response AsRef<[u8]> for Response {
fn as_ref(&self) -> &[u8] {
unsafe { mem::transmute::<&Response , &[u8; 60]>(self) }
}
}
#[repr(packed)]
pub struct StorageResponse {
pub padding1: [u8; 13],
pub command_counter: u8,
pub last_storage_command: Command,
pub storage_status: StorageStatus,
pub progress: u8,
pub padding2: [u8; 2],
}
#[repr(packed)]
pub struct DeviceStatusResponse {
pub padding0: [u8; 22],
pub magic: u16,
pub unencrypted_volume_read_only: u8,
pub encrypted_volume_read_only: u8,
pub version_major: u8,
pub version_minor: u8,
pub version_build: u8,
pub version_internal: u8,
pub hidden_volume_read_only: u8,
pub firmware_locked: u8,
pub new_sdcard_found: u8,
pub sdcard_fill_with_random: u8,
pub active_sdcard_id: u32,
pub volume_active: u8,
pub new_smartcard_found: u8,
pub user_password_retry_count: u8,
pub admin_password_retry_count: u8,
pub active_smartcard_id: u32,
pub storage_keys_missing: u8,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encrypted_volume_report() {
let password = "test42".to_string().into_bytes();
let report = EnableEncryptedVolumeCommand::new(&password);
let expected = ['t' as u8, 'e' as u8, 's' as u8, 't' as u8, '4' as u8, '2' as u8, 0u8, 0u8,
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8];
assert_eq!(report.password, expected);
}
#[test]
#[cfg(debug)]
#[should_panic(expected = "assertion failed")]
fn overly_long_password() {
let password = "012345678912345678901".to_string().into_bytes();
EnableEncryptedVolumeCommand::new(&password);
}
#[test]
fn report_crc() {
let password = "passphrase".to_string().into_bytes();
let payload = EnableEncryptedVolumeCommand::new(&password);
let report = Report::from(payload);
// The expected checksum was computed using the original
// functionality.
assert_eq!(report.crc, 0xeeb583c);
}
}