copernica_packets/
link_packet.rs

1use {
2    crate::{
3        reply_to::{ReplyTo},
4        LinkId, Nonce, Tag,
5        NarrowWaistPacket, PublicIdentity, PublicIdentityInterface,
6    },
7    copernica_common::constants::*,
8    cryptoxide::{chacha20poly1305::{ChaCha20Poly1305}},
9    anyhow::{Result, anyhow},
10    log::{error},
11};
12
13#[derive(Clone, Eq, PartialEq, Debug)]
14pub struct LinkPacket {
15    reply_to: ReplyTo,
16    nw: NarrowWaistPacket,
17}
18impl LinkPacket {
19    pub fn new(reply_to: ReplyTo, nw: NarrowWaistPacket) -> Self {
20        LinkPacket { reply_to, nw }
21    }
22    pub fn narrow_waist(&self) -> NarrowWaistPacket {
23        self.nw.clone()
24    }
25    pub fn reply_to(&self) -> ReplyTo {
26        self.reply_to.clone()
27    }
28    pub fn change_origination(&self, reply_to: ReplyTo) -> Self {
29        LinkPacket {
30            reply_to: reply_to,
31            nw: self.nw.clone(),
32        }
33    }
34    pub fn as_bytes(&self, link_id: LinkId) -> Result<Vec<u8>> {
35        let mut buf: Vec<u8> = vec![];
36        let lnk_tx_pid = link_id.link_pid()?;
37        match link_id.remote_link_pid()? {
38            PublicIdentityInterface::Absent => {
39                match self {
40                    LinkPacket { reply_to, nw } => {
41                        buf.extend_from_slice(lnk_tx_pid.key().as_ref());
42                        buf.extend_from_slice(lnk_tx_pid.chain_code().as_ref());
43                        buf.extend_from_slice(&reply_to.as_bytes()?);
44                        buf.extend_from_slice(&nw.as_bytes());
45                    }
46                }
47            },
48            PublicIdentityInterface::Present { public_identity: lnk_rx_pid } => {
49                match self {
50                    LinkPacket { reply_to, nw } => {
51                        buf.extend_from_slice(lnk_tx_pid.key().as_ref());
52                        buf.extend_from_slice(lnk_tx_pid.chain_code().as_ref());
53                        let nonce = Nonce::new();
54                        buf.extend_from_slice(&nonce.0);
55                        let mut tag = Tag::new_empty_tag();
56                        let shared_secret = link_id.shared_secret(nonce.clone(), lnk_rx_pid)?;
57                        let mut ctx = ChaCha20Poly1305::new(&shared_secret.as_ref(), &nonce.0, &[]);
58                        drop(shared_secret);
59                        let mut nws = nw.as_bytes();
60                        let mut encrypted = vec![0u8; nws.len()];
61                        ctx.encrypt(&nws, &mut encrypted[..], &mut tag.0);
62                        nws.copy_from_slice(&encrypted[..]);
63                        buf.extend_from_slice(&tag.0);
64                        buf.extend_from_slice(&reply_to.as_bytes()?);
65                        buf.extend_from_slice(&nws);
66                    }
67                }
68            },
69        }
70        Ok(buf)
71    }
72    pub fn from_bytes(data: &[u8], link_id: LinkId) -> Result<(PublicIdentity, Self)> {
73        match link_id.remote_link_pid()? {
74            PublicIdentityInterface::Absent => {
75                let mut lnk_tx_pid = [0u8; ID_SIZE + CC_SIZE];
76                lnk_tx_pid.clone_from_slice(&data[CLEARTEXT_LINK_TX_PK_START..CLEARTEXT_LINK_TX_PK_END]);
77                let lnk_tx_pid: PublicIdentity = PublicIdentity::from(lnk_tx_pid);
78                let reply_to = ReplyTo::from_bytes(&data[CLEARTEXT_LINK_REPLY_TO_START..CLEARTEXT_LINK_REPLY_TO_END])?;
79                let nw = NarrowWaistPacket::from_bytes(&data[CLEARTEXT_LINK_NARROW_WAIST_PACKET_START..])?;
80                Ok((lnk_tx_pid, LinkPacket::new(reply_to, nw)))
81            },
82            PublicIdentityInterface::Present { .. } => {
83                let mut link_tx_pid = [0u8; ID_SIZE + CC_SIZE];
84                link_tx_pid.clone_from_slice(&data[CYPHERTEXT_LINK_TX_PK_START..CYPHERTEXT_LINK_TX_PK_END]);
85                let lnk_tx_pid: PublicIdentity = PublicIdentity::from(link_tx_pid);
86                let link_nonce = Nonce::from_bytes(&data[CYPHERTEXT_LINK_NONCE_START..CYPHERTEXT_LINK_NONCE_END]);
87                let link_tag = Tag::from_bytes(&data[CYPHERTEXT_LINK_TAG_START..CYPHERTEXT_LINK_TAG_END]);
88                let reply_to = ReplyTo::from_bytes(&data[CYPHERTEXT_LINK_REPLY_TO_START..CYPHERTEXT_LINK_REPLY_TO_END])?;
89                let shared_secret = link_id.shared_secret(link_nonce.clone(), lnk_tx_pid.clone())?;
90                let mut ctx = ChaCha20Poly1305::new(&shared_secret.as_ref(), &link_nonce.0, &[]);
91                drop(shared_secret);
92                let encrypted = &data[CYPHERTEXT_LINK_NARROW_WAIST_PACKET_START..];
93                let mut decrypted = vec![0u8; encrypted.len()];
94                if !ctx.decrypt(encrypted, &mut decrypted, &link_tag.0) {
95                    let err_msg = "Failed to decrypt NarrowWaistPacket";
96                    error!("{}", err_msg);
97                    return Err(anyhow!(err_msg))
98                };
99                let nw = NarrowWaistPacket::from_bytes(&decrypted)?;
100                Ok((lnk_tx_pid, LinkPacket::new(reply_to, nw)))
101            },
102        }
103    }
104}