deadbolt_parser/
lib.rs

1#![allow(dead_code)]
2
3pub mod algorithms;
4mod compression;
5pub mod config;
6pub mod header;
7pub mod password;
8
9use std::error::Error;
10use std::fs::{self, File};
11use std::io::Read;
12use std::string::String;
13
14use config::Config;
15use header::Header;
16use secrecy::{ExposeSecret, Secret};
17
18use deadbolt_crypto::encryption::{Encryption, StreamEncryption};
19use deadbolt_crypto::hash::{Hkdf, Hmac, PasswordHash};
20use deadbolt_crypto::rand::Random;
21
22type MasterKeySignature = (Secret<Vec<u8>>, Secret<Vec<u8>>);
23
24#[derive(Debug, Clone, PartialEq)]
25pub struct Data {
26    pub key: String,
27    pub metadata: String,
28    pub value: Vec<u8>,
29}
30
31impl Data {
32    pub fn new(key: String, metadata: String, value: Vec<u8>) -> Data {
33        Data {
34            key,
35            metadata,
36            value,
37        }
38    }
39}
40
41pub struct Parser {
42    pub header: Header,
43    pub data: Vec<Data>,
44    pub signature_key: Secret<Vec<u8>>,
45    pub root_key: Secret<Vec<u8>>,
46    pub filepath: String,
47    raw_content: Vec<u8>,
48    pub config: Config,
49}
50
51impl Parser {
52    pub fn new(
53        signature_key: Secret<Vec<u8>>,
54        root_key: Secret<Vec<u8>>,
55        master_salt: Vec<u8>,
56        encrypted_root_key: Option<Vec<u8>>,
57        nonce: Option<Vec<u8>>,
58    ) -> Parser {
59        let mut header = Header::new(None, None, None, None, Some(master_salt));
60        header.root_key_ciphertext = encrypted_root_key;
61        header.root_key_nonce = nonce;
62
63        Parser {
64            header,
65            data: vec![],
66            signature_key,
67            root_key,
68            filepath: "".to_string(),
69            raw_content: vec![],
70            config: config::default_config(),
71        }
72    }
73
74    pub fn new_default() -> Parser {
75        Parser {
76            header: Header::new(None, None, None, None, None),
77            data: vec![],
78            signature_key: Secret::new(vec![]),
79            root_key: Secret::new(vec![]),
80            filepath: "".to_string(),
81            raw_content: vec![],
82            config: config::default_config(),
83        }
84    }
85
86    /// Read db from file and store the content.
87    /// Only header section will be parsed
88    pub fn read_from_file(&mut self, filepath: &str) -> Result<(), Box<dyn Error>> {
89        let raw_data = fs::read(filepath)?;
90        let header = Header::new_from_vector(raw_data.clone())?;
91
92        self.header = header;
93        self.raw_content = raw_data;
94        self.filepath = filepath.to_string();
95
96        Ok(())
97    }
98
99    /// Verify password without having to read the whole file content
100    pub fn verify_password_from_file(
101        filepath: &str,
102        master_password: Secret<String>,
103    ) -> Result<MasterKeySignature, Box<dyn Error>> {
104        // Read only the first 10 bytes of file
105        let mut file = File::open(filepath)?;
106        let mut fixed_header_data: Vec<u8> = vec![0; 8];
107        file.read_exact(&mut fixed_header_data)?;
108
109        // Read only header section of the file
110        let (version, header_length) = Header::quick_lookup(fixed_header_data)?;
111        let mut header_data: Vec<u8> = vec![0; header_length.try_into()?];
112        file.read_exact(&mut header_data)?;
113
114        let mut header = Header::new(None, None, None, None, None);
115        header.version = version;
116        header.data_length = header_length;
117        header.parse_tlv_header(header_data)?;
118
119        let (master_key, signature_key) = Parser::derive_master_key(
120            master_password,
121            &header.master_salt,
122            algorithms::KdfAlg::from_u8(header.kdf_alg)
123                .to_str()
124                .to_owned(),
125            header.kdf_params.iterations,
126            header.kdf_params.threads,
127            header.kdf_params.memory,
128        );
129
130        let mut cipher = Encryption::new(&master_key);
131        let nonce = header.root_key_nonce.as_ref().unwrap()[..].try_into()?;
132        let decryption_result = cipher.decrypt(
133            nonce,
134            header.root_key_ciphertext.as_ref().unwrap().to_vec(),
135            header.encryption_alg,
136        );
137
138        match decryption_result {
139            Ok(_) => Ok((master_key, signature_key)),
140            Err(e) => Err(e),
141        }
142    }
143
144    /// Derive `master_key` and `signature_key` from `master_password`
145    pub fn derive_master_key(
146        master_password: Secret<String>,
147        salt: &[u8],
148        algorithm: String,
149        iterations: u8,
150        threads: u8,
151        memory: u32,
152    ) -> MasterKeySignature {
153        let mut password_hash: Secret<Vec<u8>> = Secret::new(vec![]);
154        if algorithm == "argon2d" {
155            password_hash =
156                PasswordHash::argon2d(master_password, salt, iterations, threads, memory);
157        } else if algorithm == "argon2id" {
158            password_hash =
159                PasswordHash::argon2id(master_password, salt, iterations, threads, memory);
160        }
161        let key_material: Secret<Vec<u8>> =
162            Hkdf::expand(password_hash.expose_secret().to_vec().into());
163        let master_key = Secret::new(key_material.expose_secret()[..32].to_vec());
164        let signature_key = Secret::new(key_material.expose_secret()[32..].to_vec());
165
166        (master_key, signature_key)
167    }
168
169    /// Decrypt `encrypted_root_key` and set it as current `root_key`
170    pub fn get_root_key(&mut self, master_key: &Secret<Vec<u8>>) {
171        let mut cipher = Encryption::new(master_key);
172        let root_key = cipher
173            .decrypt(
174                self.header
175                    .root_key_nonce
176                    .as_ref()
177                    .unwrap()
178                    .to_vec()
179                    .try_into()
180                    .unwrap(),
181                self.header.root_key_ciphertext.as_ref().unwrap().to_vec(),
182                self.header.encryption_alg,
183            )
184            .expect("Invalid master key");
185
186        self.root_key = Secret::new(root_key.data);
187    }
188
189    /// Generate new random `root_key` and its encrypted form
190    pub fn generate_root_key(
191        master_key: Secret<Vec<u8>>,
192        encryption_alg: u8,
193    ) -> (Secret<Vec<u8>>, Vec<u8>, [u8; 12]) {
194        let root_key = Secret::new(Random::get_rand_bytes());
195        let mut cipher = Encryption::new(&master_key);
196        let encrypted_root_key = cipher
197            .encrypt(root_key.expose_secret().to_vec(), encryption_alg)
198            .unwrap();
199
200        (root_key, encrypted_root_key.data, encrypted_root_key.nonce)
201    }
202
203    /// Get the `child_key` from the current `root_key`
204    pub fn generate_child_key(&mut self) -> Secret<Vec<u8>> {
205        let mut hasher = Hmac::new(&self.signature_key);
206        hasher.update(self.root_key.expose_secret());
207
208        Secret::new(hasher.finalize())
209    }
210
211    /// Add new entry to the `Parser.data`
212    pub fn new_password_entry(&mut self, key: String, metadata: String, password: Secret<String>) {
213        let ciphertext = StreamEncryption::encrypt(
214            &self.generate_child_key(),
215            password.expose_secret().as_bytes(),
216        );
217
218        self.data.push(Data {
219            key,
220            metadata,
221            value: ciphertext,
222        })
223    }
224
225    /// Parse the TLV data
226    pub fn read_tlv(data: Vec<u8>) -> Result<Vec<Data>, Box<dyn Error>> {
227        let mut index = 0;
228        let mut current_data_index = 0;
229
230        let mut buffer = vec![];
231
232        loop {
233            let data_type = data[index];
234
235            match data_type {
236                1 => {
237                    index += 1;
238                    let start = index + 1;
239                    let end = start + usize::from(data[index]);
240                    let current_key = String::from_utf8_lossy(&data[start..end]).to_string();
241                    index = end;
242
243                    buffer.push(Data {
244                        key: current_key,
245                        metadata: "".to_string(),
246                        value: vec![],
247                    });
248                    current_data_index += 1;
249                }
250                2 => {
251                    index += 1;
252                    let start = index + 4;
253                    let length = u32::from_be_bytes(data[index..index + 4].try_into()?);
254                    let end = start + usize::try_from(length)?;
255                    let current_metadata = String::from_utf8_lossy(&data[start..end]).to_string();
256                    index = end;
257
258                    buffer[current_data_index - 1].metadata = current_metadata;
259                }
260                3 => {
261                    index += 1;
262                    let start = index + 1;
263                    let end = start + usize::from(data[index]);
264                    let current_value = data[start..end].to_vec();
265                    index = end;
266
267                    buffer[current_data_index - 1].value = current_value;
268                }
269                _ => {
270                    break;
271                }
272            }
273        }
274
275        Ok(buffer)
276    }
277
278    /// Read the whole data section and store it in `Parser.data`
279    fn parse_data(&mut self) -> Result<(), Box<dyn Error>> {
280        let mut cipher = Encryption::new(&self.root_key);
281        let nonce = self.header.nonce.as_ref().unwrap()[..].try_into()?;
282        let header_length: usize = (self.header.data_length + 32).try_into()?;
283        let decryption_result = cipher.decrypt(
284            nonce,
285            self.raw_content[header_length..].to_vec(),
286            self.header.encryption_alg,
287        );
288
289        match decryption_result {
290            Ok(decrypted_data) => {
291                let mut plain_data = decrypted_data.data;
292                if self.header.compression_alg != 0 {
293                    plain_data = compression::Gzip::decompress(plain_data)?;
294                }
295                self.data = Parser::read_tlv(plain_data)?;
296
297                Ok(())
298            }
299
300            Err(e) => Err(e),
301        }
302    }
303
304    /// Construct the db content
305    fn construct_content(&mut self) -> Result<(), Box<dyn Error>> {
306        // Construct plain data section
307        let mut plain_data: Vec<u8> = vec![];
308        for data in &self.data {
309            // Key type
310            plain_data.push(0x01);
311            plain_data.push(data.key.len().try_into()?);
312            plain_data.extend(data.key.as_bytes());
313
314            // Metadata type
315            let metadata_len: u32 = data.metadata.len().try_into()?;
316            plain_data.push(0x02);
317            plain_data.extend(metadata_len.to_be_bytes().to_vec());
318            plain_data.extend(data.metadata.as_bytes());
319
320            // Password type
321            plain_data.push(0x03);
322            plain_data.push(data.value.len().try_into()?);
323            plain_data.extend(data.value.clone());
324        }
325
326        // Terminator (end of data section)
327        plain_data.push(0x00);
328
329        // Compress plain data (optional)
330        if self.config.algorithms.compression {
331            plain_data = compression::Gzip::compress(plain_data)?;
332        }
333
334        // Encrypt data section
335        let mut cipher = Encryption::new(&self.root_key);
336        let encrypted_data = cipher.encrypt(
337            plain_data,
338            algorithms::EncryptionAlg::from_str(&self.config.algorithms.encryption).value(),
339        )?;
340
341        // Update existing variables of parser
342        self.header.encryption_alg =
343            algorithms::EncryptionAlg::from_str(&self.config.algorithms.encryption).value();
344        self.header.hash_alg = algorithms::HashAlg::from_str(&self.config.algorithms.hash).value();
345        self.header.kdf_alg =
346            algorithms::KdfAlg::from_str(&self.config.algorithms.kdf.algorithm).value();
347        self.header.compression_alg =
348            algorithms::CompressionAlg::from_bool(self.config.algorithms.compression).value();
349        self.header.nonce = Some(encrypted_data.nonce.to_vec());
350
351        match &self.config.algorithms.kdf.parameters {
352            Some(params) => {
353                self.header.kdf_params.iterations = params.iterations;
354                self.header.kdf_params.threads = params.threads;
355                self.header.kdf_params.memory = params.memory;
356            }
357            None => {}
358        }
359
360        // Construct header section
361        let mut buffer: Vec<u8> = self.header.construct_header()?;
362
363        // Construct signature section
364        let mut hmac = Hmac::new(&self.signature_key);
365        hmac.update(&buffer);
366        let tag = hmac.finalize();
367        buffer.extend(tag);
368
369        // And encrypted data section to constructed buffer
370        buffer.extend(encrypted_data.data);
371
372        self.raw_content = buffer;
373
374        Ok(())
375    }
376
377    /// Verify whether the signature is correct with the header data
378    pub fn verify_signature(&mut self) -> Result<(), Box<dyn Error>> {
379        let mut hmac = Hmac::new(&self.signature_key);
380        let header_len: usize = self.header.data_length.try_into()?;
381        hmac.update(&self.raw_content[..header_len]);
382        let expected_mac = &self.raw_content[header_len..header_len + 32];
383
384        hmac.verify(expected_mac)?;
385        Ok(())
386    }
387
388    /// Parse `Parser.raw_content` into `Parser.data`
389    pub fn read_raw_content(&mut self) -> Result<(), Box<dyn Error>> {
390        if self.verify_signature().is_ok() {
391            if !self.header.validate_version() {
392                return Err("Invalid header data".to_string().into());
393            }
394            return self.parse_data();
395        }
396        Err("File might be corrupted".to_string().into())
397    }
398
399    /// Write content into file
400    pub fn write_to_file(&mut self) -> Result<(), Box<dyn Error>> {
401        self.construct_content()?;
402        fs::write(&self.filepath, &self.raw_content)?;
403        Ok(())
404    }
405}
406
407#[cfg(test)]
408mod tests {
409    use std::env::temp_dir;
410
411    use crate::{Data, Parser};
412    use deadbolt_crypto::encryption::StreamEncryption;
413    use secrecy::{ExposeSecret, Secret};
414
415    fn generate_temp_test_file(filename: &str) -> String {
416        let mut test_path = temp_dir();
417        test_path.push(filename);
418
419        test_path.to_string_lossy().to_string()
420    }
421
422    #[test]
423    fn test_read_tlv() {
424        let test_data: [Data; 3] = [
425            Data {
426                key: "test1".to_string(),
427                metadata: "test1".to_string(),
428                value: vec![0x01, 0x02, 0x03],
429            },
430            Data {
431                key: "test2".to_string(),
432                metadata: "test2".to_string(),
433                value: vec![],
434            },
435            Data {
436                key: "test3".to_string(),
437                metadata: "".to_string(),
438                value: vec![],
439            },
440        ];
441        let length: u32 = test_data[0].metadata.len().try_into().unwrap();
442        let mut buffer: Vec<u8> = vec![0x01];
443        buffer.push(test_data[0].key.len().try_into().unwrap());
444        buffer.extend(test_data[0].key.as_bytes());
445        buffer.push(0x02);
446        buffer.extend(length.to_be_bytes());
447        buffer.extend(test_data[0].metadata.as_bytes());
448        buffer.push(0x03);
449        buffer.push(test_data[0].value.len().try_into().unwrap());
450        buffer.extend(test_data[0].value.clone());
451
452        buffer.push(0x01);
453        buffer.push(test_data[1].key.len().try_into().unwrap());
454        buffer.extend(test_data[1].key.as_bytes());
455        buffer.push(0x02);
456        buffer.extend(length.to_be_bytes());
457        buffer.extend(test_data[1].metadata.as_bytes());
458
459        buffer.push(0x01);
460        buffer.push(test_data[2].key.len().try_into().unwrap());
461        buffer.extend(test_data[2].key.as_bytes());
462
463        buffer.push(0x00);
464
465        let result = Parser::read_tlv(buffer).unwrap();
466
467        assert_eq!(result[0], test_data[0]);
468        assert_eq!(result[1], test_data[1]);
469        assert_eq!(result[2], test_data[2]);
470    }
471
472    #[test]
473    fn test_read_write_file() {
474        let path = &generate_temp_test_file("test-1.dblt");
475        let master_password = Secret::new("password123".to_string());
476
477        let (master_key, signature_key) = Parser::derive_master_key(
478            master_password.clone(),
479            "yellow_submarine".as_bytes(),
480            "argon2d".to_string(),
481            3,
482            4,
483            64 * 1024,
484        );
485        let (root_key, encrypted_root_key, root_key_nonce) =
486            Parser::generate_root_key(Secret::new(master_key.expose_secret().clone()), 1);
487        let mut write_parser = Parser::new(
488            Secret::new(signature_key.expose_secret().clone()),
489            Secret::new(root_key.expose_secret().clone()),
490            "yellow_submarine".as_bytes().to_vec(),
491            Some(encrypted_root_key.clone()),
492            Some(root_key_nonce.to_vec()),
493        );
494        let test_str = "test";
495        write_parser.new_password_entry(
496            test_str.to_string(),
497            test_str.to_string(),
498            Secret::new(test_str.to_string()),
499        );
500        write_parser.filepath = path.to_string();
501        write_parser.write_to_file().unwrap();
502
503        let mut read_parser = Parser::new(
504            signature_key,
505            root_key,
506            "yellow_submarine".as_bytes().to_vec(),
507            Some(encrypted_root_key),
508            Some(root_key_nonce.to_vec()),
509        );
510        read_parser.read_from_file(path).unwrap();
511        read_parser.read_raw_content().unwrap();
512
513        assert!(Parser::verify_password_from_file(path, master_password).is_ok());
514        assert_eq!(write_parser.header, read_parser.header);
515        assert_eq!(write_parser.data.len(), read_parser.data.len());
516
517        assert_eq!(write_parser.data[0].key, read_parser.data[0].key);
518        assert_eq!(write_parser.data[0].metadata, read_parser.data[0].metadata);
519        assert_eq!(write_parser.data[0].value, read_parser.data[0].value);
520
521        let child_key = write_parser.generate_child_key();
522        let writer_plaintext = StreamEncryption::decrypt(&child_key, &write_parser.data[0].value);
523        let reader_plaintext = StreamEncryption::decrypt(&child_key, &read_parser.data[0].value);
524
525        assert_eq!(writer_plaintext, reader_plaintext);
526    }
527
528    #[test]
529    fn test_invalid_password() {
530        let path = &generate_temp_test_file("test-2.dblt");
531        let (master_key, signature_key) = Parser::derive_master_key(
532            Secret::new("password123".to_string()),
533            "yellow_submarine".as_bytes(),
534            "argon2d".to_string(),
535            2,
536            1,
537            19 * 1024,
538        );
539        let (root_key, encrypted_root_key, root_key_nonce) =
540            Parser::generate_root_key(master_key, 1);
541        let mut write_parser = Parser::new(
542            Secret::new(signature_key.expose_secret().clone()),
543            Secret::new(root_key.expose_secret().clone()),
544            "yellow_submarine".as_bytes().to_vec(),
545            Some(encrypted_root_key),
546            Some(root_key_nonce.to_vec()),
547        );
548        write_parser.filepath = path.to_string();
549        write_parser.write_to_file().unwrap();
550
551        let invalid_password = Secret::new("password1234".to_string());
552
553        let expected_from_sample = Parser::verify_password_from_file(path, invalid_password);
554
555        assert!(expected_from_sample.is_err());
556    }
557}