1use binrw::{
2 meta::{ReadEndian, WriteEndian},
3 BinRead, BinWrite,
4};
5
6mod cipher;
7pub use cipher::{CipherCore, OpeningCipher, SealingCipher};
8
9mod mac;
10pub use mac::Mac;
11
12pub const PACKET_MAX_SIZE: usize = u16::MAX as usize;
15
16pub const PACKET_MIN_SIZE: usize = 16;
19
20#[derive(Debug, Clone)]
24
25pub struct Packet {
26 pub payload: Vec<u8>,
28}
29
30impl Packet {
31 pub fn to<T: for<'a> BinRead<Args<'a> = ()> + ReadEndian>(&self) -> Result<T, binrw::Error> {
33 T::read(&mut std::io::Cursor::new(&self.payload))
34 }
35
36 #[cfg(feature = "futures")]
37 #[cfg_attr(docsrs, doc(cfg(feature = "futures")))]
38 pub async fn from_reader<R, C>(reader: &mut R, cipher: &mut C, seq: u32) -> Result<Self, C::Err>
40 where
41 R: futures::io::AsyncRead + Unpin,
42 C: OpeningCipher,
43 {
44 use futures::io::AsyncReadExt;
45
46 let mut buf = vec![0; cipher.block_size()];
47 reader.read_exact(&mut buf[..]).await?;
48
49 if !cipher.mac().etm() {
50 cipher.decrypt(&mut buf[..])?;
51 }
52
53 let len = u32::from_be_bytes(
54 buf[..4]
55 .try_into()
56 .expect("The buffer of size 4 is not of size 4"),
57 );
58
59 if len as usize > PACKET_MAX_SIZE {
60 return Err(binrw::Error::Custom {
61 pos: 0x0,
62 err: Box::new(format!("Packet size too large, {len} > {PACKET_MAX_SIZE}")),
63 })?;
64 }
65
66 buf.resize(std::mem::size_of_val(&len) + len as usize, 0);
68 reader.read_exact(&mut buf[cipher.block_size()..]).await?;
69
70 let mut mac = vec![0; cipher.mac().size()];
71 reader.read_exact(&mut mac[..]).await?;
72
73 if cipher.mac().etm() {
74 cipher.open(&buf, mac, seq)?;
75 cipher.decrypt(&mut buf[4..])?;
76 } else {
77 cipher.decrypt(&mut buf[cipher.block_size()..])?;
78 cipher.open(&buf, mac, seq)?;
79 }
80
81 let (padlen, mut decrypted) =
82 buf[4..].split_first().ok_or_else(|| binrw::Error::Custom {
83 pos: 0x4,
84 err: Box::new(format!("Packet size too small ({len})")),
85 })?;
86
87 if *padlen as usize > len as usize - 1 {
88 return Err(binrw::Error::Custom {
89 pos: 0x4,
90 err: Box::new(format!("Padding size too large, {padlen} > {} - 1", len)),
91 })?;
92 }
93
94 let mut payload = vec![0; len as usize - *padlen as usize - std::mem::size_of_val(padlen)];
95 std::io::Read::read_exact(&mut decrypted, &mut payload[..])?;
96
97 let payload = cipher.decompress(payload)?;
98
99 Ok(Self { payload })
100 }
101
102 #[cfg(feature = "futures")]
103 #[cfg_attr(docsrs, doc(cfg(feature = "futures")))]
104 pub async fn to_writer<W, C>(
106 &self,
107 writer: &mut W,
108 cipher: &mut C,
109 seq: u32,
110 ) -> Result<(), C::Err>
111 where
112 W: futures::io::AsyncWrite + Unpin,
113 C: SealingCipher,
114 {
115 use futures::AsyncWriteExt;
116
117 let compressed = cipher.compress(&self.payload)?;
118
119 let padding = cipher.padding(compressed.len());
120 let buf = cipher.pad(compressed, padding)?;
121 let mut buf = [(buf.len() as u32).to_be_bytes().to_vec(), buf].concat();
122
123 let (buf, mac) = if cipher.mac().etm() {
124 cipher.encrypt(&mut buf[4..])?;
125 let mac = cipher.seal(&buf, seq)?;
126
127 (buf, mac)
128 } else {
129 let mac = cipher.seal(&buf, seq)?;
130 cipher.encrypt(&mut buf[..])?;
131
132 (buf, mac)
133 };
134
135 writer.write_all(&buf).await?;
136 writer.write_all(&mac).await?;
137
138 Ok(())
139 }
140}
141
142pub trait IntoPacket {
144 fn into_packet(self) -> Packet;
146}
147
148impl IntoPacket for Packet {
149 fn into_packet(self) -> Packet {
150 self
151 }
152}
153
154impl<T: for<'a> BinWrite<Args<'a> = ()> + WriteEndian> IntoPacket for &T {
155 fn into_packet(self) -> Packet {
156 let mut buffer = std::io::Cursor::new(Vec::new());
157 self.write(&mut buffer)
158 .expect("Failed to convert `impl BinWrite` type to Packet");
159
160 Packet {
161 payload: buffer.into_inner(),
162 }
163 }
164}