Add the report.
[crypto_lab1.git] / src / packet.rs
diff --git a/src/packet.rs b/src/packet.rs
deleted file mode 100644 (file)
index 73eecea..0000000
+++ /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<Packet, ReadingError>;
-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<u8> // 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::<u8>(),
-         payload: payload
-      }
-   }
-
-   pub fn new_packet_data(id: u8, payload: Vec<u8>) -> 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<u8> {
-         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<u8> {
-   let mut iv = io::MemWriter::with_capacity(16);
-   let _ = iv.write_be_u64(0u64);
-   let _ = iv.write_be_u64(timestamp);
-   iv.unwrap()
-}