devolutions_crypto/
header.rs1use super::DataType;
2
3use super::Error;
4use super::Result;
5
6use cfg_if::cfg_if;
7use std::convert::TryFrom;
8use std::io::Cursor;
9
10use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
11use zeroize::Zeroize;
12
13#[cfg(feature = "fuzz")]
14use arbitrary::Arbitrary;
15
16const SIGNATURE: u16 = 0x0C0D;
17
18pub trait HeaderType {
19 cfg_if! {
20 if #[cfg(feature = "fuzz")] {
21 type Version: Into<u16> + TryFrom<u16> + Clone + Default + Zeroize + std::fmt::Debug + Arbitrary;
22 type Subtype: Into<u16> + TryFrom<u16> + Clone + Default + Zeroize + std::fmt::Debug + Arbitrary;
23 }
24 else {
25 type Version: Into<u16> + TryFrom<u16> + Clone + Default + Zeroize + std::fmt::Debug;
26 type Subtype: Into<u16> + TryFrom<u16> + Clone + Default + Zeroize + std::fmt::Debug;
27 }
28 }
29
30 fn data_type() -> DataType;
31
32 fn default_version() -> Self::Version {
33 Default::default()
34 }
35
36 fn subtype() -> Self::Subtype {
37 Default::default()
38 }
39}
40
41impl HeaderType for () {
43 type Version = super::CiphertextVersion;
44 type Subtype = super::CiphertextSubtype;
45
46 fn data_type() -> DataType {
47 super::DataType::None
48 }
49}
50
51#[derive(Clone, Debug)]
52#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
53pub struct Header<M>
54where
55 M: HeaderType,
56{
57 pub signature: u16,
58 pub data_type: DataType,
59 pub data_subtype: M::Subtype,
60 pub version: M::Version,
61}
62
63impl<M> TryFrom<&[u8]> for Header<M>
64where
65 M: HeaderType,
66{
67 type Error = crate::error::Error;
68 fn try_from(data: &[u8]) -> Result<Self> {
69 let mut data_cursor = Cursor::new(data);
70 let signature = data_cursor.read_u16::<LittleEndian>()?;
71 let data_type = data_cursor.read_u16::<LittleEndian>()?;
72 let data_subtype = data_cursor.read_u16::<LittleEndian>()?;
73 let version = data_cursor.read_u16::<LittleEndian>()?;
74
75 if signature != SIGNATURE {
76 return Err(Error::InvalidSignature);
77 }
78
79 let data_type = match DataType::try_from(data_type) {
80 Ok(d) => d,
81 Err(_) => return Err(Error::UnknownType),
82 };
83
84 let data_subtype = match M::Subtype::try_from(data_subtype) {
85 Ok(d) => d,
86 Err(_) => return Err(Error::UnknownSubtype),
87 };
88
89 let version = match M::Version::try_from(version) {
90 Ok(d) => d,
91 Err(_) => return Err(Error::UnknownVersion),
92 };
93
94 if data_type != M::data_type() {
95 return Err(Error::InvalidData);
96 };
97
98 Ok(Header {
99 signature,
100 data_type,
101 data_subtype,
102 version,
103 })
104 }
105}
106
107impl<M> From<&Header<M>> for Vec<u8>
108where
109 M: HeaderType,
110{
111 fn from(header: &Header<M>) -> Self {
112 <&Header<M> as Into<[u8; 8]>>::into(header).to_vec()
113 }
114}
115
116impl<M> From<&Header<M>> for [u8; 8]
117where
118 M: HeaderType,
119{
120 fn from(header: &Header<M>) -> Self {
121 let mut data = [0u8; 8];
122 let mut cursor = Cursor::new(data.as_mut_slice());
123 cursor.write_u16::<LittleEndian>(header.signature).unwrap();
124 cursor
125 .write_u16::<LittleEndian>(header.data_type.into())
126 .unwrap();
127 cursor
128 .write_u16::<LittleEndian>(header.data_subtype.clone().into())
129 .unwrap();
130 cursor
131 .write_u16::<LittleEndian>(header.version.clone().into())
132 .unwrap();
133 data
134 }
135}
136
137impl<M> Default for Header<M>
138where
139 M: HeaderType,
140{
141 fn default() -> Self {
142 Header {
143 signature: SIGNATURE,
144 data_type: M::data_type(),
145 data_subtype: M::subtype(),
146 version: M::default_version(),
147 }
148 }
149}
150
151impl Header<()> {
152 pub fn len() -> usize {
153 8
154 }
155}