devolutions_crypto/
header.rs

1use 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
41// Default values, used for len()
42impl 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}