73eecea9ad1cb7948f7bd83948296fdd00ee92dc
[crypto_lab1.git] / src / packet.rs
1 use std::io;
2 use std::fmt;
3 use std::rand::{ Rng, StdRng, SeedableRng, distributions };
4 use std::rand::distributions::IndependentSample;
5 use serialize::hex::{ ToHex };
6 use crypto;
7
8 // There are all the errors that may occur when reading an encrypted and authenticated packet.
9 #[deriving(Show)]
10 pub enum ReadingError {
11 IOReadError(io::IoError),
12 UnknownPacketTypeError, // If the first byte is unknown.
13 UnconsistentEncryptedSizeError,
14 UnconsistentDataSizeError, // The data size is not valid.
15 UnconsistentMACSizeError, // The MAC hasn't the correct size.
16 MACMismatchError, // The uncrypted received data doesn't match to the received MAC.
17 PaddingError, // Padding format error.
18 DataError, // The data are invalid.
19 InvalidTimestampError
20 }
21
22 // A macro to return a 'IOReadError' in case of error.
23 macro_rules! try_read_io(
24 ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(IOReadError(e)) })
25 )
26
27 // There are all the errors that may occur when encrypting, authenticating and writing a packet.
28 #[deriving(Show)]
29 pub enum WritingError {
30 WriteIOError(io::IoError),
31 EncryptError,
32 }
33
34 // A macro to return a 'IOWritingError' in case of error.
35 macro_rules! try_write_io(
36 ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(WriteIOError(e)) })
37 )
38
39 pub type ReadingResult = Result<Packet, ReadingError>;
40 pub type WritingResult = Result<(), WritingError>;
41
42 static MIN_PAYLOAD_SIZE: uint = 7;
43 static MAX_PAYLOAD_SIZE: uint = 39;
44 static FIXED_PACKET_SIZE: uint = 1 + 8 + 10; // Packet type + timestamp + MAC.
45
46 #[deriving(Show, Clone)]
47 pub struct PacketData {
48 id: u8,
49 payload: Vec<u8> // The size can vary from 'MIN_PAYLOAD_SIZE' to 'MAX_PAYLOAD_SIZE' bytes.
50 }
51
52 #[deriving(Show, Clone)]
53 pub enum ErrorType {
54 CryptError,
55 AuthError
56 }
57
58 #[deriving(Clone)]
59 pub enum PacketType {
60 Command(PacketData),
61 Answer(PacketData),
62 Error(ErrorType),
63 }
64
65 /// Serialized packet format : |LL|P|TTTTTTTT|D...D|MMMMMMMMMM|
66 /// Where:
67 /// LL: Size of the following data
68 /// P: Packet type:
69 /// 0x00: Command
70 /// OxFF: Answer
71 /// 0x0A: Decrypt error
72 /// 0x0B: Authentication error
73 /// TTTTTTTT: Timestamp (64 bits)
74 /// D...D: Encrypted data (AES-256 CBC mode) of:
75 /// |I|C...C|P...P| for command and answer packet:
76 /// I: Command ID
77 /// C: Command payload (from 7 to 39 bytes)
78 /// P: Padding from 1 to 16, |I|C...C|P...P| size must be a multiple of 16
79 /// |0000000000000000| for error packet (16 bytes length)
80 /// MMMMMMMMMM: first 10 bytes (most significant) of the HMAC-SHA256 of:
81 /// |I|C...C| for command and answer packet
82 /// |0000000000000000| for error packet
83 #[deriving(Show)]
84 pub struct Packet {
85 pub t: PacketType,
86 pub timestamp: u64
87 }
88
89 impl fmt::Show for PacketType {
90 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
91 fn data_to_str(data: &PacketData) -> String {
92 format!("id: {}, payload({}): \"{}\"", data.id, data.payload.len(), data.payload.as_slice().to_hex())
93 }
94 match self {
95 &Command(ref data) => write!(formatter, "Command {{ {} }}", data_to_str(data)),
96 &Answer(ref data) => write!(formatter, "Answer {{ {} }}", data_to_str(data)),
97 &Error(error_type) => write!(formatter, "Error {{ errorType: {} }}", error_type)
98 }
99 }
100 }
101
102 impl Packet {
103 pub fn random_packet_data(seed: &[uint]) -> PacketData {
104 let mut rng = if seed.is_empty() { StdRng::new().unwrap() } else { SeedableRng::from_seed(seed) };
105 let mut payload = Vec::from_elem(distributions::Range::new(MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE + 1).ind_sample(&mut rng), 0u8);
106 rng.fill_bytes(payload.as_mut_slice_());
107 PacketData {
108 id: rng.gen::<u8>(),
109 payload: payload
110 }
111 }
112
113 pub fn new_packet_data(id: u8, payload: Vec<u8>) -> PacketData {
114 PacketData { id: id, payload: payload }
115 }
116
117 pub fn write(&self, output: &mut io::Writer) -> WritingResult {
118 self.write_with_padding_fun(output, |_, padding_length: uint| -> u8 {
119 padding_length as u8
120 })
121 }
122
123 /// 'padd_fun' is function defining the padding. The first argument is the index of the current byte, starting at 0.
124 /// The second argument is the padding length.
125 pub fn write_with_padding_fun(&self, output: &mut io::Writer, padd_fun: |uint, uint| -> u8) -> WritingResult {
126 fn packet_data(p: &PacketData) -> Vec<u8> {
127 let mut d = Vec::new();
128 d.push(p.id);
129 d.push_all(p.payload.as_slice());
130 d
131 }
132
133 // Data to be encrypted.
134 let mut data =
135 match self.t {
136 Command(ref p) | Answer(ref p) => packet_data(p),
137 Error(_) => Vec::from_elem(16, 0) // Padding as data: 16 * 0.
138 };
139
140 // Compute the MAC
141 let mac = crypto::compute_mac(data.as_slice());
142
143 // Padding.
144 match self.t {
145 Command(_) | Answer(_) => {
146 let padding_size = if data.len() % 16 == 0 { 16 } else { 16 - data.len() % 16 } ;
147 data.reserve_additional(padding_size);
148 for i in range(0, padding_size) {
149 data.push(padd_fun(i, padding_size));
150 }
151 },
152 _ => ()
153 }
154
155 // Encrypt.
156 let encrypted_data = match crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice()) {
157 Some(d) => d,
158 _ => return Err(EncryptError)
159 };
160
161 // Write packet length.
162 try_write_io!(output.write_be_u16((encrypted_data.len() + FIXED_PACKET_SIZE) as u16));
163
164 // Write packet type.
165 try_write_io!(output.write_u8(
166 match self.t {
167 Command(_) => 0x00,
168 Answer(_) => 0xFF,
169 Error(CryptError) => 0x0A,
170 Error(AuthError) => 0x0B
171 }
172 ));
173
174 // Write timestamp.
175 try_write_io!(output.write_be_u64(self.timestamp));
176
177 // Write encrypted data.
178 try_write_io!(output.write(encrypted_data.as_slice()));
179
180 // Write the MAC.
181 try_write_io!(output.write(mac));
182
183 Ok(())
184 }
185
186 pub fn read(input: &mut io::Reader) -> ReadingResult {
187 fn consume(input: &mut io::Reader, nb_byte: uint) {
188 let _ = input.read_exact(nb_byte);
189 }
190
191 let data_size = try_read_io!(input.read_be_u16());
192
193 // Read and check the packet type.
194 let packet_type = try_read_io!(input.read_u8());
195 if ![0x00, 0xFF, 0x0A, 0x0B].iter().any(|p| *p == packet_type) {
196 consume(input, data_size as uint - 1);
197 return Err(UnknownPacketTypeError)
198 }
199
200 let timestamp = try_read_io!(input.read_be_u64());
201
202 let mut encrypted_data = Vec::from_elem(data_size as uint - FIXED_PACKET_SIZE, 0u8);
203 if try_read_io!(input.read(encrypted_data.as_mut_slice_())) != encrypted_data.len() {
204 return Err(UnconsistentEncryptedSizeError)
205 }
206 let mut data = match crypto::decrypt(encrypted_data.as_slice(), iv_from_timestamp(timestamp).as_slice()) {
207 Some(d) => d,
208 _ => return Err(UnconsistentEncryptedSizeError)
209 };
210
211 // Control the size and the content of the padding then remove it.
212 if packet_type == 0x00 || packet_type == 0xFF {
213 match data.last() {
214 Some(&padding_size) => {
215 if padding_size as uint > data.len() || !data.slice_from(data.len() - padding_size as uint).iter().any(|b| *b == padding_size) {
216 consume(input, 10);
217 return Err(PaddingError)
218 }
219 let data_length = data.len() - padding_size as uint;
220 data.truncate(data_length);
221 },
222 None =>
223 return Err(PaddingError)
224 }
225 }
226
227 // Read an verify the MAC.
228 let mut mac_read = [0u8, ..10];
229 if try_read_io!(input.read(mac_read)) != mac_read.len() {
230 return Err(UnconsistentMACSizeError)
231 }
232 let mac_data = crypto::compute_mac(data.as_slice());
233 if mac_read != mac_data {
234 return Err(MACMismatchError)
235 }
236
237 Ok(Packet {
238 t: match packet_type {
239 // Command or answer.
240 0x00 | 0xFF => {
241 if data.len() < MIN_PAYLOAD_SIZE + 1 || data.len() > MAX_PAYLOAD_SIZE + 1 {
242 return Err(UnconsistentDataSizeError)
243 }
244 let pd = PacketData { id: data[0], payload: data.tail().to_vec() }; // match data.as_slice() { [id, payload..] => PacketData { id: id, payload: payload.to_vec() } };
245 match packet_type { 0x00 => Command(pd), _ => Answer(pd) }
246 },
247 // Error.
248 _ => {
249 if data.len() != 16 {
250 return Err(UnconsistentDataSizeError)
251 } else if data != Vec::from_elem(16, 0) {
252 return Err(DataError)
253 }
254 match packet_type { 0x0A => Error(CryptError), _ => Error(AuthError) }
255 }
256 },
257 timestamp: timestamp
258 })
259 }
260 }
261
262 // Build an initialization vector: 64 * 0u8 + timestamp (128 bits).
263 fn iv_from_timestamp(timestamp: u64) -> Vec<u8> {
264 let mut iv = io::MemWriter::with_capacity(16);
265 let _ = iv.write_be_u64(0u64);
266 let _ = iv.write_be_u64(timestamp);
267 iv.unwrap()
268 }