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