Skip to main content

over_there/core/transport/wire/output/
mod.rs

1pub mod encoder;
2
3use crate::core::transport::crypto::{CryptError, Encrypter};
4use crate::core::transport::{auth::Signer, wire::packet::PacketEncryption};
5use derive_more::{Display, Error};
6use encoder::{EncodeArgs, Encoder};
7
8#[derive(Debug, Display, Error)]
9pub enum OutputProcessorError {
10    DecodePacket(serde_cbor::Error),
11    EncodeData(encoder::EncoderError),
12    EncryptData(CryptError),
13}
14
15#[derive(Debug, Clone)]
16pub struct OutputProcessor<S, E>
17where
18    S: Signer,
19    E: Encrypter,
20{
21    encoder: Encoder,
22    transmission_size: usize,
23    signer: S,
24    encrypter: E,
25}
26
27impl<S, E> OutputProcessor<S, E>
28where
29    S: Signer,
30    E: Encrypter,
31{
32    pub fn new(transmission_size: usize, signer: S, encrypter: E) -> Self {
33        let encoder = Encoder::default();
34        Self {
35            encoder,
36            transmission_size,
37            signer,
38            encrypter,
39        }
40    }
41
42    pub fn process(
43        &mut self,
44        data: &[u8],
45    ) -> Result<Vec<Vec<u8>>, OutputProcessorError> {
46        // Encrypt entire dataset before splitting as it will grow in size
47        // and it's difficult to predict if we can stay under our transmission
48        // limit if encrypting at the individual packet level
49        let associated_data = self.encrypter.new_encrypt_associated_data();
50        let encryption = PacketEncryption::from(associated_data.clone());
51        let data = self
52            .encrypter
53            .encrypt(data, &associated_data)
54            .map_err(OutputProcessorError::EncryptData)?;
55
56        // Produce a unique id used to group our packets
57        let id: u32 = Self::new_id();
58
59        // Split data into multiple packets
60        // NOTE: Must protect mutable access to encoder, which caches
61        //       computing the estimated packet sizes; if there is a way
62        //       that we could do this faster (not need a cache), we could
63        //       get rid of the locking and only need a reference
64        let packets = self
65            .encoder
66            .encode(EncodeArgs {
67                id,
68                encryption,
69                data: &data,
70                max_packet_size: self.transmission_size,
71                signer: &self.signer,
72            })
73            .map_err(OutputProcessorError::EncodeData)?;
74
75        // For each packet, serialize and add to output
76        let mut output = Vec::new();
77        for packet in packets.iter() {
78            let packet_data = packet
79                .to_vec()
80                .map_err(OutputProcessorError::DecodePacket)?;
81            output.push(packet_data);
82        }
83
84        Ok(output)
85    }
86
87    fn new_id() -> u32 {
88        rand::random()
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use crate::core::transport::auth::{ClosureSigner, Digest, NoopAuthenticator};
96    use crate::core::transport::crypto::{ClosureEncrypter, NoopBicrypter};
97    use crate::core::transport::wire::packet::Packet;
98
99    fn new_processor(
100        buffer_size: usize,
101    ) -> OutputProcessor<NoopAuthenticator, NoopBicrypter> {
102        OutputProcessor::new(buffer_size, NoopAuthenticator, NoopBicrypter)
103    }
104
105    #[test]
106    fn output_processor_process_should_fail_if_unable_to_convert_bytes_to_packets(
107    ) {
108        // Produce a transmitter with a "bytes per packet" that is too
109        // low, causing the process to fail
110        let mut processor = new_processor(0);
111        let data = vec![1, 2, 3];
112
113        match processor.process(&data) {
114            Err(OutputProcessorError::EncodeData(_)) => (),
115            x => panic!("Unexpected result: {:?}", x),
116        }
117    }
118
119    #[test]
120    fn output_processor_process_should_return_signed_and_encrypted_serialized_packets(
121    ) {
122        use std::convert::TryFrom;
123        let signer = ClosureSigner::new(|_| Digest::try_from([9; 32]).unwrap());
124        let encrypter = ClosureEncrypter::new(|msg, _| {
125            let mut v = Vec::new();
126
127            for d in msg {
128                v.push(*d);
129            }
130
131            v.push(99);
132
133            Ok(v)
134        });
135        let mut processor = OutputProcessor::new(100, signer, encrypter);
136        let data = vec![1, 2, 3];
137
138        match processor.process(&data) {
139            Ok(packeted_data) => {
140                assert_eq!(
141                    packeted_data.len(),
142                    1,
143                    "More packets than expected"
144                );
145                let packet_bytes = &packeted_data[0];
146                let packet = Packet::from_slice(packet_bytes).unwrap();
147
148                assert_eq!(packet.signature().digest(), &[9; 32]);
149                assert_eq!(packet.data(), &vec![1, 2, 3, 99]);
150            }
151            Err(x) => panic!("Unexpected error: {:?}", x),
152        }
153    }
154
155    #[cfg(test)]
156    mod crypt {
157        use super::*;
158        use crate::core::transport::crypto::{
159            AssociatedData, CryptError, Decrypter, Encrypter,
160        };
161
162        #[derive(Clone)]
163        struct BadEncrypter;
164        impl Encrypter for BadEncrypter {
165            fn encrypt(
166                &self,
167                _: &[u8],
168                _: &AssociatedData,
169            ) -> Result<Vec<u8>, CryptError> {
170                Err(CryptError::EncryptFailed(From::from("Some error")))
171            }
172
173            fn new_encrypt_associated_data(&self) -> AssociatedData {
174                AssociatedData::None
175            }
176        }
177        impl Decrypter for BadEncrypter {
178            fn decrypt(
179                &self,
180                _: &[u8],
181                _: &AssociatedData,
182            ) -> Result<Vec<u8>, CryptError> {
183                Err(CryptError::DecryptFailed(From::from("Some error")))
184            }
185        }
186
187        fn new_processor(
188            buffer_size: usize,
189        ) -> OutputProcessor<NoopAuthenticator, BadEncrypter> {
190            OutputProcessor::new(buffer_size, NoopAuthenticator, BadEncrypter)
191        }
192
193        #[test]
194        fn output_processor_process_should_fail_if_unable_to_encrypt_data() {
195            let mut processor = new_processor(100);
196            let data = vec![1, 2, 3];
197
198            match processor.process(&data) {
199                Err(super::OutputProcessorError::EncryptData(_)) => (),
200                x => panic!("Unexpected result: {:?}", x),
201            }
202        }
203    }
204}