X-Git-Url: http://git.euphorik.ch/?p=crypto_lab1.git;a=blobdiff_plain;f=lab1_rust%2Fsrc%2Fpacket.rs;h=c9f111a77098dccf97dfafd0477795921548edb8;hp=c81fe20aff6aa7b57161d6762de51c17f35e839c;hb=d7f0bb987b21e93a5798403d294f7905151682f7;hpb=c484911fa250681026144ddb9e521daa2c2b4351 diff --git a/lab1_rust/src/packet.rs b/lab1_rust/src/packet.rs index c81fe20..c9f111a 100644 --- a/lab1_rust/src/packet.rs +++ b/lab1_rust/src/packet.rs @@ -3,43 +3,46 @@ use std::fmt; use std::rand::{ Rng, StdRng, SeedableRng, distributions }; use std::rand::distributions::IndependentSample; use serialize::hex::{ ToHex }; +use self::PacketType::{ Command, Answer, Error }; use crypto; +use utils::from_elem; +#[derive(Show, Copy)] pub enum Variant { Weak, // The MAC is computed on data without padding. Fixed // The MAC is computed on data and padding. } // There are all the errors that may occur when reading an encrypted and authenticated packet. -#[deriving(Show)] +#[derive(Show)] pub enum ReadingError { - IOReadError(io::IoError), - UnknownPacketTypeError, // If the first byte is unknown. - UnconsistentEncryptedSizeError, - UnconsistentDataSizeError, // The data size is not valid. - UnconsistentMACSizeError, // The MAC hasn't the correct size. - MACMismatchError, // The uncrypted received data doesn't match to the received MAC. - PaddingError, // Padding format error. - DataError, // The data are invalid. - InvalidTimestampError + IO(io::IoError), + UnknownPacketType, // If the first byte is unknown. + UnconsistentEncryptedSize, + UnconsistentDataSize, // The data size is not valid. + UnconsistentMACSize, // The MAC hasn't the correct size. + MACMismatch, // The uncrypted received data doesn't match to the received MAC. + Padding, // Padding format error. + Data, // The data are invalid. + InvalidTimestamp } -// A macro to return a 'IOReadError' in case of error. +// A macro to return a 'Err(ReadingError::IO(..))' in case of error. macro_rules! try_read_io( - ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(IOReadError(e)) }) -) + ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(ReadingError::IO(e)) }) +); // There are all the errors that may occur when encrypting, authenticating and writing a packet. -#[deriving(Show)] +#[derive(Show)] pub enum WritingError { - WriteIOError(io::IoError), - EncryptError, + IO(io::IoError), + Encrypt, } -// A macro to return a 'IOWritingError' in case of error. +// A macro to return a 'Err(WritingError::IO(..))' in case of error. macro_rules! try_write_io( - ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(WriteIOError(e)) }) -) + ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(WritingError::IO(e)) }) +); pub type ReadingResult = Result; pub type WritingResult = Result<(), WritingError>; @@ -48,19 +51,19 @@ static MIN_PAYLOAD_SIZE: uint = 7; static MAX_PAYLOAD_SIZE: uint = 39; static FIXED_PACKET_SIZE: uint = 1 + 8 + 10; // Packet type + timestamp + MAC. -#[deriving(Show, Clone)] +#[derive(Show, Clone)] pub struct PacketData { id: u8, payload: Vec // The size can vary from 'MIN_PAYLOAD_SIZE' to 'MAX_PAYLOAD_SIZE' bytes. } -#[deriving(Show, Clone)] +#[derive(Show, Clone)] pub enum ErrorType { - CryptError, - AuthError + Crypt, + Auth } -#[deriving(Clone)] +#[derive(Clone)] pub enum PacketType { Command(PacketData), Answer(PacketData), @@ -76,22 +79,22 @@ pub enum PacketType { /// 0x0A: Decrypt error /// 0x0B: Authentication error /// TTTTTTTT: Timestamp (64 bits) -/// D...D: Encrypted data (AES-256 CBC mode) of: -/// |I|C...C|P...P| for command and answer packet: -/// I: Command ID -/// C: Command payload (from 7 to 39 bytes) -/// P: Padding from 1 to 16, |I|C...C|P...P| size must be a multiple of 16 -/// |0000000000000000| for error packet (16 bytes length) +/// D...D: Encrypted data (AES-256 CBC mode) of: +/// |I|C...C|P...P| for command and answer packet: +/// I: Command ID +/// C: Command payload (from 7 to 39 bytes) +/// P: Padding from 1 to 16, |I|C...C|P...P| size must be a multiple of 16 +/// |0000000000000000| for error packet (16 bytes length) /// MMMMMMMMMM: first 10 bytes (most significant) of the HMAC-SHA256 of: /// for command and answer packet: /// |I|C...C| for weak variant /// |I|C...C|P...P|for fixed variant /// |0000000000000000| for error packet -#[deriving(Show)] +#[derive(Show)] pub struct Packet { pub t: PacketType, pub timestamp: u64 -} +} impl fmt::Show for PacketType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -101,7 +104,7 @@ impl fmt::Show for PacketType { match self { &Command(ref data) => write!(formatter, "Command {{ {} }}", data_to_str(data)), &Answer(ref data) => write!(formatter, "Answer {{ {} }}", data_to_str(data)), - &Error(error_type) => write!(formatter, "Error {{ errorType: {} }}", error_type) + &Error(ref error_type) => write!(formatter, "Error {{ errorType: {} }}", error_type) } } } @@ -109,8 +112,8 @@ impl fmt::Show for PacketType { impl Packet { pub fn random_packet_data(seed: &[uint]) -> PacketData { let mut rng = if seed.is_empty() { StdRng::new().unwrap() } else { SeedableRng::from_seed(seed) }; - let mut payload = Vec::from_elem(distributions::Range::new(MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE + 1).ind_sample(&mut rng), 0u8); - rng.fill_bytes(payload.as_mut_slice_()); + let mut payload = from_elem(distributions::Range::new(MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE + 1).ind_sample(&mut rng), 0u8); + rng.fill_bytes(payload.as_mut_slice()); PacketData { id: rng.gen::(), payload: payload @@ -141,7 +144,7 @@ impl Packet { let mut data = match self.t { Command(ref p) | Answer(ref p) => packet_data(p), - Error(_) => Vec::from_elem(16, 0) // Padding as data: 16 * 0. + Error(_) => from_elem(16, 0) // Padding as data: 16 * 0. }; let data_size = data.len(); @@ -150,7 +153,7 @@ impl Packet { match self.t { Command(_) | Answer(_) => { let padding_size = if data.len() % 16 == 0 { 16 } else { 16 - data.len() % 16 } ; - data.reserve_additional(padding_size); + data.reserve(padding_size); for i in range(0, padding_size) { data.push(padd_fun(i, padding_size)); } @@ -158,36 +161,36 @@ impl Packet { _ => () } - // Compute the MAC. It depends of the choosen variant. - let mac = crypto::compute_mac(data.slice_to(match variant { Weak => data_size, _ => data.len() })); + // Computes the MAC. It depends of the choosen variant. + let mac = crypto::compute_mac(data.slice_to(match variant { Variant::Weak => data_size, _ => data.len() })); - // Encrypt. + // Encrypts. let encrypted_data = match crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice()) { Some(d) => d, - _ => return Err(EncryptError) + _ => return Err(WritingError::Encrypt) }; - // Write packet length. + // Writes packet length. try_write_io!(output.write_be_u16((encrypted_data.len() + FIXED_PACKET_SIZE) as u16)); - // Write packet type. + // Writes packet type. try_write_io!(output.write_u8( match self.t { Command(_) => 0x00, Answer(_) => 0xFF, - Error(CryptError) => 0x0A, - Error(AuthError) => 0x0B + Error(ErrorType::Crypt) => 0x0A, + Error(ErrorType::Auth) => 0x0B } )); - // Write timestamp. + // Writes timestamp. try_write_io!(output.write_be_u64(self.timestamp)); - // Write encrypted data. + // Writes encrypted data. try_write_io!(output.write(encrypted_data.as_slice())); - // Write the MAC. - try_write_io!(output.write(mac)); + // Writes the MAC. + try_write_io!(output.write(&mac)); Ok(()) } @@ -199,55 +202,55 @@ impl Packet { let data_size = try_read_io!(input.read_be_u16()); - // Read and check the packet type. + // Reads and checks the packet type. let packet_type = try_read_io!(input.read_u8()); if ![0x00, 0xFF, 0x0A, 0x0B].iter().any(|p| *p == packet_type) { consume(input, data_size as uint - 1); - return Err(UnknownPacketTypeError) + return Err(ReadingError::UnknownPacketType) } let timestamp = try_read_io!(input.read_be_u64()); - let mut encrypted_data = Vec::from_elem(data_size as uint - FIXED_PACKET_SIZE, 0u8); - if try_read_io!(input.read(encrypted_data.as_mut_slice_())) != encrypted_data.len() { - return Err(UnconsistentEncryptedSizeError) + let mut encrypted_data = from_elem(data_size as uint - FIXED_PACKET_SIZE, 0u8); + if try_read_io!(input.read(encrypted_data.as_mut_slice())) != encrypted_data.len() { + return Err(ReadingError::UnconsistentEncryptedSize) } let mut data = match crypto::decrypt(encrypted_data.as_slice(), iv_from_timestamp(timestamp).as_slice()) { Some(d) => d, - _ => return Err(UnconsistentEncryptedSizeError) + _ => return Err(ReadingError::UnconsistentEncryptedSize) }; - // Read the MAC. - let mut mac_read = [0u8, ..10]; - if try_read_io!(input.read(mac_read)) != mac_read.len() { - return Err(UnconsistentMACSizeError) + // Reads the MAC. + let mut mac_read = [0u8; 10]; + if try_read_io!(input.read(&mut mac_read)) != mac_read.len() { + return Err(ReadingError::UnconsistentMACSize) } - match variant { Fixed if mac_read != crypto::compute_mac(data.as_slice()) => return Err(MACMismatchError), _ => () }; + match variant { Variant::Fixed if mac_read != crypto::compute_mac(data.as_slice()) => return Err(ReadingError::MACMismatch), _ => () }; - // Control the size and the content of the padding then remove it. + // Controls the size and the content of the padding then removes it. if packet_type == 0x00 || packet_type == 0xFF { match data.last() { Some(&padding_size) => { if padding_size as uint > data.len() || padding_size == 0 || data.slice_from(data.len() - padding_size as uint).iter().any(|b| *b != padding_size) { - return Err(PaddingError) + return Err(ReadingError::Padding) } let data_length = data.len() - padding_size as uint; data.truncate(data_length); }, None => - return Err(PaddingError) + return Err(ReadingError::Padding) } } - match variant { Weak if mac_read != crypto::compute_mac(data.as_slice()) => return Err(MACMismatchError), _ => () }; + match variant { Variant::Weak if mac_read != crypto::compute_mac(data.as_slice()) => return Err(ReadingError::MACMismatch), _ => () }; Ok(Packet { t: match packet_type { // Command or answer. 0x00 | 0xFF => { if data.len() < MIN_PAYLOAD_SIZE + 1 || data.len() > MAX_PAYLOAD_SIZE + 1 { - return Err(UnconsistentDataSizeError) + return Err(ReadingError::UnconsistentDataSize) } let pd = PacketData { id: data[0], payload: data.tail().to_vec() }; // match data.as_slice() { [id, payload..] => PacketData { id: id, payload: payload.to_vec() } }; match packet_type { 0x00 => Command(pd), _ => Answer(pd) } @@ -255,11 +258,11 @@ impl Packet { // Error. _ => { if data.len() != 16 { - return Err(UnconsistentDataSizeError) - } else if data != Vec::from_elem(16, 0) { - return Err(DataError) + return Err(ReadingError::UnconsistentDataSize) + } else if data != from_elem(16, 0) { + return Err(ReadingError::Data) } - match packet_type { 0x0A => Error(CryptError), _ => Error(AuthError) } + match packet_type { 0x0A => Error(ErrorType::Crypt), _ => Error(ErrorType::Auth) } } }, timestamp: timestamp @@ -267,10 +270,10 @@ impl Packet { } } -// Build an initialization vector: 64 * 0u8 + timestamp (128 bits). +// Builds an initialization vector: 64 * 0u8 + timestamp (128 bits). fn iv_from_timestamp(timestamp: u64) -> Vec { let mut iv = io::MemWriter::with_capacity(16); let _ = iv.write_be_u64(0u64); let _ = iv.write_be_u64(timestamp); - iv.unwrap() + iv.into_inner() }