Fix to the new nightly.
[crypto_lab1.git] / lab1_rust / src / packet.rs
index c81fe20..ec63d9e 100644 (file)
@@ -3,8 +3,10 @@ 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;
 
+#[deriving(Show, Copy)]
 pub enum Variant {
    Weak, // The MAC is computed on data without padding.
    Fixed // The MAC is computed on data and padding.
@@ -13,33 +15,33 @@ pub enum Variant {
 // 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
+   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)]
 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<Packet, ReadingError>;
 pub type WritingResult = Result<(), WritingError>;
@@ -56,8 +58,8 @@ pub struct PacketData {
 
 #[deriving(Show, Clone)]
 pub enum ErrorType {
-   CryptError,
-   AuthError
+   Crypt,
+   Auth
 }
 
 #[deriving(Clone)]
@@ -76,12 +78,12 @@ 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
@@ -101,7 +103,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)
       }
    }
 }
@@ -150,7 +152,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 +160,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 +201,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)
+         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.
+      // Reads the MAC.
       let mut mac_read = [0u8, ..10];
-      if try_read_io!(input.read(mac_read)) != mac_read.len() {
-         return Err(UnconsistentMACSizeError)
+      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 +257,11 @@ impl Packet {
             // Error.
             _ => {
                if data.len() != 16 {
-                  return Err(UnconsistentDataSizeError)
+                  return Err(ReadingError::UnconsistentDataSize)
                } else if data != Vec::from_elem(16, 0) {
-                  return Err(DataError)
+                  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 +269,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<u8> {
    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()
 }