3 use std
::rand
::{ Rng
, StdRng
, SeedableRng
, distributions
};
4 use std
::rand
::distributions
::IndependentSample
;
5 use serialize
::hex
::{ ToHex
};
8 // There are all the errors that may occur when reading an encrypted and authenticated packet.
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.
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
)) })
27 // There are all the errors that may occur when encrypting, authenticating and writing a packet.
29 pub enum WritingError
{
30 WriteIOError(io
::IoError
)
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
)) })
39 pub type ReadingResult
= Result
<Packet
, ReadingError
>;
40 pub type WritingResult
= Result
<(), WritingError
>;
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.
46 #[deriving(Show, Clone)]
47 pub struct PacketData
{
49 payload
: Vec
<u8> // The size can vary from 'MIN_PAYLOAD_SIZE' to 'MAX_PAYLOAD_SIZE' bytes.
52 #[deriving(Show, Clone)]
65 /// Serialized packet format : |LL|P|TTTTTTTT|D...D|MMMMMMMMMM|
67 /// LL: Size on the following data
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:
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 ans answer packet
82 /// |0000000000000000| for error packet
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())
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
)
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_());
113 pub fn new_packet_data(id
: u8, payload
: Vec
<u8>) -> PacketData
{
114 PacketData
{ id
: id
, payload
: payload
}
117 pub fn write(&self, output
: &mut io
::Writer
) -> WritingResult
{
118 self.write_with_padding_fun(output
, |_
: uint
, padding_length
: uint
| -> u8 {
123 /// 'padd_fun' is function to fill 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();
129 d
.push_all(p
.payload
.as_slice());
133 // Data to be encrypted.
136 Command(ref p
) | Answer(ref p
) => packet_data(p
),
137 Error(_
) => Vec
::from_elem(16, 0) // Padding as data: 16 * 0.
141 let mac
= crypto
::compute_mac(data
.as_slice());
145 Command(_
) | Answer(_
) => {
146 let padding_size
= if data
.len() % 16 == 0 { 16 } else { 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
));
155 println!("data not crypted: {}", data
);
158 let encrypted_data
= crypto
::encrypt(data
.as_slice(), iv_from_timestamp(self.timestamp
).as_slice());
160 println!("data crypted: {}", encrypted_data
);
162 // Write packet length.
163 try_write_io!(output
.write_be_u16((encrypted_data
.len() + FIXED_PACKET_SIZE
) as u16));
165 // Write packet type.
166 try_write_io!(output
.write_u8(
170 Error(CryptError
) => 0x0A,
171 Error(AuthError
) => 0x0B
176 try_write_io!(output
.write_be_u64(self.timestamp
));
178 // Write encrypted data.
179 try_write_io!(output
.write(encrypted_data
.as_slice()));
182 try_write_io!(output
.write(mac
));
187 pub fn read(input
: &mut io
::Reader
) -> ReadingResult
{
188 fn consume(input
: &mut io
::Reader
, nb_byte
: uint
) {
189 let _
= input
.read_exact(nb_byte
);
192 let data_size
= try_read_io!(input
.read_be_u16());
194 // Read and check the packet type.
195 let packet_type
= try_read_io!(input
.read_u8());
196 if ![0x00, 0xFF, 0x0A, 0x0B].iter().any(|p
| *p
== packet_type
) {
197 consume(input
, data_size
as uint
- 1);
198 return Err(UnknownPacketTypeError
)
201 let timestamp
= try_read_io!(input
.read_be_u64());
203 let mut encrypted_data
= Vec
::from_elem(data_size
as uint
- FIXED_PACKET_SIZE
, 0u8);
204 if try_read_io!(input
.read(encrypted_data
.as_mut_slice_())) != encrypted_data
.len() {
205 return Err(UnconsistentEncryptedSizeError
)
207 let mut data
= crypto
::decrypt(encrypted_data
.as_slice(), iv_from_timestamp(timestamp
).as_slice());
209 // Control the size and the content of the padding then remove it.
210 if packet_type
== 0x00 || packet_type
== 0xFF {
212 Some(&padding_size
) => {
213 if padding_size
as uint
> data
.len() || !data
.slice_from(data
.len() - padding_size
as uint
).iter().any(|b
| *b
== padding_size
) {
215 return Err(PaddingError
)
217 let data_length
= data
.len() - padding_size
as uint
;
218 data
.truncate(data_length
);
221 return Err(PaddingError
)
225 // Read an verify the MAC.
226 let mut mac_read
= [0u8, ..10];
227 if try_read_io!(input
.read(mac_read
)) != mac_read
.len() {
228 return Err(UnconsistentMACSizeError
)
230 let mac_data
= crypto
::compute_mac(data
.as_slice());
231 if mac_read
!= mac_data
{
232 return Err(MACMismatchError
)
236 t
: match packet_type
{
237 // Command or answer.
239 if data
.len() < MIN_PAYLOAD_SIZE
+ 1 || data
.len() > MAX_PAYLOAD_SIZE
+ 1 {
240 return Err(UnconsistentDataSizeError
)
242 let pd
= PacketData
{ id
: data
[0], payload
: data
.tail().to_vec() }; // match data.as_slice() { [id, payload..] => PacketData { id: id, payload: payload.to_vec() } };
243 match packet_type
{ 0x00 => Command(pd
), _
=> Answer(pd
) }
247 if data
.len() != 16 {
248 return Err(UnconsistentDataSizeError
)
249 } else if data
!= Vec
::from_elem(16, 0) {
250 return Err(DataError
)
252 match packet_type
{ 0x0A => Error(CryptError
), _
=> Error(AuthError
) }
260 // Build an initialization vector: 64 * 0u8 + timestamp (128 bits).
261 fn iv_from_timestamp(timestamp
: u64) -> Vec
<u8> {
262 let mut iv
= io
::MemWriter
::with_capacity(16);
263 let _
= iv
.write_be_u64(0u64);
264 let _
= iv
.write_be_u64(timestamp
);