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 /// |"0000000000"| 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 write(&self, output
: &mut io
::Writer
) -> WritingResult
{
114 fn packet_data(p
: &PacketData
) -> Vec
<u8> {
115 let mut d
= Vec
::new();
117 d
.push_all(p
.payload
.as_slice());
121 // Data to be encrypted.
124 Command(ref p
) | Answer(ref p
) => packet_data(p
),
125 Error(_
) => Vec
::from_elem(16, '
0'
as u8) // Padding as data: 16 * '0'.
129 let mac
= crypto
::compute_mac(data
.as_slice());
133 Command(_
) | Answer(_
) => {
134 let padding_size
= if data
.len() % 16 == 0 { 16 } else { data
.len() % 16 } ;
135 data
.push_all(Vec
::from_elem(padding_size
, padding_size
as u8).as_slice());
141 let encrypted_data
= crypto
::encrypt(data
.as_slice(), iv_from_timestamp(self.timestamp
).as_slice());
143 // Write packet length.
144 try_write_io!(output
.write_be_u16((encrypted_data
.len() + FIXED_PACKET_SIZE
) as u16));
146 // Write packet type.
147 try_write_io!(output
.write_u8(
151 Error(CryptError
) => 0x0A,
152 Error(AuthError
) => 0x0B
157 try_write_io!(output
.write_be_u64(self.timestamp
));
159 // Write encrypted data.
160 try_write_io!(output
.write(encrypted_data
.as_slice()));
163 try_write_io!(output
.write(mac
));
168 pub fn read(input
: &mut io
::Reader
) -> ReadingResult
{
169 fn consume(input
: &mut io
::Reader
, nb_byte
: uint
) {
170 let _
= input
.read_exact(nb_byte
);
173 let data_size
= try_read_io!(input
.read_be_u16());
175 // Read and check the packet type.
176 let packet_type
= try_read_io!(input
.read_u8());
177 if ![0x00, 0xFF, 0x0A, 0x0B].iter().any(|p
| *p
== packet_type
) {
178 consume(input
, data_size
as uint
- 1);
179 return Err(UnknownPacketTypeError
)
182 let timestamp
= try_read_io!(input
.read_be_u64());
184 let mut encrypted_data
= Vec
::from_elem(data_size
as uint
- FIXED_PACKET_SIZE
, 0u8);
185 if try_read_io!(input
.read(encrypted_data
.as_mut_slice_())) != encrypted_data
.len() {
186 return Err(UnconsistentEncryptedSizeError
)
188 let mut data
= crypto
::decrypt(encrypted_data
.as_slice(), iv_from_timestamp(timestamp
).as_slice());
190 // Control the size and the content of the padding then remove it.
191 if packet_type
== 0x00 || packet_type
== 0xFF {
193 Some(&padding_size
) => {
194 if padding_size
as uint
> data
.len() || !data
.slice_from(data
.len() - padding_size
as uint
).iter().any(|b
| *b
== padding_size
) {
195 return Err(PaddingError
)
197 let data_length
= data
.len() - padding_size
as uint
;
198 data
.truncate(data_length
);
201 return Err(PaddingError
)
205 // Read an verify the MAC.
206 let mut mac_read
= [0u8, ..10];
207 if try_read_io!(input
.read(mac_read
)) != mac_read
.len() {
208 return Err(UnconsistentMACSizeError
)
210 let mac_data
= crypto
::compute_mac(data
.as_slice());
211 if mac_read
!= mac_data
{
212 return Err(MACMismatchError
)
216 t
: match packet_type
{
217 // Command or answer.
219 if data
.len() < MIN_PAYLOAD_SIZE
+ 1 || data
.len() > MAX_PAYLOAD_SIZE
+ 1 {
220 return Err(UnconsistentDataSizeError
)
222 let pd
= PacketData
{ id
: data
[0], payload
: data
.tail().to_vec() }; // match data.as_slice() { [id, payload..] => PacketData { id: id, payload: payload.to_vec() } };
223 match packet_type
{ 0x00 => Command(pd
), _
=> Answer(pd
) }
227 if data
.len() != 16 {
228 return Err(UnconsistentDataSizeError
)
229 } else if data
!= Vec
::from_elem(16, '
0'
as u8) {
230 return Err(DataError
)
232 match packet_type
{ 0x0A => Error(CryptError
), _
=> Error(AuthError
) }
240 // Build an initialization vector: 64 * 0u8 + timestamp (128 bits).
241 fn iv_from_timestamp(timestamp
: u64) -> Vec
<u8> {
242 let mut iv
= io
::MemWriter
::with_capacity(16);
243 let _
= iv
.write_be_u64(0u64);
244 let _
= iv
.write_be_u64(timestamp
);