1use std::io;
2
3use byteorder::{BigEndian, WriteBytesExt};
4use log::debug;
5use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
6
7use crate::errors::Result;
8
9#[derive(Debug, PartialEq, Eq, Clone)]
12pub struct Packet {
13 pub version: Version,
15 pub tag: Tag,
17 pub body: Vec<u8>,
19}
20
21#[derive(Debug, PartialEq, Eq, Clone)]
23pub enum PacketLength {
24 Fixed(usize),
25 Indeterminate,
26 Partial(usize),
27}
28
29impl From<usize> for PacketLength {
30 fn from(val: usize) -> PacketLength {
31 PacketLength::Fixed(val)
32 }
33}
34
35#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, IntoPrimitive)]
42#[repr(u8)]
43pub enum Tag {
44 PublicKeyEncryptedSessionKey = 1,
46 Signature = 2,
48 SymKeyEncryptedSessionKey = 3,
50 OnePassSignature = 4,
52 SecretKey = 5,
54 PublicKey = 6,
56 SecretSubkey = 7,
58 CompressedData = 8,
60 SymEncryptedData = 9,
62 Marker = 10,
64 LiteralData = 11,
66 Trust = 12,
68 UserId = 13,
70 PublicSubkey = 14,
72 UserAttribute = 17,
74 SymEncryptedProtectedData = 18,
76 ModDetectionCode = 19,
78 Padding = 21,
80
81 #[num_enum(catch_all)]
82 Other(u8),
83}
84
85impl Tag {
86 pub fn encode(self) -> u8 {
89 let t: u8 = self.into();
90 0b1100_0000 | t
91 }
92}
93
94#[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromPrimitive)]
104#[repr(u8)]
105#[derive(Default)]
106pub enum Version {
107 Old = 0,
109 #[default]
111 New = 1,
112}
113
114impl Version {
115 pub fn write_header(self, writer: &mut impl io::Write, tag: u8, len: usize) -> Result<()> {
116 debug!("write_header {:?} {} {}", self, tag, len);
117
118 match self {
119 Version::Old => {
120 if len < 256 {
121 writer.write_u8(0b1000_0000 | tag << 2)?;
123 writer.write_u8(len.try_into()?)?;
124 } else if len < 65536 {
125 writer.write_u8(0b1000_0001 | tag << 2)?;
127 writer.write_u16::<BigEndian>(len as u16)?;
128 } else {
129 writer.write_u8(0b1000_0010 | tag << 2)?;
131 writer.write_u32::<BigEndian>(len as u32)?;
132 }
133 }
134 Version::New => {
135 writer.write_u8(0b1100_0000 | tag)?;
136 if len < 192 {
137 writer.write_u8(len.try_into()?)?;
138 } else if len < 8384 {
139 writer.write_u8((((len - 192) >> 8) + 192) as u8)?;
140 writer.write_u8(((len - 192) & 0xFF) as u8)?;
141 } else {
142 writer.write_u8(255)?;
143 writer.write_u32::<BigEndian>(len as u32)?;
144 }
145 }
146 }
147
148 Ok(())
149 }
150}
151
152#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, IntoPrimitive)]
154#[repr(u8)]
155pub enum KeyVersion {
156 V2 = 2,
157 V3 = 3,
158 V4 = 4,
159 V5 = 5,
160 V6 = 6,
161
162 #[num_enum(catch_all)]
163 Other(u8),
164}
165
166impl KeyVersion {
167 pub const fn fingerprint_len(&self) -> Option<usize> {
170 match self {
171 KeyVersion::V2 | KeyVersion::V3 => Some(16), KeyVersion::V4 => Some(20), KeyVersion::V5 | KeyVersion::V6 => Some(32), KeyVersion::Other(_) => None,
175 }
176 }
177}
178
179impl Default for KeyVersion {
180 fn default() -> Self {
181 Self::V4
182 }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, IntoPrimitive)]
186#[repr(u8)]
187pub enum PkeskVersion {
188 V3 = 3,
189 V6 = 6,
190
191 #[num_enum(catch_all)]
192 Other(u8),
193}
194
195#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, IntoPrimitive)]
196#[repr(u8)]
197pub enum SkeskVersion {
198 V4 = 4,
199 V6 = 6,
200
201 #[num_enum(catch_all)]
202 Other(u8),
203}
204
205#[cfg(test)]
206mod tests {
207 #![allow(clippy::unwrap_used)]
208
209 use super::*;
210
211 #[test]
212 fn test_write_header() {
213 let mut buf = Vec::new();
214 Version::New
215 .write_header(&mut buf, Tag::UserAttribute.into(), 12875)
216 .unwrap();
217
218 assert_eq!(hex::encode(buf), "d1ff0000324b");
219
220 let mut buf = Vec::new();
221 Version::New
222 .write_header(&mut buf, Tag::Signature.into(), 302)
223 .unwrap();
224
225 assert_eq!(hex::encode(buf), "c2c06e");
226
227 let mut buf = Vec::new();
228 Version::New
229 .write_header(&mut buf, Tag::Signature.into(), 303)
230 .unwrap();
231
232 assert_eq!(hex::encode(buf), "c2c06f");
233 }
234}