X-Git-Url: http://git.euphorik.ch/?p=crypto_lab1.git;a=blobdiff_plain;f=src%2Fpacket.rs;fp=src%2Fpacket.rs;h=0000000000000000000000000000000000000000;hp=73eecea9ad1cb7948f7bd83948296fdd00ee92dc;hb=ecdec5bf7022018eadf4a38b01890bbb3ab79c89;hpb=c9318a07ce0ec00f999ff17943b83048d536ecd1 diff --git a/src/packet.rs b/src/packet.rs deleted file mode 100644 index 73eecea..0000000 --- a/src/packet.rs +++ /dev/null @@ -1,268 +0,0 @@ -use std::io; -use std::fmt; -use std::rand::{ Rng, StdRng, SeedableRng, distributions }; -use std::rand::distributions::IndependentSample; -use serialize::hex::{ ToHex }; -use crypto; - -// There are all the errors that may occur when reading an encrypted and authenticated packet. -#[deriving(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 -} - -// A macro to return a 'IOReadError' in case of error. -macro_rules! try_read_io( - ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(IOReadError(e)) }) -) - -// There are all the errors that may occur when encrypting, authenticating and writing a packet. -#[deriving(Show)] -pub enum WritingError { - WriteIOError(io::IoError), - EncryptError, -} - -// A macro to return a 'IOWritingError' in case of error. -macro_rules! try_write_io( - ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(WriteIOError(e)) }) -) - -pub type ReadingResult = Result; -pub type WritingResult = Result<(), WritingError>; - -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)] -pub struct PacketData { - id: u8, - payload: Vec // The size can vary from 'MIN_PAYLOAD_SIZE' to 'MAX_PAYLOAD_SIZE' bytes. -} - -#[deriving(Show, Clone)] -pub enum ErrorType { - CryptError, - AuthError -} - -#[deriving(Clone)] -pub enum PacketType { - Command(PacketData), - Answer(PacketData), - Error(ErrorType), -} - -/// Serialized packet format : |LL|P|TTTTTTTT|D...D|MMMMMMMMMM| -/// Where: -/// LL: Size of the following data -/// P: Packet type: -/// 0x00: Command -/// OxFF: Answer -/// 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) -/// MMMMMMMMMM: first 10 bytes (most significant) of the HMAC-SHA256 of: -/// |I|C...C| for command and answer packet -/// |0000000000000000| for error packet -#[deriving(Show)] -pub struct Packet { - pub t: PacketType, - pub timestamp: u64 -} - -impl fmt::Show for PacketType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - fn data_to_str(data: &PacketData) -> String { - format!("id: {}, payload({}): \"{}\"", data.id, data.payload.len(), data.payload.as_slice().to_hex()) - } - 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) - } - } -} - -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_()); - PacketData { - id: rng.gen::(), - payload: payload - } - } - - pub fn new_packet_data(id: u8, payload: Vec) -> PacketData { - PacketData { id: id, payload: payload } - } - - pub fn write(&self, output: &mut io::Writer) -> WritingResult { - self.write_with_padding_fun(output, |_, padding_length: uint| -> u8 { - padding_length as u8 - }) - } - - /// 'padd_fun' is function defining the padding. The first argument is the index of the current byte, starting at 0. - /// The second argument is the padding length. - pub fn write_with_padding_fun(&self, output: &mut io::Writer, padd_fun: |uint, uint| -> u8) -> WritingResult { - fn packet_data(p: &PacketData) -> Vec { - let mut d = Vec::new(); - d.push(p.id); - d.push_all(p.payload.as_slice()); - d - } - - // Data to be encrypted. - 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. - }; - - // Compute the MAC - let mac = crypto::compute_mac(data.as_slice()); - - // Padding. - match self.t { - Command(_) | Answer(_) => { - let padding_size = if data.len() % 16 == 0 { 16 } else { 16 - data.len() % 16 } ; - data.reserve_additional(padding_size); - for i in range(0, padding_size) { - data.push(padd_fun(i, padding_size)); - } - }, - _ => () - } - - // Encrypt. - let encrypted_data = match crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice()) { - Some(d) => d, - _ => return Err(EncryptError) - }; - - // Write packet length. - try_write_io!(output.write_be_u16((encrypted_data.len() + FIXED_PACKET_SIZE) as u16)); - - // Write packet type. - try_write_io!(output.write_u8( - match self.t { - Command(_) => 0x00, - Answer(_) => 0xFF, - Error(CryptError) => 0x0A, - Error(AuthError) => 0x0B - } - )); - - // Write timestamp. - try_write_io!(output.write_be_u64(self.timestamp)); - - // Write encrypted data. - try_write_io!(output.write(encrypted_data.as_slice())); - - // Write the MAC. - try_write_io!(output.write(mac)); - - Ok(()) - } - - pub fn read(input: &mut io::Reader) -> ReadingResult { - fn consume(input: &mut io::Reader, nb_byte: uint) { - let _ = input.read_exact(nb_byte); - } - - let data_size = try_read_io!(input.read_be_u16()); - - // Read and check 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) - } - - 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 data = match crypto::decrypt(encrypted_data.as_slice(), iv_from_timestamp(timestamp).as_slice()) { - Some(d) => d, - _ => return Err(UnconsistentEncryptedSizeError) - }; - - // Control the size and the content of the padding then remove it. - if packet_type == 0x00 || packet_type == 0xFF { - match data.last() { - Some(&padding_size) => { - if padding_size as uint > data.len() || !data.slice_from(data.len() - padding_size as uint).iter().any(|b| *b == padding_size) { - consume(input, 10); - return Err(PaddingError) - } - let data_length = data.len() - padding_size as uint; - data.truncate(data_length); - }, - None => - return Err(PaddingError) - } - } - - // Read an verify the MAC. - let mut mac_read = [0u8, ..10]; - if try_read_io!(input.read(mac_read)) != mac_read.len() { - return Err(UnconsistentMACSizeError) - } - let mac_data = crypto::compute_mac(data.as_slice()); - if mac_read != mac_data { - return Err(MACMismatchError) - } - - 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) - } - 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) } - }, - // Error. - _ => { - if data.len() != 16 { - return Err(UnconsistentDataSizeError) - } else if data != Vec::from_elem(16, 0) { - return Err(DataError) - } - match packet_type { 0x0A => Error(CryptError), _ => Error(AuthError) } - } - }, - timestamp: timestamp - }) - } -} - -// Build 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() -}