sare_core/format/
header.rs1use 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 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 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()?; 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))?; 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}