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