deadbolt_parser/
header.rs

1use std::error::Error;
2
3use deadbolt_crypto::rand::Random;
4
5use crate::config::KdfParams;
6
7pub const MAGIC_HEADER: [u8; 4] = [0xde, 0xad, 0xb0, 0x17];
8
9const ENCRYPTION_ALGORITHMS: [u8; 2] = [0x01, 0x02];
10const HASH_ALGORITHMS: [u8; 1] = [0x01];
11const KDF_ALGORITHMS: [u8; 2] = [0x01, 0x02];
12const COMPRESSION_ALGORITHMS: [u8; 2] = [0x00, 0x01];
13
14#[derive(PartialEq, Debug)]
15pub struct Header {
16    pub version: u16,
17    pub data_length: u16,
18    pub encryption_alg: u8,
19    pub hash_alg: u8,
20    pub kdf_alg: u8,
21    pub kdf_params: KdfParams,
22    pub compression_alg: u8,
23    pub master_salt: Vec<u8>,
24    pub nonce: Option<Vec<u8>>,
25    pub root_key_nonce: Option<Vec<u8>>,
26    pub root_key_ciphertext: Option<Vec<u8>>,
27}
28
29impl Header {
30    pub fn new(
31        encryption_alg: Option<u8>,
32        hash_alg: Option<u8>,
33        kdf_alg: Option<u8>,
34        compression_alg: Option<u8>,
35        master_salt: Option<Vec<u8>>,
36    ) -> Header {
37        Header {
38            version: 0x01,
39            data_length: 0,
40            encryption_alg: encryption_alg.unwrap_or(0x01),
41            hash_alg: hash_alg.unwrap_or(0x01),
42            kdf_alg: kdf_alg.unwrap_or(0x01),
43            kdf_params: KdfParams::default(),
44            compression_alg: compression_alg.unwrap_or(0x00),
45            master_salt: master_salt.unwrap_or_else(Random::get_rand_bytes),
46            nonce: Default::default(),
47            root_key_nonce: Default::default(),
48            root_key_ciphertext: Default::default(),
49        }
50    }
51
52    /// Read fixed part of header which will return version and the header total length.
53    /// Return `Err` if the data is not started with `MAGIC_HEADER` bytes
54    pub fn quick_lookup(data: Vec<u8>) -> Result<(u16, u16), Box<dyn Error>> {
55        if data[0..4] != MAGIC_HEADER {
56            Err("Data is not valid deadbolt database")?;
57        }
58
59        let version = ((data[4] as u16) << 8) | (data[5] as u16);
60        let data_length = ((data[6] as u16) << 8) | (data[7] as u16);
61
62        Ok((version, data_length))
63    }
64
65    /// Initialize new `Header` from `Vec<u8>`
66    pub fn new_from_vector(data: Vec<u8>) -> Result<Header, Box<dyn Error>> {
67        let (version, data_length) = Header::quick_lookup(data[..8].to_vec())?;
68        let mut header = Header::new(None, None, None, None, None);
69        header.version = version;
70        header.data_length = data_length;
71        header.parse_tlv_header(data[8..].to_vec())?;
72
73        Ok(header)
74    }
75
76    /// Parse the dynamic part (Type-Length-Value list) of header
77    pub fn parse_tlv_header(&mut self, data: Vec<u8>) -> Result<(), Box<dyn Error>> {
78        let mut index = 0;
79
80        loop {
81            let data_type = data[index];
82            index += 1;
83            let start = index + 1;
84            let end = start + usize::from(data[index]);
85            index = end;
86
87            match data_type {
88                1 => {
89                    self.encryption_alg = u8::from_be_bytes(data[start..end].try_into()?);
90                }
91                2 => {
92                    self.hash_alg = u8::from_be_bytes(data[start..end].try_into()?);
93                }
94                3 => {
95                    self.kdf_alg = u8::from_be_bytes(data[start..end].try_into()?);
96                }
97                4 => {
98                    self.compression_alg = u8::from_be_bytes(data[start..end].try_into()?);
99                }
100                6 => {
101                    self.master_salt = data[start..end].to_vec();
102                }
103                7 => {
104                    self.nonce = Some(data[start..end].to_vec());
105                }
106                8 => {
107                    self.root_key_nonce = Some(data[start..end].to_vec());
108                }
109                9 => {
110                    self.root_key_ciphertext = Some(data[start..end].to_vec());
111                }
112                10 => {
113                    self.kdf_params.iterations = u8::from_be_bytes(data[start..end].try_into()?);
114                }
115                11 => {
116                    self.kdf_params.threads = u8::from_be_bytes(data[start..end].try_into()?);
117                }
118                12 => {
119                    self.kdf_params.memory = u32::from_be_bytes(data[start..end].try_into()?);
120                }
121                0 => {
122                    break;
123                }
124                _ => {}
125            }
126        }
127
128        Ok(())
129    }
130
131    /// Construct header section and return the buffer.
132    /// It will also automatically update `data_length`
133    pub fn construct_header(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
134        let mut buffer: Vec<u8> = MAGIC_HEADER.to_vec();
135        buffer.extend(self.version.to_be_bytes());
136
137        let mut tmp_buffer: Vec<u8> = vec![];
138        // Encryption algorithm
139        tmp_buffer.extend([0x01, 0x01]);
140        tmp_buffer.push(self.encryption_alg);
141
142        // Hash algorithm
143        tmp_buffer.extend([0x02, 0x01]);
144        tmp_buffer.push(self.hash_alg);
145
146        // KDF algorithm
147        tmp_buffer.extend([0x03, 0x01]);
148        tmp_buffer.push(self.kdf_alg);
149
150        // Compression algorithm
151        tmp_buffer.extend([0x04, 0x01]);
152        tmp_buffer.push(self.compression_alg);
153
154        // Master salt
155        tmp_buffer.push(0x06);
156        tmp_buffer.push(self.master_salt.len().try_into()?);
157        tmp_buffer.extend(self.master_salt.clone());
158
159        // Data encryption nonce
160        let nonce = self.nonce.as_ref().unwrap();
161        let nonce_size: u8 = nonce.len().try_into()?;
162        tmp_buffer.push(0x07);
163        tmp_buffer.push(nonce_size);
164        tmp_buffer.extend(nonce);
165
166        // Root key encryption nonce
167        let root_key_nonce = self.root_key_nonce.as_ref().unwrap();
168        let nonce_size: u8 = root_key_nonce.len().try_into()?;
169        tmp_buffer.push(0x08);
170        tmp_buffer.push(nonce_size);
171        tmp_buffer.extend(root_key_nonce);
172
173        // Encrypted root key
174        let root_key_ciphertext = self.root_key_ciphertext.as_ref().unwrap();
175        let key_size: u8 = root_key_ciphertext.len().try_into()?;
176        tmp_buffer.push(0x09);
177        tmp_buffer.push(key_size);
178        tmp_buffer.extend(root_key_ciphertext);
179
180        // Key Derivation params
181        // Iterations
182        tmp_buffer.extend([0x0a, 0x01]);
183        tmp_buffer.push(self.kdf_params.iterations);
184        // Threads
185        tmp_buffer.extend([0x0b, 0x01]);
186        tmp_buffer.push(self.kdf_params.threads);
187        // Memory (in kibibytes)
188        tmp_buffer.extend([0x0c, 0x04]);
189        tmp_buffer.extend(self.kdf_params.memory.to_be_bytes());
190
191        // End of header section
192        tmp_buffer.extend([0x0, 0x0]);
193
194        // Count header section length and append to buffer
195        let header_length: u16 = (tmp_buffer.len() + 8).try_into()?;
196        buffer.extend(header_length.to_be_bytes());
197        buffer.extend(tmp_buffer);
198
199        self.data_length = header_length;
200
201        Ok(buffer)
202    }
203
204    /// Check whether the header is valid in the current version
205    pub fn validate_version(&mut self) -> bool {
206        match self.version {
207            0x01 => {
208                if !ENCRYPTION_ALGORITHMS.contains(&self.encryption_alg) {
209                    return false;
210                }
211                if !HASH_ALGORITHMS.contains(&self.hash_alg) {
212                    return false;
213                }
214                if !KDF_ALGORITHMS.contains(&self.kdf_alg) {
215                    return false;
216                }
217                if !COMPRESSION_ALGORITHMS.contains(&self.compression_alg) {
218                    return false;
219                }
220                true
221            }
222            _ => false,
223        }
224    }
225}