* Oracle machine finished.
[crypto_lab1.git] / lab1_rust / src / oracle_machine.rs
index 68aef94..2feb31b 100644 (file)
@@ -1,19 +1,97 @@
 use std::io;
 use std::io::{ TcpStream };
+use std::iter::{ range_inclusive };
+use std::slice::bytes::copy_memory;
+use packet;
+use packet::{ Packet, Error };
 use end_point::EndPoint;
 
-/// Try to decypher a cyphered data block by using an oracle on the provided address and port.
+/// Try to decypher a cyphered data block by using the previous xor operand and an oracle on the provided address and port.
 /// May prints some message on the stdout.
-pub fn decypher(address: &str, port: u16, cypherblock: [u8, ..16]) -> Option<Vec<u8>> {
-   let end_point = EndPoint::new(
+pub fn decypher(address: &str, port: u16, original_xor_operand: &[u8, ..16], cypherblock: &[u8, ..16], variant: packet::Variant) -> Option<Vec<u8>> {
+   let mut end_point = EndPoint::new(
       match TcpStream::connect(address, port) {
          Ok(s) => s,
          _ => {
-            println!("Unable to connect to the oracle on {}:{}", address, port);
+            println!("Unable to connect to the oracle on [{}]:{}", address, port);
             return None
          }
-      }
+      },
+      variant,
    );
 
-   None
-}
+   let mut final_packet = [0u8, ..2 + 1 + 8 + 32 + 10];
+   final_packet[1] = 1 + 8 + 32 + 10; // Data length.
+   copy_memory(final_packet.slice_mut(2 + 1 + 8 + 16, 2 + 1 + 8 + 32), cypherblock);
+
+   let mut decypher_block = [0u8, ..16]; // The result.
+   let mut x_prime_block = [0u8, ..16]; // The cypher block ('cypherblock') after AES and before XOR.
+   let mut current_timestamp = 0u64;
+   let mut first_byte = 0u8; // Used to save the first byte for the first iteration.
+
+   #[inline(always)]
+   fn forged_xor_operand(packet: &mut [u8]) -> &mut [u8] { packet.slice_mut(2 + 1 + 8, 2 + 1 + 8 + 16) }
+
+   // For each bytes.
+   let mut byte = 15;
+   'main_loop: loop {
+      let mut get_mac_mismatch_error = false; // For the first byte we need to insure there is only one AUTH error (one valid padding).
+
+      for v in range_inclusive(0u8, 255) { // For each values of the current byte.
+
+         // Compute and write timestamp.
+         current_timestamp += 2;
+         {
+            let mut timestamp_writer = io::BufWriter::new(final_packet.slice_mut(2 + 1, 2 + 1 + 8));
+            let _ = timestamp_writer.write_be_u64(current_timestamp - 1);
+         }
+
+         forged_xor_operand(&mut final_packet)[byte] = v;
+
+         match end_point.send_raw_with_result(final_packet) {
+            Ok(Ok(Packet { t: Error(packet::AuthError), .. })) => {
+
+               // If we already got a MAC mismatch for the first byte then the second byte is incremented and the loop is replayed.
+               if byte == 15 && get_mac_mismatch_error {
+                  forged_xor_operand(&mut final_packet)[14] += 1;
+                  continue 'main_loop;
+               }
+
+               get_mac_mismatch_error = true;
+
+               let padding_value = 16 - byte;
+               x_prime_block[byte] = v ^ (padding_value as u8);
+               decypher_block[byte] = x_prime_block[byte] ^ original_xor_operand[byte];
+
+               // We set the processed bytes of the forged XOR operand to have the next padding value.
+               for i in range(16 - padding_value, 16) {
+                  forged_xor_operand(&mut final_packet)[i] = x_prime_block[i] ^ ((padding_value as u8) + 1);
+               }
+
+               // Special case for the first byte: we have to test all the values.
+               if byte == 15 {
+                  first_byte = forged_xor_operand(&mut final_packet)[15];
+               } else {
+                  break;
+               }
+            },
+            Ok(Ok(Packet { t: Error(packet::CryptError), .. })) => (), // Ignored case: the padding is wrong.
+            other => {
+               println!("Unexcepted response, aborting. {}", other);
+               return None
+            }
+         }
+      }
+
+      if byte == 15 {
+         forged_xor_operand(&mut final_packet)[15] = first_byte;
+      }
+
+      // It was the last byte.
+      if byte == 0 { break; }
+
+      byte -= 1;
+   }
+
+   Some(decypher_block.to_vec())
+}
\ No newline at end of file