disco_rs/
channel.rs

1/*
2    Copyright David Huseby, All Rights Reserved.
3    SPDX-License-Identifier: Apache-2.0
4*/
5use crate::{
6    error::ProtocolError,
7    nonce::NonceGenerator,
8    tag::{Tag, TaggedData},
9    transport::{Transport, TransportOrder, TransportState},
10    Result,
11};
12use core::marker::PhantomData;
13use serde::{Deserialize, Serialize};
14use strobe_rs::Strobe;
15
16use std::println as debug;
17
18/// The fixed size of MAC values in the protocol
19const MSG_MAC_LEN: usize = 16;
20
21/// Specifies if the channel is full duplex, or if it is a half-duplex channel for either inbound
22/// or outbout
23#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
24pub enum ChannelDuplex {
25    /// Inbound half-duplex channel
26    InboundHalf,
27    /// Outbound half-duplex channel
28    OutboundHalf,
29    /// In/Out full duplex channel
30    Full,
31}
32
33/// Specifies if the channel is for an initiator or a responder. This is really only useful for
34/// handshaking channel state machines
35#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
36pub enum ChannelRole {
37    /// Session initiator
38    Initiator,
39    /// Session responder
40    Responder,
41}
42
43/// Channels have an internal channel state that handles stateful message exchanges such as
44/// handshakes and encrypted transports
45pub trait ChannelState: Iterator + Clone {
46    /// get the channel role
47    fn role(&self) -> &ChannelRole;
48    /// get the channel duplex
49    fn duplex(&self) -> &ChannelDuplex;
50    /// reset the channel state
51    fn reset(&mut self) -> Result<()>;
52}
53
54/// Channel manages all the channel states and nonces and sending/receiving messages
55#[derive(Clone, Serialize, Deserialize)]
56pub struct Channel<T, CS, N, NG>
57where
58    T: Tag,
59    CS: ChannelState,
60    N: TaggedData<T>,
61    NG: NonceGenerator<T, N>,
62{
63    current_strobe: Strobe,
64    previous_strobe: Strobe,
65    msg_strobe: Option<Strobe>,
66    state: CS,
67    nonce_generator: NG,
68    msg_order: TransportOrder,
69    is_keyed: bool,
70    _t: PhantomData<T>,
71    _n: PhantomData<N>,
72}
73
74/// Make it easy walk through the steps of the state machine
75impl<T, CS, N, NG> Iterator for Channel<T, CS, N, NG>
76where
77    T: Tag,
78    CS: ChannelState,
79    N: TaggedData<T>,
80    NG: NonceGenerator<T, N>,
81{
82    type Item = CS::Item;
83    fn next(&mut self) -> Option<Self::Item> {
84        self.state.next()
85    }
86}
87
88impl<T, CS, N, NG> Channel<T, CS, N, NG>
89where
90    T: Tag,
91    CS: ChannelState,
92    N: TaggedData<T>,
93    NG: NonceGenerator<T, N>,
94{
95    /// Create a new Channel from the strobe, channel state and transport order
96    pub fn new(
97        strobe: &Strobe,
98        state: &CS,
99        nonce_generator: &NG,
100        msg_order: TransportOrder,
101        is_keyed: bool,
102    ) -> Self {
103        Self {
104            current_strobe: strobe.clone(),
105            previous_strobe: strobe.clone(),
106            msg_strobe: None,
107            state: state.clone(),
108            nonce_generator: nonce_generator.clone(),
109            msg_order,
110            is_keyed,
111            _t: PhantomData,
112            _n: PhantomData,
113        }
114    }
115
116    /// Start a new message
117    pub fn start(&mut self) {
118        // at the start of each message we clone the current strobe state, preserving the current
119        // state so we can support both in-order and out-of-order message delivery
120        self.msg_strobe = Some(self.current_strobe.clone());
121    }
122
123    /// Stop a new message
124    pub fn stop(&mut self) {
125        match self.msg_order {
126            TransportOrder::InOrder => {
127                // when we are delivering messages in-order, the message state must be moved back
128                // to the current state so that the next message is based on the accumulated state
129                self.current_strobe = self.msg_strobe.take().unwrap();
130            }
131            TransportOrder::OutOfOrder => {
132                // when we are delivering messages out-of-order, we throw away the message state
133                self.msg_strobe = None;
134            }
135        }
136    }
137
138    /// Returns whether this channel has had a KEY operation done on it
139    pub fn is_keyed(&self) -> bool {
140        self.is_keyed
141    }
142
143    /// Return the channel role
144    pub fn role(&self) -> &ChannelRole {
145        self.state.role()
146    }
147
148    /// Return the channel duplex mode
149    pub fn duplex(&self) -> &ChannelDuplex {
150        self.state.duplex()
151    }
152
153    /// Return the channel ordering
154    pub fn ordering(&self) -> TransportOrder {
155        self.msg_order
156    }
157
158    /// Return the next nonce
159    pub fn nonce(&mut self) -> N {
160        self.nonce_generator.generate()
161    }
162
163    /// Check the nonce to see if it is valid
164    pub fn check_nonce(&mut self, nonce: &N) -> bool {
165        self.nonce_generator.check(nonce)
166    }
167
168    /// Return a default nonce for receiving
169    pub fn default_nonce(&mut self) -> N {
170        self.nonce_generator.default_nonce()
171    }
172
173    /// Do a prf function on the strobe state to get pseudo-random data derived from all data mixed
174    /// into the strobe state until now.
175    pub fn prf(&mut self, data: &mut [u8]) {
176        if let Some(s) = self.msg_strobe.as_mut() {
177            (*s).prf(data, false);
178            debug!("PRF({:02x?})", data);
179        }
180    }
181
182    /// this uses the KEY operation to rekey with the data bytes
183    pub fn key(&mut self, data: &[u8]) {
184        // update the strobe state with the data bytes
185        if data.len() > 0 {
186            if let Some(s) = self.msg_strobe.as_mut() {
187                // mix in the key data
188                (*s).key(data, false);
189                // mark the channel as keyed
190                self.is_keyed = true;
191                debug!("MIX KEY({:02x?})", data);
192            }
193        }
194    }
195
196    /// Split this full-duplex channel into two half-duplex channels so that sending and receiving
197    /// does not have to proceed in an alternating fashion. This is the split() operation detailed
198    /// in the Disco Noise Extension specification (https://discocrypto.com/disco.html).
199    pub fn split(
200        &mut self,
201        handshake_hash: &[u8; 32],
202    ) -> (
203        Channel<T, TransportState, N, NG>,
204        Channel<T, TransportState, N, NG>,
205    ) {
206        // This function follows the steps in §5 and §7.3.1 of the Disco extension spec
207        // (https://www.discocrypto.com/disco.html) to support both regular and out-of-order
208        // message delivery
209
210        // Both message delivery modes follow the steps in §5
211
212        // 0. store the current state before proceeding
213        self.current_strobe = self.msg_strobe.take().unwrap();
214
215        // 1. clone the strobe state into one for outbound and one for inbound
216        let mut s_out = self.current_strobe.clone();
217        let mut s_in = self.current_strobe.clone();
218
219        // 2. for the initiator, call meta_AD("initiator") on outbount and meta_AD("responder") on
220        //    the inbound. for the responder, call meta_AD("responder") on outbound and
221        //    meta_AD("initiator") on inbound.
222        match self.state.role() {
223            ChannelRole::Initiator => {
224                // initiator's outbound state is tagged as "initiator" and
225                // inbound state is tagged as "responder"
226                s_out.meta_ad(b"initiator", false);
227                s_in.meta_ad(b"responder", false);
228            }
229            ChannelRole::Responder => {
230                // responder's output state is tagged as "responder" and
231                // inbound state is tagged as "initiator"
232                s_out.meta_ad(b"responder", false);
233                s_in.meta_ad(b"initiator", false);
234            }
235        }
236
237        // 3. call RATCHET(16) on both inbound and outbount for both initiator and responder
238        s_out.ratchet(16, false);
239        s_in.ratchet(16, false);
240
241        // 4. create the correct transport state objects based on the message delivery mode
242        //
243        // Out-of-order delivery follows the steps in §7.3.1
244        if self.msg_order == TransportOrder::OutOfOrder {
245            // 4.1 call meta_RATCHET(0) on both inbound and outbound
246            s_out.meta_ratchet(0, false);
247            s_in.meta_ratchet(0, false);
248        }
249
250        // create transport states for inbound and outbound
251        let t_out = TransportState::new(
252            Transport {},
253            self.state.role(),
254            &ChannelDuplex::OutboundHalf,
255        );
256        let t_in =
257            TransportState::new(Transport {}, self.state.role(), &ChannelDuplex::InboundHalf);
258
259        // reset the nonce generator to the handshake hash
260        self.nonce_generator.reset(handshake_hash);
261
262        // create and return two new Channels with the new ChannelState, strobe, role, duplex, and
263        // ordering
264        (
265            // outbound half-duplex
266            Channel::<T, TransportState, N, NG>::new(
267                &s_out,
268                &t_out,
269                &self.nonce_generator,
270                self.msg_order,
271                self.is_keyed,
272            ),
273            // inbound half-duplex
274            Channel::<T, TransportState, N, NG>::new(
275                &s_in,
276                &t_in,
277                &self.nonce_generator,
278                self.msg_order,
279                self.is_keyed,
280            ),
281        )
282    }
283
284    /// Write a tag and associated data to the message. The boolean 'force_clear' forces the data
285    /// to be written as cleartext even if the channel is keyed. The boolen 'meta_tag' prevents any
286    /// tag data from being sent and instead it is just mixed into the strobe state using
287    /// meta_AD/AD operations. This is only useful when the data being sent is a known fixed type
288    /// and known fixed length because the recipient must manually create a tag with the correct
289    /// type and length information to pass into the recv function when receiving the data.
290    pub fn send(
291        &mut self,
292        send_tag: bool,
293        send_data: bool,
294        send_clear: bool,
295        tag: &T,
296        data: &[u8],
297        msg: &mut [u8],
298    ) -> Result<usize> {
299        // make sure we're not sending a tag without any data
300        if send_tag && !send_data {
301            return Err(ProtocolError::InvalidSend.into());
302        }
303
304        // get the number of bytes the tag will write
305        let tlen = if send_tag {
306            tag.as_ref().len() + MSG_MAC_LEN
307        } else {
308            0 // meta tag means we're not actually sending the tag
309        };
310
311        // get the number of bytes the data will write
312        let dlen = if send_data {
313            tag.get_data_length()
314                + if self.is_keyed && !send_clear {
315                    MSG_MAC_LEN
316                } else {
317                    0
318                }
319        } else {
320            0
321        };
322
323        // make sure we're not writing beyond the end of the output buffer
324        if tlen + dlen > msg.len() {
325            return Err(ProtocolError::InvalidBufferLen.into());
326        }
327
328        // make sure the data length in the tag matches the number of data bytes
329        if tag.get_data_length() != data.len() {
330            return Err(ProtocolError::InvalidBufferLen.into());
331        }
332
333        // output the tag and mac
334        let tag_len = self.send_tag(send_tag, send_clear, tag, msg)?;
335
336        // output the data and mac
337        let data_len = self.send_data(
338            send_data,
339            send_clear,
340            &data[..tag.get_data_length()],
341            &mut msg[tag_len..],
342        )?;
343
344        // return the number of bytes sent
345        Ok(tag_len + data_len)
346    }
347
348    /// Read a tag and associated data from the message. The boolean 'force_clear' forces the data
349    /// to be read as cleartext even if the channel is keyed.
350    pub fn recv(
351        &mut self,
352        recv_tag: bool,
353        recv_data: bool,
354        recv_clear: bool,
355        msg: &[u8],
356        tag: &mut T,
357        data: &mut [u8],
358    ) -> Result<usize> {
359        // make sure we're not receiving a tag and no data
360        if recv_tag && !recv_data {
361            return Err(ProtocolError::InvalidRecv.into());
362        }
363
364        // if the tag data was sent, reset the tag before reading the tag
365        if recv_tag {
366            *tag = T::default();
367        }
368
369        // recv the tag
370        let actual_tag_len = self.recv_tag(recv_tag, recv_clear, msg, tag)?;
371
372        // make sure we didn't read any bytes if we aren't supposed to receive a tag
373        if !recv_tag && actual_tag_len != 0 {
374            return Err(ProtocolError::InvalidTag.into());
375        }
376
377        // calculate the expected data length
378        let expected_data_len = if recv_data {
379            tag.get_data_length()
380                + if self.is_keyed && !recv_clear {
381                    MSG_MAC_LEN
382                } else {
383                    0
384                }
385        } else {
386            actual_tag_len + 0
387        };
388
389        // make sure we're not going to read past the end of the message buffer
390        if expected_data_len > msg.len() {
391            return Err(ProtocolError::InvalidBufferLen.into());
392        }
393
394        // recv the data
395        let actual_data_len = self.recv_data(
396            recv_data,
397            recv_clear,
398            &msg[actual_tag_len..],
399            &mut data[..tag.get_data_length()],
400        )?;
401
402        if actual_data_len != expected_data_len {
403            return Err(ProtocolError::InvalidData.into());
404        }
405
406        // return just the number of bytes we read from the msg buffer
407        Ok(actual_tag_len + actual_data_len)
408    }
409
410    ///////////////// PRIVATE HELPERS
411
412    // write a MAC to the message, if framing is true, then we use the meta operation
413    fn send_mac(&mut self, framing: bool, msg: &mut [u8]) -> Result<usize> {
414        // make sure we're not going to write beyond the end of the buffer
415        if MSG_MAC_LEN > msg.len() {
416            return Err(ProtocolError::InvalidBufferLen.into());
417        }
418
419        if let Some(s) = self.msg_strobe.as_mut() {
420            // do a meta_AD of the MAC length in network byte order
421            (*s).meta_ad(&MSG_MAC_LEN.to_be_bytes(), false);
422            debug!("META_AD({:02x?})", &MSG_MAC_LEN.to_be_bytes());
423
424            // now add the MAC payload using the meta operation if it is for framing data
425            if framing {
426                (*s).meta_send_mac(&mut msg[..MSG_MAC_LEN], false);
427                debug!("META_SEND_MAC({:02x?})", &msg[..MSG_MAC_LEN]);
428            } else {
429                (*s).send_mac(&mut msg[..MSG_MAC_LEN], false);
430                debug!("SEND_MAC({:02x?})", &msg[..MSG_MAC_LEN]);
431            }
432
433            // return the number of bytes sent
434            Ok(MSG_MAC_LEN)
435        } else {
436            Err(ProtocolError::InvalidState.into())
437        }
438    }
439
440    // write a Tag to the message
441    fn send_tag(
442        &mut self,
443        send_tag: bool,
444        send_clear: bool,
445        tag: &T,
446        msg: &mut [u8],
447    ) -> Result<usize> {
448        // get the length of tag data to be written
449        let expected_len = if send_tag {
450            tag.as_ref().len()
451                + if self.is_keyed && !send_clear {
452                    MSG_MAC_LEN
453                } else {
454                    0
455                }
456        } else {
457            0
458        };
459
460        // make sure we're not going to write beyond the end of the output buffer
461        if expected_len > msg.len() {
462            return Err(ProtocolError::InvalidBufferLen.into());
463        }
464
465        if let Some(s) = self.msg_strobe.as_mut() {
466            let actual_len = if send_tag {
467                // get the length of the tag bytes
468                let mut tag_len = tag.as_ref().len();
469
470                // copy the tag bytes to the message
471                msg[..tag_len].copy_from_slice(tag.as_ref());
472
473                // if keyed then meta_send_enc otherwise meta_send_clr
474                tag_len += if self.is_keyed && !send_clear {
475                    // send the tag bytes encrypted
476                    debug!("META_SEND_ENC:\n\tPT: {:02x?}", &msg[..tag_len]);
477                    (*s).meta_send_enc(&mut msg[..tag_len], false);
478                    debug!("\tCT: {:02x?})", &msg[..tag_len]);
479
480                    // write a framing data MAC to the message
481                    self.send_mac(true, &mut msg[tag_len..])?
482                } else {
483                    // mix the tag bytes into the strobe state
484                    debug!("META_AD({:02x?})", &msg[..tag_len]);
485                    (*s).meta_ad(&msg[..tag_len], false);
486
487                    // send the tag bytes in the clear
488                    debug!("META_SEND_CLR({:02x?})", &msg[..tag_len]);
489                    (*s).meta_send_clr(&msg[..tag_len], false);
490
491                    // no extra bytes other than the tag itself
492                    0
493                };
494
495                // return the number of bytes written
496                tag_len
497            } else {
498                // we're not sending the tag, just mixing it into the strobe state
499                (*s).meta_ad(tag.as_ref(), false);
500                debug!("META_AD({:02x?})", tag.as_ref());
501
502                // no bytes written
503                0
504            };
505
506            // make sure we wrote what we expected
507            if expected_len != actual_len {
508                return Err(ProtocolError::InvalidTag.into());
509            }
510
511            Ok(actual_len)
512        } else {
513            Err(ProtocolError::InvalidState.into())
514        }
515    }
516
517    // write the data to the message
518    fn send_data(
519        &mut self,
520        send_data: bool,
521        send_clear: bool,
522        data: &[u8],
523        msg: &mut [u8],
524    ) -> Result<usize> {
525        // get the length of the data
526        let expected_len = if send_data {
527            data.len()
528                + if self.is_keyed && !send_clear {
529                    MSG_MAC_LEN
530                } else {
531                    0
532                }
533        } else {
534            0
535        };
536
537        // make sure we're not going to write beyond the end of the buffer
538        if expected_len > msg.len() {
539            return Err(ProtocolError::InvalidBufferLen.into());
540        }
541
542        if let Some(s) = self.msg_strobe.as_mut() {
543            let actual_len = if send_data {
544                let mut data_len = data.len();
545
546                // copy the data to the message
547                msg[..data_len].copy_from_slice(data);
548
549                // make this a composite operation by first doing a meta_AD of the data length in
550                // network byte order
551                (*s).meta_ad(&data_len.to_be_bytes(), false);
552                debug!("META_AD({:02x?})", &data_len.to_be_bytes());
553
554                // if we're keyed, then we encrypt the message, otherwise send it in the clear
555                data_len += if self.is_keyed && !send_clear {
556                    // send the data encrypted
557                    debug!("SEND_ENC:\n\tPT: {:02x?}", &msg[..data_len]);
558                    (*s).send_enc(&mut msg[..data_len], false);
559                    debug!("\tCT: {:02x?}", &msg[..data_len]);
560
561                    // write the payload data MAC to the message
562                    self.send_mac(false, &mut msg[data_len..])?
563                } else {
564                    // mix the data bytes into the strobe state
565                    debug!("AD({:02x?})", &msg[..data_len]);
566                    (*s).ad(&msg[..data_len], false);
567
568                    // send the data in the clear
569                    debug!("SEND_CLR({:02x?})", &msg[..data_len]);
570                    (*s).send_clr(&msg[..data_len], false);
571
572                    // no extra bytes other than the data that was written
573                    0
574                };
575
576                // return the number of bytes sent
577                data_len
578            } else {
579                // we're not actually sending the data, just going to mix it into the strobe state
580                debug!("AD({:02x?})", data);
581                (*s).ad(data, false);
582
583                // didn't write any bytes
584                0
585            };
586
587            // make sure we wrote what we expected
588            if expected_len != actual_len {
589                return Err(ProtocolError::InvalidTag.into());
590            }
591
592            Ok(actual_len)
593        } else {
594            Err(ProtocolError::InvalidState.into())
595        }
596    }
597
598    // read a MAC to the message, if framing is true, then we use the meta operation
599    fn recv_mac(&mut self, framing: bool, msg: &[u8]) -> Result<usize> {
600        // make sure we're not going to read beyond the end of the buffer
601        if MSG_MAC_LEN > msg.len() {
602            return Err(ProtocolError::InvalidBufferLen.into());
603        }
604
605        // copy the mac locally
606        let mut mac = [0u8; MSG_MAC_LEN];
607        mac.copy_from_slice(&msg[..MSG_MAC_LEN]);
608
609        if let Some(s) = self.msg_strobe.as_mut() {
610            // do a meta_AD of the MAC length in network byte order
611            (*s).meta_ad(&MSG_MAC_LEN.to_be_bytes(), false);
612            debug!("META_AD({:02x?})", &MSG_MAC_LEN.to_be_bytes());
613
614            // now check the MAC payload using the meta operation if it is for framing data
615            if framing {
616                debug!("META_RECV_MAC({:02x?})", &mac);
617                (*s).meta_recv_mac(&mut mac)
618                    .map_err(|_| ProtocolError::InvalidMac)?;
619            } else {
620                debug!("RECV_MAC({:02x?})", &mac);
621                (*s).recv_mac(&mut mac)
622                    .map_err(|_| ProtocolError::InvalidMac)?;
623            }
624
625            // return the number of bytes received
626            Ok(MSG_MAC_LEN)
627        } else {
628            Err(ProtocolError::InvalidState.into())
629        }
630    }
631
632    // read a tag from the message, this assumes the tag is in the default state
633    fn recv_tag(
634        &mut self,
635        recv_tag: bool,
636        recv_clear: bool,
637        msg: &[u8],
638        tag: &mut T,
639    ) -> Result<usize> {
640        if let Some(s) = self.msg_strobe.as_mut() {
641            if recv_tag {
642                let mut idx = 0;
643                if self.is_keyed && !recv_clear {
644                    // this loop copies one byte at a time to the tag until it parses
645                    let tag_len = loop {
646                        // the first strobe calls will have more set to false, the remaining calls it will be
647                        // true for the streaming interface of strobe-rs
648                        let more = idx > 0;
649
650                        // make sure we're not going to read beyond the end of the buffer
651                        if idx > msg.len() {
652                            return Err(ProtocolError::InvalidBufferLen.into());
653                        }
654
655                        // make sure that we're not going to write beyond the end of the tag buffer
656                        if idx >= tag.as_mut().len() {
657                            return Err(ProtocolError::InvalidBufferLen.into());
658                        }
659
660                        // copy the next byte over to the tag buffer
661                        tag.as_mut()[idx] = msg[idx];
662
663                        // recv and decrypt the next byte
664                        (*s).meta_recv_enc(&mut tag.as_mut()[idx..idx + 1], more);
665
666                        // increment the index
667                        idx += 1;
668
669                        // check to see if we've read enough bytes to get a valid tag
670                        if tag.try_parse(idx) {
671                            break idx;
672                        }
673                    };
674
675                    debug!("META_RECV_ENC:\n\tCT: {:02x?}", &msg[..tag_len]);
676                    debug!("\tPT: {:02x?}", &tag.as_ref());
677
678                    // read and check the framing MAC
679                    let mac_len = self.recv_mac(true, &msg[tag_len..])?;
680
681                    // return the number of bytes received
682                    Ok(tag_len + mac_len)
683                } else {
684                    // this loop copies one byte at a time to the tag until it parses
685                    let tag_len = loop {
686                        // make sure we're not going to read beyond the end of the buffer
687                        if idx > msg.len() {
688                            return Err(ProtocolError::InvalidBufferLen.into());
689                        }
690
691                        // make sure that we're not going to write beyond the end of the tag buffer
692                        if idx >= tag.as_mut().len() {
693                            return Err(ProtocolError::InvalidBufferLen.into());
694                        }
695
696                        // copy the next byte over to the tag buffer
697                        tag.as_mut()[idx] = msg[idx];
698
699                        // increment the index
700                        idx += 1;
701
702                        // check to see if we've read enough bytes to get a valid tag
703                        if tag.try_parse(idx) {
704                            break idx;
705                        }
706                    };
707
708                    // mix the tag bytes into the strobe state
709                    debug!("META_AD({:02x?})", tag.as_ref());
710                    (*s).meta_ad(tag.as_ref(), false);
711
712                    // recv the tag bytes in the clear
713                    debug!("META_RECV_CLR({:02x?})", tag.as_ref());
714                    (*s).meta_recv_clr(tag.as_ref(), false);
715
716                    // return the number of bytes received
717                    Ok(tag_len)
718                }
719            } else {
720                // no tag data was sent so we're just mixing the provided tag bytes into the strobe
721                // state. the recipient must create a tag with the correct tag type and data length
722                // to avoid corrupting the strobe state.
723                debug!("META_AD({:02x?})", tag.as_ref());
724                (*s).meta_ad(tag.as_ref(), false);
725                Ok(0)
726            }
727        } else {
728            Err(ProtocolError::InvalidState.into())
729        }
730    }
731
732    // read data from the mesasge
733    fn recv_data(
734        &mut self,
735        recv_data: bool,
736        recv_clear: bool,
737        msg: &[u8],
738        data: &mut [u8],
739    ) -> Result<usize> {
740        if let Some(s) = self.msg_strobe.as_mut() {
741            if recv_data {
742                // get the length of data to read
743                let mut data_len = data.len();
744
745                // copy the message data over
746                data[..data_len].copy_from_slice(&msg[..data_len]);
747
748                // make this a composite operation by meta_AD the data length in network byte order
749                (*s).meta_ad(&data_len.to_be_bytes(), false);
750                debug!("META_AD({:02x?})", &data_len.to_be_bytes());
751
752                data_len += if self.is_keyed && !recv_clear {
753                    // recv and decrypt the data
754                    debug!("RECV_ENC:\n\tCT: {:02x?}", &data[..data_len]);
755                    (*s).recv_enc(&mut data[..data_len], false);
756                    debug!("\tPT: {:02x?}", &data[..data_len]);
757
758                    // read and check the payload MAC
759                    self.recv_mac(false, &msg[data_len..])?
760                } else {
761                    // mix the data bytes into the strobe state
762                    debug!("AD({:02x?})", &data[..data_len]);
763                    (*s).ad(&data[..data_len], false);
764
765                    // recv the data in the clear
766                    debug!("RECV_CLR({:02x?})", &data[..data_len]);
767                    (*s).recv_clr(&data[..data_len], false);
768
769                    // no extra bytes other than the data that was received
770                    0
771                };
772
773                // return the number of bytes received
774                Ok(data_len)
775            } else {
776                // we're not actually receiving any data so we're just mixing the provided data
777                // bytes into the strobe state. the recipient must pass in the correct bytes to
778                // avoid corrupting the strobe state.
779                debug!("AD({:02x?})", data);
780                (*s).ad(data, false);
781
782                // didn't receive any bytes
783                Ok(0)
784            }
785        } else {
786            Err(ProtocolError::InvalidState.into())
787        }
788    }
789}