* Oracle machine finished.
[crypto_lab1.git] / lab1_rust / src / packet.rs
index 73eecea..95468a1 100644 (file)
@@ -5,6 +5,11 @@ use std::rand::distributions::IndependentSample;
 use serialize::hex::{ ToHex };
 use crypto;
 
+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)]
 pub enum ReadingError {
@@ -78,7 +83,9 @@ pub enum PacketType {
 ///            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
+///      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)]
 pub struct Packet {
@@ -114,15 +121,15 @@ impl Packet {
       PacketData { id: id, payload: payload }
    }
 
-   pub fn write(&self, output: &mut io::Writer) -> WritingResult {
-      self.write_with_padding_fun(output, |_, padding_length: uint| -> u8 {
+   pub fn write(&self, output: &mut io::Writer, variant: Variant) -> WritingResult {
+      self.write_with_padding_fun(output, variant, |_, 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 {
+   pub fn write_with_padding_fun(&self, output: &mut io::Writer, variant: Variant, padd_fun: |uint, uint| -> u8) -> WritingResult {
       fn packet_data(p: &PacketData) -> Vec<u8> {
          let mut d = Vec::new();
          d.push(p.id);
@@ -137,8 +144,7 @@ impl Packet {
             Error(_) => Vec::from_elem(16, 0) // Padding as data: 16 * 0.
          };
 
-      // Compute the MAC
-      let mac = crypto::compute_mac(data.as_slice());
+      let data_size = data.len();
 
       // Padding.
       match self.t {
@@ -152,6 +158,9 @@ impl Packet {
          _ => ()
       }
 
+      // Compute the MAC. It depends the choosen variant.
+      let mac = crypto::compute_mac(data.slice_to(match variant { Weak => data_size, _ => data.len() }));
+
       // Encrypt.
       let encrypted_data = match crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice()) {
          Some(d) => d,
@@ -183,7 +192,7 @@ impl Packet {
       Ok(())
    }
 
-   pub fn read(input: &mut io::Reader) -> ReadingResult {
+   pub fn read(input: &mut io::Reader, variant: Variant) -> ReadingResult {
       fn consume(input: &mut io::Reader, nb_byte: uint) {
          let _ = input.read_exact(nb_byte);
       }
@@ -208,12 +217,19 @@ impl Packet {
          _ => return Err(UnconsistentEncryptedSizeError)
       };
 
+      // Read the MAC.
+      let mut mac_read = [0u8, ..10];
+      if try_read_io!(input.read(mac_read)) != mac_read.len() {
+         return Err(UnconsistentMACSizeError)
+      }
+
+      match variant { Fixed if mac_read != crypto::compute_mac(data.as_slice()) => return Err(MACMismatchError), _ => () };
+
       // 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);
+               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)
                }
                let data_length = data.len() - padding_size as uint;
@@ -224,15 +240,7 @@ impl Packet {
          }
       }
 
-      // 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)
-      }
+      match variant { Weak if mac_read != crypto::compute_mac(data.as_slice()) => return Err(MACMismatchError), _ => () };
 
       Ok(Packet {
          t: match packet_type {