3 use std
::rand
::{ random
, task_rng
, distributions
};
4 use std
::rand
::distributions
::IndependentSample
;
7 // There are all the errors that may occur when reading an encrypted and authenticated packet.
9 pub enum ReadingError
{
10 IOReadError(io
::IoError
),
11 UnknownPacketTypeReadError
, // If the first byte is unknown.
12 UnconsistentEncryptedSizeError
,
13 UnconsistentDataSizeError
, // The data size is not valid.
14 UnconsistentMACSizeError
, // The MAC hasn't the correct size.
15 MACMismatchError
, // The uncrypted received data doesn't match to the received MAC.
16 PaddingError
, // Padding format error.
17 DataError
, // The data are invalid.
20 // A macro to return a 'IOReadError' in case of error.
21 macro_rules
! try_read_io(
22 ($e
:expr
) => (match $e
{ Ok(e
) => e
, Err(e
) => return Err(IOReadError(e
)) })
25 // There are all the errors that may occur when encrypting, authenticating and writing a packet.
27 pub enum WritingError
{
28 WriteIOError(io
::IoError
)
32 // A macro to return a 'IOWritingError' in case of error.
33 macro_rules
! try_write_io(
34 ($e
:expr
) => (match $e
{ Ok(e
) => e
, Err(e
) => return Err(WriteIOError(e
)) })
37 pub type ReadingResult
= Result
<Packet
, ReadingError
>;
38 pub type WritingResult
= Result
<(), WritingError
>;
40 static MIN_PAYLOAD_SIZE
: uint
= 7;
41 static MAX_PAYLOAD_SIZE
: uint
= 39;
42 static FIXED_PACKET_SIZE
: uint
= 1 + 8 + 10; // Packet type + timestamp + MAC.
45 pub struct PacketData
{
47 payload
: Vec
<u8> // The size can vary from 'MIN_PAYLOAD_SIZE' to 'MAX_PAYLOAD_SIZE' bytes.
68 impl fmt
::Show
for Packet
{
69 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
70 fn data_to_str(data
: &PacketData
) -> String
{
71 format!("id: {}, payload({}): {}", data
.id
, data
.payload
.len(), data
.payload
)
74 Command(ref data
) => write!(formatter
, "Command packet {{ timestamp: {}, {} }}", self.timestamp
, data_to_str(data
)),
75 Answer(ref data
) => write!(formatter
, "Answer packet {{ timestamp: {}, {} }}", self.timestamp
, data_to_str(data
)),
76 Error(error_type
) => write!(formatter
, "Error packet {{ timestamp: {}, errorType: {} }}", self.timestamp
, error_type
)
82 pub fn random_packet_data() -> PacketData
{
83 let mut rng
= task_rng();
86 payload
: Vec
::from_fn(distributions
::Range
::new(MIN_PAYLOAD_SIZE
, MAX_PAYLOAD_SIZE
+ 1).ind_sample(&mut rng
), |_
| random
::<u8>())
90 pub fn write(&self, output
: &mut io
::Writer
) -> WritingResult
{
91 fn packet_data(p
: &PacketData
) -> Vec
<u8> {
92 let mut d
= Vec
::new();
94 d
.push_all(p
.payload
.as_slice());
98 // Data to be encrypted.
101 Command(ref p
) | Answer(ref p
) => packet_data(p
),
102 Error(_
) => Vec
::from_elem(16, '
0'
as u8) // Padding as data: 16 * '0'.
106 let mac
= crypto
::compute_mac(data
.as_slice());
110 Command(_
) | Answer(_
) => {
111 let padding_size
= if data
.len() % 16 == 0 { 16 } else { data
.len() % 16 } ;
112 data
.push_all(Vec
::from_elem(padding_size
, padding_size
as u8).as_slice());
118 let encrypted_data
= crypto
::encrypt(data
.as_slice(), iv_from_timestamp(self.timestamp
).as_slice());
120 // Write packet length.
121 try_write_io!(output
.write_be_u16((encrypted_data
.len() + FIXED_PACKET_SIZE
) as u16));
123 // Write packet type.
124 try_write_io!(output
.write_u8(
128 Error(CryptError
) => 0x0A,
129 Error(AuthError
) => 0x0B
134 try_write_io!(output
.write_be_u64(self.timestamp
));
136 // Write encrypted data.
137 try_write_io!(output
.write(encrypted_data
.as_slice()));
140 try_write_io!(output
.write(mac
));
145 pub fn read(input
: &mut io
::Reader
) -> ReadingResult
{
146 let data_size
= try_read_io!(input
.read_be_u16());
147 let packet_type
= try_read_io!(input
.read_u8());
148 let timestamp
= try_read_io!(input
.read_be_u64());
150 let mut encrypted_data
= Vec
::from_elem(data_size
as uint
- FIXED_PACKET_SIZE
, 0u8);
151 if try_read_io!(input
.read(encrypted_data
.as_mut_slice_())) != encrypted_data
.len() {
152 return Err(UnconsistentEncryptedSizeError
)
154 let mut data
= crypto
::decrypt(encrypted_data
.as_slice(), iv_from_timestamp(timestamp
).as_slice());
156 // Control the size and the content of the padding then remove it.
157 if packet_type
== 0x00 || packet_type
== 0xFF {
159 Some(&padding_size
) => {
160 if padding_size
as uint
> data
.len() || !data
.slice_from(data
.len() - padding_size
as uint
).iter().any(|b
| *b
== padding_size
) {
161 return Err(PaddingError
)
163 let data_length
= data
.len() - padding_size
as uint
;
164 data
.truncate(data_length
);
167 return Err(PaddingError
)
171 // Read an verify the MAC.
172 let mut mac_read
= [0u8, ..10];
173 if try_read_io!(input
.read(mac_read
)) != mac_read
.len() {
174 return Err(UnconsistentMACSizeError
)
176 let mac_data
= crypto
::compute_mac(data
.as_slice());
177 if mac_read
!= mac_data
{
178 return Err(MACMismatchError
)
182 t
: match packet_type
{
184 if data
.len() < MIN_PAYLOAD_SIZE
+ 1 || data
.len() > MAX_PAYLOAD_SIZE
+ 1 {
185 return Err(UnconsistentDataSizeError
)
187 let pd
= PacketData
{ id
: data
[0], payload
: data
.tail().to_vec() }; // match data.as_slice() { [id, payload..] => PacketData { id: id, payload: payload.to_vec() } };
188 match packet_type
{ 0x00 => Command(pd
), _
=> Answer(pd
) }
191 if data
.len() != 16 {
192 return Err(UnconsistentDataSizeError
)
193 } else if data
!= Vec
::from_elem(16, '
0'
as u8) {
194 return Err(DataError
)
196 match packet_type
{ 0x0A => Error(CryptError
), _
=> Error(AuthError
) }
199 return Err(UnknownPacketTypeReadError
)
206 // Build an initialization vector: 64 * 0u8 + timestamp (128 bits).
207 fn iv_from_timestamp(timestamp
: u64) -> Vec
<u8> {
208 let mut iv
= io
::MemWriter
::with_capacity(16);
209 let _
= iv
.write_be_u64(0u64);
210 let _
= iv
.write_be_u64(timestamp
);