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 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 pub fn verify_password_from_file(
101 filepath: &str,
102 master_password: Secret<String>,
103 ) -> Result<MasterKeySignature, Box<dyn Error>> {
104 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 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 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 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 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 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 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 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 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 fn construct_content(&mut self) -> Result<(), Box<dyn Error>> {
306 let mut plain_data: Vec<u8> = vec![];
308 for data in &self.data {
309 plain_data.push(0x01);
311 plain_data.push(data.key.len().try_into()?);
312 plain_data.extend(data.key.as_bytes());
313
314 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 plain_data.push(0x03);
322 plain_data.push(data.value.len().try_into()?);
323 plain_data.extend(data.value.clone());
324 }
325
326 plain_data.push(0x00);
328
329 if self.config.algorithms.compression {
331 plain_data = compression::Gzip::compress(plain_data)?;
332 }
333
334 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 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 let mut buffer: Vec<u8> = self.header.construct_header()?;
362
363 let mut hmac = Hmac::new(&self.signature_key);
365 hmac.update(&buffer);
366 let tag = hmac.finalize();
367 buffer.extend(tag);
368
369 buffer.extend(encrypted_data.data);
371
372 self.raw_content = buffer;
373
374 Ok(())
375 }
376
377 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 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 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}