Report
where P: AsRef<[u8]> + Default, { pub fn new() -> Report
{ return Report { data: P::default(), crc: 0, }; } pub fn is_valid(&self) -> bool { // TODO: Certain commands return a wrong CRC code that does not // match the actual report content. For now we defuse the // check but that cannot stay. // return self.crc == crc(self.data.as_ref()); return self.crc != 0; } } impl
AsRef<[u8]> for Report
where P: AsRef<[u8]>, { fn as_ref(&self) -> &[u8] { unsafe { return 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()); return Report { data: payload, crc: crc, }; } } impl
AsMut<[u8]> for Report
where P: AsRef<[u8]>, { fn as_mut(&mut self) -> &mut [u8] { unsafe { return mem::transmute::<&mut Report
, &mut [u8; 64]>(self) }; } } pub struct EmptyPayload { pub data: [u8; 60], } impl Default for EmptyPayload { fn default() -> EmptyPayload { return EmptyPayload { data: [0u8; 60], }; } } impl AsRef<[u8]> for EmptyPayload { fn as_ref(&self) -> &[u8] { unsafe { return mem::transmute::<&EmptyPayload, &[u8; 60]>(self) }; } } impl
AsRef {
unsafe { return 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 {
return $name{
command: Command::$command,
padding: [0; 59],
};
}
}
}
}
macro_rules! defaultPayloadAsRef {
( $name:ty ) => {
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
unsafe {
return 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: &Vec AsRef<[u8]> for Response {
fn as_ref(&self) -> &[u8] {
unsafe { return 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 padding1: u8,
pub version_major: u8,
pub padding2: u8,
pub version_minor: 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);
}
}