where Payload: AsRef<[u8]>,
{
// The actual payload data. A report may encapsulate a command to send
// to the stick or a response to receive from it.
pub data: Payload,
pub crc: u32,
}
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,
};
}
}
#[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) -> EnableEncryptedVolumeCommand {
let mut report = EnableEncryptedVolumeCommand {
command: Command::EnableEncryptedVolume,
kind: 'P' as u8,
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]);
return report;
}
}
impl AsRef<[u8]> for EnableEncryptedVolumeCommand {
fn as_ref(&self) -> &[u8] {
unsafe { return mem::transmute::<&EnableEncryptedVolumeCommand, &[u8; 60]>(self) };
}
}
#[allow(dead_code)]
#[repr(packed)]
pub struct DisableEncryptedVolumeCommand {
command: Command,
padding: [u8; 59],
}
impl DisableEncryptedVolumeCommand {
pub fn new() -> DisableEncryptedVolumeCommand {
return DisableEncryptedVolumeCommand {
command: Command::DisableEncryptedVolume,
padding: [0; 59],
};
}
}
impl AsRef<[u8]> for DisableEncryptedVolumeCommand {
fn as_ref(&self) -> &[u8] {
unsafe { return mem::transmute::<&DisableEncryptedVolumeCommand, &[u8; 60]>(self) };
}
}
#[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);
}
}