sare_core/format/
header.rs

1use byteorder::{LittleEndian, ReadBytesExt};
2use serde::{Deserialize, Serialize};
3use std::io;
4use std::io::Cursor;
5use std::io::Read;
6use std::io::Seek;
7use std::io::SeekFrom;
8
9use crate::format::encryption::*;
10use crate::format::signature::*;
11use crate::format::{ErrSection, FormatError};
12
13use super::EncodablePublic;
14
15const MAGIC_BYTES: &[u8; 9] = b"SARECRYPT";
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct HeaderMetadataFormat {
19    #[serde(skip_serializing_if = "Option::is_none", flatten)]
20    pub signature_metadata: Option<SignatureMetadataFormat>,
21    #[serde(flatten)]
22    pub encryption_metadata: EncryptionMetadataFormat,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub comment: Option<String>,
25}
26
27impl HeaderMetadataFormat {
28    pub fn encode(&self) -> Vec<u8> {
29        bson::to_vec(&self).unwrap()
30    }
31
32    pub fn decode(bson_metadata: &[u8]) -> Result<Self, FormatError> {
33        let metadata = bson::from_slice::<HeaderMetadataFormat>(bson_metadata);
34
35        // TODO: Needs Error Handling
36        Ok(metadata.unwrap())
37    }
38}
39
40#[derive(Debug)]
41pub struct HeaderFormat {
42    pub version: u32,
43    pub metadata: HeaderMetadataFormat,
44    pub signature: Option<SignatureFormat>,
45}
46
47impl HeaderFormat {
48    fn verify_magic_bytes(header: &[u8], cursor: &mut usize) -> Result<bool, FormatError> {
49        let magic_bytes = &header[*cursor..*cursor + MAGIC_BYTES.len()];
50        *cursor += MAGIC_BYTES.len();
51        Ok(magic_bytes == MAGIC_BYTES)
52    }
53
54    fn read_u64(header: &[u8], cursor: &mut usize) -> Result<u64, FormatError> {
55        let mut rdr = Cursor::new(&header[*cursor..*cursor + 8]);
56        *cursor += 8;
57        rdr.read_u64::<LittleEndian>()
58            .map_err(|_| FormatError::FailedToDecode(ErrSection::HEADER))
59    }
60
61    fn read_u32(header: &[u8], cursor: &mut usize) -> Result<u32, FormatError> {
62        let mut rdr = Cursor::new(&header[*cursor..*cursor + 4]);
63        *cursor += 4;
64        rdr.read_u32::<LittleEndian>()
65            .map_err(|_| FormatError::FailedToDecode(ErrSection::HEADER))
66    }
67
68    pub fn encode(&self) -> Vec<u8> {
69        let mut header: Vec<u8> = Vec::new();
70        header.extend(MAGIC_BYTES);
71
72        let mut header_buffer: Vec<u8> = Vec::new();
73
74        header_buffer.extend(&self.version.to_le_bytes());
75
76        let metadata_bson = self.metadata.encode();
77        header_buffer.extend(&(metadata_bson.len() as u64).to_le_bytes());
78        header_buffer.extend(metadata_bson);
79
80        if let Some(signature) = &self.signature {
81            let signature_bson = signature.encode_bson();
82            header_buffer.extend(&(signature_bson.len() as u64).to_le_bytes());
83            header_buffer.extend(signature_bson);
84        } else {
85            header_buffer.extend(&0u64.to_le_bytes());
86        }
87
88        header.extend(&(header_buffer.len() as u64).to_le_bytes());
89        header.extend(header_buffer);
90
91        header
92    }
93
94    pub fn decode(header: &[u8]) -> Result<Self, FormatError> {
95        let mut cursor = 0;
96
97        if !Self::verify_magic_bytes(header, &mut cursor)? {
98            return Err(FormatError::FailedToDecode(ErrSection::HEADER));
99        }
100
101        let header_length = Self::read_u64(header, &mut cursor)?;
102
103        if header.len() < (MAGIC_BYTES.len() + 8 + header_length as usize) {
104            return Err(FormatError::FailedToDecode(ErrSection::HEADER));
105        }
106
107        let version = Self::read_u32(header, &mut cursor)?;
108        let metadata_length = Self::read_u64(header, &mut cursor)?;
109
110        let metadata_bson = &header[cursor..cursor + metadata_length as usize];
111        let metadata = HeaderMetadataFormat::decode(metadata_bson)?;
112        cursor += metadata_length as usize;
113
114        let signature_length = Self::read_u64(header, &mut cursor)?;
115        let signature = if signature_length > 0 {
116            let signature_bson = &header[cursor..cursor + signature_length as usize];
117            //cursor += signature_length as usize;
118            Some(SignatureFormat::decode_bson(signature_bson)?)
119        } else {
120            None
121        };
122
123        Ok(HeaderFormat {
124            version,
125            metadata,
126            signature,
127        })
128    }
129
130    pub fn peek_header_seek<R: Read + Seek>(reader: &mut R) -> std::io::Result<Vec<u8>> {
131        let pos = reader.stream_position()?; // save current position
132
133        let mut magic = [0u8; 9];
134        reader.read_exact(&mut magic)?;
135
136        let mut len_buf = [0u8; 8];
137        reader.read_exact(&mut len_buf)?;
138        let header_len = u64::from_le_bytes(len_buf) as usize;
139
140        let mut header_buf = vec![0u8; header_len];
141        reader.read_exact(&mut header_buf)?;
142
143        reader.seek(SeekFrom::Start(pos))?; // rewind
144
145        let mut full = Vec::with_capacity(magic.len() + 8 + header_buf.len());
146        full.extend_from_slice(&magic);
147        full.extend_from_slice(&len_buf);
148        full.extend_from_slice(&header_buf);
149
150        Ok(full)
151    }
152
153    pub fn separate_header<R: Read>(reader: &mut R) -> io::Result<Vec<u8>> {
154        let mut magic = [0u8; MAGIC_BYTES.len()];
155        reader.read_exact(&mut magic)?;
156
157        let mut len_buf = [0u8; 8];
158        reader.read_exact(&mut len_buf)?;
159        let header_len = u64::from_le_bytes(len_buf) as usize;
160
161        let mut header_buf = vec![0u8; header_len];
162        reader.read_exact(&mut header_buf)?;
163
164        let mut full_header = Vec::with_capacity(magic.len() + len_buf.len() + header_buf.len());
165        full_header.extend_from_slice(&magic);
166        full_header.extend_from_slice(&len_buf);
167        full_header.extend_from_slice(&header_buf);
168
169        Ok(full_header)
170    }
171
172    pub fn is_asymmetric(&self) -> bool {
173        let metadata = &self.metadata;
174
175        metadata.encryption_metadata.kem_metadata.is_some()
176    }
177
178    pub fn is_signed(&self) -> bool {
179        let metadata = &self.metadata;
180
181        metadata.signature_metadata.is_some()
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188    use crate::encryption::EncryptionAlgorithm;
189    use crate::kdf::PKDFAlgorithm;
190    use base64::prelude::*;
191
192    const ENCODED_METADATA: &str = "ygAAAAJlbmNyeXB0aW9uX2FsZ29yaXRobQAKAAAAQUVTMjU2R0NNAARwa2RmX3NhbHQAPQAAABAwAAAAAAAQMQAAAAAAEDIAAAAAABAzAAAAAAAQNAAAAAAAEDUAAAAAABA2AAAAAAAQNwAAAAAAAANwa2RmX2FsZ29yaXRobQAvAAAABFNjcnlwdAAiAAAAEDAACgAAABIxAAgAAAAAAAAAEjIACgAAAAAAAAAAAAJjb21tZW50AA0AAABUZXN0IENvbW1lbnQAAA==";
193
194    const ENCODED_HEADER: &str = "U0FSRUNSWVBU3gAAAAAAAAABAAAAygAAAAAAAADKAAAAAmVuY3J5cHRpb25fYWxnb3JpdGhtAAoAAABBRVMyNTZHQ00ABHBrZGZfc2FsdAA9AAAAEDAAAAAAABAxAAAAAAAQMgAAAAAAEDMAAAAAABA0AAAAAAAQNQAAAAAAEDYAAAAAABA3AAAAAAAAA3BrZGZfYWxnb3JpdGhtAC8AAAAEU2NyeXB0ACIAAAAQMAAKAAAAEjEACAAAAAAAAAASMgAKAAAAAAAAAAAAAmNvbW1lbnQADQAAAFRlc3QgQ29tbWVudAAAAAAAAAAAAAA=";
195
196    #[test]
197    fn metadata_format_encode() {
198        let pkdf_metadata = PKDFMetadataFormat {
199            pkdf_salt: vec![0, 0, 0, 0, 0, 0, 0, 0],
200            pkdf_algorithm: PKDFAlgorithm::Scrypt(10, 8, 10),
201        };
202
203        let encryption_metadata = EncryptionMetadataFormat {
204            encryption_algorithm: EncryptionAlgorithm::AES256GCM,
205            nonce: None,
206            pkdf_metadata: Some(pkdf_metadata),
207            kem_metadata: None,
208        };
209
210        let metadata = HeaderMetadataFormat {
211            signature_metadata: None,
212            encryption_metadata,
213            comment: Some("Test Comment".to_string()),
214        };
215
216        assert_eq!(ENCODED_METADATA, &BASE64_STANDARD.encode(metadata.encode()));
217    }
218
219    #[test]
220    fn header_format_encode() {
221        let header = HeaderFormat {
222            version: 1,
223            metadata: HeaderMetadataFormat::decode(
224                &BASE64_STANDARD.decode(ENCODED_METADATA).unwrap(),
225            )
226            .unwrap(),
227            signature: None,
228        };
229
230        assert_eq!(ENCODED_HEADER, BASE64_STANDARD.encode(header.encode()));
231    }
232
233    #[test]
234    fn header_format_decode() {
235        let expected_header = HeaderFormat {
236            version: 1,
237            metadata: HeaderMetadataFormat::decode(
238                &BASE64_STANDARD.decode(ENCODED_METADATA).unwrap(),
239            )
240            .unwrap(),
241            signature: None,
242        };
243
244        let decoded_header =
245            HeaderFormat::decode(&BASE64_STANDARD.decode(ENCODED_HEADER).unwrap()).unwrap();
246
247        assert_eq!(expected_header.encode(), decoded_header.encode());
248    }
249}