Update the report.
[crypto_lab1.git] / lab1_rust / src / oracle_machine.rs
1 use std::io;
2 use std::io::TcpStream;
3 use std::iter::range_inclusive;
4 use std::slice::bytes::copy_memory;
5 use packet;
6 use packet::{ Packet, Error };
7 use end_point::EndPoint;
8
9 /// Try to decipher a ciphered data block by using the previous XOR operand and an oracle on the provided address and port.
10 /// May print some message on stdout.
11 pub fn decipher(address: &str, port: u16, original_xor_operand: &[u8, ..16], cipherblock: &[u8, ..16], variant: packet::Variant) -> Option<Vec<u8>> {
12 let mut end_point = EndPoint::new(
13 match TcpStream::connect(address, port) {
14 Ok(s) => s,
15 _ => {
16 println!("Unable to connect to the oracle on [{}]:{}", address, port);
17 return None
18 }
19 },
20 variant,
21 );
22
23 // See 'packet::Packet' documentation for a complete description about the binary packet structure.
24 let mut final_packet = [0u8, ..2 + 1 + 8 + 32 + 10];
25 final_packet[1] = (final_packet.len() as u8) - 2; // Data length.
26 copy_memory(final_packet.slice_mut(2 + 1 + 8 + 16, 2 + 1 + 8 + 32), cipherblock);
27
28 let mut decipher_block = [0u8, ..16]; // The result.
29 let mut x_prime_block = [0u8, ..16]; // The cipher block ('cipherblock') after AES and before XOR.
30 let mut current_timestamp = 0u64;
31 let mut first_byte = 0u8; // Used to save the first byte for the first iteration.
32
33 #[inline(always)]
34 fn forged_xor_operand(packet: &mut [u8]) -> &mut [u8] { packet.slice_mut(2 + 1 + 8, 2 + 1 + 8 + 16) }
35
36 // For each bytes.
37 let mut byte = 15;
38 'main_loop: loop {
39 let mut get_mac_mismatch_error = false; // For the first byte we need to insure there is only one AUTH error (one valid padding).
40
41 for v in range_inclusive(0u8, 255) { // For each values of the current byte.
42
43 // Compute and write timestamp.
44 current_timestamp += 2;
45 {
46 let mut timestamp_writer = io::BufWriter::new(final_packet.slice_mut(2 + 1, 2 + 1 + 8));
47 let _ = timestamp_writer.write_be_u64(current_timestamp - 1);
48 }
49
50 forged_xor_operand(&mut final_packet)[byte] = v;
51
52 match end_point.send_raw_with_result(final_packet) {
53 Ok(Ok(p @ Packet { t: Error(packet::AuthError), .. })) => {
54 println!("We received a MAC Error: {}", p);
55
56 // If we already got a MAC mismatch for the first byte then the second byte is incremented and the loop is replayed.
57 if byte == 15 && get_mac_mismatch_error {
58 forged_xor_operand(&mut final_packet)[14] += 1;
59 continue 'main_loop;
60 }
61
62 get_mac_mismatch_error = true;
63
64 let padding_value = 16 - byte;
65 x_prime_block[byte] = v ^ (padding_value as u8);
66 decipher_block[byte] = x_prime_block[byte] ^ original_xor_operand[byte];
67
68 // We set the processed bytes of the forged XOR operand to have the next padding value (2, 3, 4, etc..).
69 for i in range(16 - padding_value, 16) {
70 forged_xor_operand(&mut final_packet)[i] = x_prime_block[i] ^ ((padding_value as u8) + 1);
71 }
72
73 // Special case for the first byte: we have to test all the values to avoid a valid padding
74 // which is not [.., 0x01], for instance [.., 0x02, 0x02]. It's a very rare case but not impossible.
75 if byte == 15 {
76 first_byte = forged_xor_operand(&mut final_packet)[15];
77 } else {
78 break;
79 }
80 },
81 Ok(Ok(Packet { t: Error(packet::CryptError), .. })) => (), // Ignored case: the padding is wrong.
82 other => {
83 println!("Unexcepted response, aborting. {}", other);
84 return None
85 }
86 }
87 }
88
89 if byte == 15 {
90 forged_xor_operand(&mut final_packet)[15] = first_byte;
91 }
92
93 // It was the last byte.
94 if byte == 0 { break; }
95
96 byte -= 1;
97 }
98
99 Some(decipher_block.to_vec())
100 }