copernica_packets/
link_packet.rs1use {
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}