1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::kdbx::Kdbx4;
use byteorder::{ByteOrder, LE};
use sha2::{Digest, Sha256, Sha512};
use std::fs::read;
use std::io;
use std::path::Path;
pub struct CompositeKey {
keys: Vec<[u8; 32]>,
}
impl CompositeKey {
#[allow(clippy::new_ret_no_self)]
pub fn new<P, F>(password: Option<P>, key_file: Option<F>) -> Result<Self, io::Error>
where
P: AsRef<str>,
F: AsRef<Path>,
{
let mut keys = Vec::with_capacity(3);
if let Some(pass) = password {
keys.push(hash(pass.as_ref().as_bytes()))
}
if let Some(key_file) = key_file {
keys.push(hash(&read(key_file)?))
}
Ok(CompositeKey { keys })
}
pub(super) fn transform_with<'a>(&self, kdbx: &'a Kdbx4) -> TransformedKey<'a> {
let transformed_key = kdbx.kdf.transform(&self.compose_keys());
TransformedKey(transformed_key, kdbx)
}
fn compose_keys(&self) -> [u8; 32] {
let mut h = Sha256::new();
self.keys.iter().for_each(|k| h.update(k));
h.finalize().into()
}
}
pub struct TransformedKey<'a>(Vec<u8>, &'a Kdbx4);
impl<'a> TransformedKey<'a> {
pub fn header_key(&self) -> [u8; 64] {
use crate::constants;
self.block_key(constants::HEADER_BLK_IDX)
}
pub fn block_key(&self, block_idx: u64) -> [u8; 64] {
let mut block_idx_bytes = [0; 8];
LE::write_u64(&mut block_idx_bytes, block_idx);
let mut h = Sha512::new();
h.update(&block_idx_bytes);
h.update(&self.hmac_key().as_ref());
unsafe { std::mem::transmute(h.finalize()) }
}
pub fn hmac_key(&self) -> [u8; 64] {
let mut h = Sha512::new();
h.update(&self.1.master_seed);
h.update(&self.0);
h.update(&[1]);
unsafe { std::mem::transmute(h.finalize()) }
}
pub fn final_key(&self) -> [u8; 32] {
let mut h = Sha256::new();
h.update(&self.1.master_seed);
h.update(&self.0);
unsafe { std::mem::transmute(h.finalize()) }
}
}
fn hash(slice: &[u8]) -> [u8; 32] {
let mut h = Sha256::new();
h.update(slice);
unsafe { std::mem::transmute(h.finalize()) }
}