1use super::{errors, header};
2use crate::{crypto, database, stream};
3use std::io::{Read, Write};
4use std::ops::{Deref, DerefMut};
5
6pub trait KdbxState: std::fmt::Debug {
7 fn header(&self) -> &header::KdbxHeader;
8 fn header_mut(&mut self) -> &mut header::KdbxHeader;
9 fn major_version(&self) -> u16;
10 fn minor_version(&self) -> u16;
11 fn write<W: Write>(&self, output: W) -> Result<(), errors::WriteError>;
12}
13
14#[derive(Debug)]
15pub struct Kdbx<S>
27where
28 S: KdbxState,
29{
30 pub(super) state: S,
31}
32
33impl<T: KdbxState> Kdbx<T> {
34 pub fn header(&self) -> &header::KdbxHeader {
36 self.state.header()
37 }
38
39 pub fn header_mut(&mut self) -> &mut header::KdbxHeader {
41 self.state.header_mut()
42 }
43
44 pub fn major_version(&self) -> u16 {
46 self.state.major_version()
47 }
48
49 pub fn minor_version(&self) -> u16 {
51 self.state.minor_version()
52 }
53
54 pub fn write<W: Write>(&self, output: W) -> Result<(), errors::WriteError> {
56 self.state.write(output)?;
57 Ok(())
58 }
59}
60
61pub struct FailedUnlock(pub Kdbx<Locked>, pub errors::UnlockError);
71
72impl From<FailedUnlock> for errors::UnlockError {
73 fn from(funlock: FailedUnlock) -> errors::UnlockError {
74 funlock.1
75 }
76}
77
78#[derive(Debug)]
79pub struct Unlocked {
81 pub(crate) header: header::KdbxHeader,
83 pub(crate) inner_header: header::KdbxInnerHeader,
85 pub(crate) major_version: u16,
87 pub(crate) minor_version: u16,
89 pub(crate) composed_key: Option<crypto::ComposedKey>,
91 pub(crate) master_key: Option<crypto::MasterKey>,
93 pub(crate) xml_data: Option<Vec<u8>>,
95 pub(crate) database: crate::Database,
97}
98
99impl Unlocked {
100 fn encrypt_inner(&self, key: &crypto::MasterKey) -> Result<Vec<u8>, super::errors::WriteError> {
101 let mut encrypted_buf = Vec::new();
102 let mut encrypted_stream = crate::stream::kdbx4_write_stream(
103 &mut encrypted_buf,
104 key.hmac_key(&self.header.master_seed),
105 key.cipher_key(&self.header.master_seed),
106 self.header.cipher,
107 &self.header.encryption_iv,
108 self.header.compression_type,
109 )?;
110 self.inner_header.write(&mut encrypted_stream)?;
111 let mut stream_cipher = self
112 .inner_header
113 .inner_stream_cipher
114 .stream_cipher(&self.inner_header.inner_stream_key)?;
115 crate::xml::write_xml(
116 &mut encrypted_stream,
117 &self.database,
118 stream_cipher.as_mut(),
119 )?;
120
121 encrypted_stream.finish()?;
122 Ok(encrypted_buf)
123 }
124}
125
126impl KdbxState for Unlocked {
127 fn header(&self) -> &header::KdbxHeader {
128 &self.header
129 }
130
131 fn header_mut(&mut self) -> &mut header::KdbxHeader {
132 &mut self.header
133 }
134
135 fn major_version(&self) -> u16 {
136 self.major_version
137 }
138
139 fn minor_version(&self) -> u16 {
140 self.minor_version
141 }
142
143 fn write<W: Write>(&self, mut output: W) -> Result<(), errors::WriteError> {
144 let master_key = self
145 .master_key
146 .as_ref()
147 .ok_or(errors::WriteError::MissingKeys)?;
148 let mut header_buf = Vec::new();
149 let header_writer = &mut header_buf as &mut dyn Write;
150 header_writer.write_all(&super::KEEPASS_MAGIC_NUMBER.to_le_bytes())?;
151 header_writer.write_all(&super::KDBX_MAGIC_NUMBER.to_le_bytes())?;
152 header_writer.write_all(&self.minor_version.to_le_bytes())?;
153 header_writer.write_all(&self.major_version.to_le_bytes())?;
154 self.header.write(&mut header_buf)?;
155 output.write_all(&header_buf)?;
156 output.write_all(&crypto::sha256(&header_buf))?;
157 let hmac_key = master_key.hmac_key(&self.header.master_seed);
158 let hmac = hmac_key
159 .block_key(u64::MAX)
160 .calculate_header_hmac(&header_buf)
161 .map_err(|_| errors::WriteError::MissingKeys)?;
162 output.write_all(&hmac.into_bytes())?;
163 let encrypted_xml = self.encrypt_inner(master_key)?;
164 output.write_all(&encrypted_xml)?;
165 Ok(())
166 }
167}
168
169impl Kdbx<Unlocked> {
170 pub fn inner_header(&self) -> &header::KdbxInnerHeader {
172 &self.state.inner_header
173 }
174
175 pub fn inner_header_mut(&mut self) -> &mut header::KdbxInnerHeader {
177 &mut self.state.inner_header
178 }
179
180 pub fn set_key(
182 &mut self,
183 key: crypto::CompositeKey,
184 ) -> Result<(), crate::errors::KeyGenerationError> {
185 self.state.composed_key = Some(key.composed());
186 let composed_key = self.state.composed_key.as_ref().unwrap();
187 self.state.master_key = Some(composed_key.master_key(&self.header().kdf_params)?);
188
189 Ok(())
190 }
191
192 pub fn raw_xml(&self) -> Option<&[u8]> {
196 self.state.xml_data.as_deref()
197 }
198
199 pub fn database(&self) -> &crate::Database {
201 &self.state.database
202 }
203
204 pub fn database_mut(&mut self) -> &mut crate::Database {
206 &mut self.state.database
207 }
208
209 pub fn from_database(database: crate::Database) -> Kdbx<Unlocked> {
219 let header = header::KdbxHeader::from_os_random();
220 let inner_header = header::KdbxInnerHeader::from_os_random();
221 let unlocked = Unlocked {
222 header,
223 inner_header,
224 major_version: 4,
225 minor_version: 0,
226 xml_data: None,
227 composed_key: None,
228 master_key: None,
229 database,
230 };
231 Kdbx { state: unlocked }
232 }
233}
234
235impl Deref for Kdbx<Unlocked> {
236 type Target = database::Database;
237
238 fn deref(&self) -> &database::Database {
239 &self.state.database
240 }
241}
242
243impl DerefMut for Kdbx<Unlocked> {
244 fn deref_mut(&mut self) -> &mut database::Database {
245 &mut self.state.database
246 }
247}
248
249#[derive(Debug, PartialEq, Eq)]
250pub struct Locked {
252 pub(crate) header: header::KdbxHeader,
254 pub(crate) header_data: Vec<u8>,
256 pub(crate) major_version: u16,
258 pub(crate) minor_version: u16,
260 pub(crate) hmac: Option<Vec<u8>>,
262 pub(crate) encrypted_data: Vec<u8>,
264}
265
266impl KdbxState for Locked {
267 fn header(&self) -> &header::KdbxHeader {
268 &self.header
269 }
270
271 fn header_mut(&mut self) -> &mut header::KdbxHeader {
272 &mut self.header
273 }
274
275 fn major_version(&self) -> u16 {
276 self.major_version
277 }
278
279 fn minor_version(&self) -> u16 {
280 self.minor_version
281 }
282
283 fn write<W: Write>(&self, mut output: W) -> Result<(), errors::WriteError> {
284 let mut header_buf = Vec::new();
285 let header_writer = &mut header_buf as &mut dyn Write;
286 header_writer.write_all(&super::KEEPASS_MAGIC_NUMBER.to_le_bytes())?;
287 header_writer.write_all(&super::KDBX_MAGIC_NUMBER.to_le_bytes())?;
288 header_writer.write_all(&self.minor_version.to_le_bytes())?;
289 header_writer.write_all(&self.major_version.to_le_bytes())?;
290 self.header.write(&mut header_buf)?;
291 output.write_all(&header_buf)?;
292 if self.major_version >= 4 {
293 output.write_all(&crypto::sha256(&header_buf))?;
294 output.write_all(self.hmac.as_ref().unwrap())?;
295 }
296 output.write_all(&self.encrypted_data)?;
297 Ok(())
298 }
299}
300
301impl Kdbx<Locked> {
302 fn decrypt_v4(
303 &self,
304 master_key: &crypto::MasterKey,
305 ) -> Result<(header::KdbxInnerHeader, Vec<u8>), errors::UnlockError> {
306 let hmac_key = master_key.hmac_key(&self.state.header.master_seed);
307 let cipher_key = master_key.cipher_key(&self.state.header.master_seed);
308 let mut input_stream = stream::kdbx4_read_stream(
309 &*self.state.encrypted_data,
310 hmac_key,
311 cipher_key,
312 self.state.header.cipher,
313 &self.state.header.encryption_iv,
314 self.state.header.compression_type,
315 )?;
316 let inner_header =
317 header::KdbxInnerHeader::read(&mut input_stream, self.state.major_version)?;
318 let mut output_buffer = Vec::new();
319 input_stream.read_to_end(&mut output_buffer)?;
320 Ok((inner_header, output_buffer))
321 }
322
323 #[allow(clippy::result_large_err)]
327 pub fn unlock(self, key: &crypto::CompositeKey) -> Result<Kdbx<Unlocked>, FailedUnlock> {
328 if self.state.major_version >= 4 {
329 self.unlock_v4(key)
330 } else {
331 self.unlock_v3(key)
332 }
333 }
334
335 fn decrypt_v3(
336 &self,
337 master_key: &crypto::MasterKey,
338 ) -> Result<(header::KdbxInnerHeader, Vec<u8>), errors::UnlockError> {
339 let cipher_key = master_key.cipher_key(&self.state.header.master_seed);
340 let mut input_stream = stream::kdbx3_read_stream(
341 &*self.state.encrypted_data,
342 cipher_key,
343 self.state.header.cipher,
344 &self.state.header.encryption_iv,
345 self.state.header.compression_type,
346 self.header().stream_start_bytes.as_ref().unwrap(),
347 )?;
348 let inner_header = header::KdbxInnerHeader::from_legacy_fields(&self.state.header)?;
349 let mut output_buffer = Vec::new();
350 input_stream.read_to_end(&mut output_buffer)?;
351 Ok((inner_header, output_buffer))
352 }
353
354 #[allow(clippy::result_large_err)]
355 fn unlock_v3(self, key: &crypto::CompositeKey) -> Result<Kdbx<Unlocked>, FailedUnlock> {
356 let composed_key = key.composed();
357 let master_key = match composed_key.master_key(&self.header().kdf_params) {
358 Ok(master_key) => master_key,
359 Err(e) => return Err(FailedUnlock(self, errors::UnlockError::from(e))),
360 };
361
362 let parsed = self
363 .decrypt_v3(&master_key)
364 .and_then(|(inner_header, data)| {
365 let mut stream_cipher = inner_header
366 .inner_stream_cipher
367 .stream_cipher(inner_header.inner_stream_key.as_ref())?;
368 let parsed = crate::xml::parse_xml(data.as_slice(), stream_cipher.as_mut())?;
369 Ok((inner_header, data, parsed))
370 });
371 match parsed {
372 Ok((inner_header, data, db)) => Ok(Kdbx {
373 state: Unlocked {
374 inner_header,
375 header: self.state.header,
376 major_version: self.state.major_version,
377 minor_version: self.state.minor_version,
378 composed_key: Some(composed_key),
379 master_key: Some(master_key),
380 database: db,
381 xml_data: Some(data),
382 },
383 }),
384 Err(e) => Err(FailedUnlock(self, e)),
385 }
386 }
387
388 #[allow(clippy::result_large_err)]
389 fn unlock_v4(self, key: &crypto::CompositeKey) -> Result<Kdbx<Unlocked>, FailedUnlock> {
390 let composed_key = key.composed();
391 let master_key = match composed_key.master_key(&self.header().kdf_params) {
392 Ok(master_key) => master_key,
393 Err(e) => return Err(FailedUnlock(self, errors::UnlockError::from(e))),
394 };
395 let hmac_key = master_key.hmac_key(&self.state.header.master_seed);
396 let header_block_key = hmac_key.block_key(u64::MAX);
397
398 let hmac = self.state.hmac.clone().unwrap();
399
400 if header_block_key.verify_header_block(hmac.as_ref(), &self.state.header_data) {
401 let parsed = self
402 .decrypt_v4(&master_key)
403 .and_then(|(inner_header, data)| {
404 let mut stream_cipher = inner_header
405 .inner_stream_cipher
406 .stream_cipher(inner_header.inner_stream_key.as_ref())?;
407 let parsed = crate::xml::parse_xml(data.as_slice(), stream_cipher.as_mut())?;
408 Ok((inner_header, data, parsed))
409 });
410
411 match parsed {
412 Ok((inner_header, data, db)) => Ok(Kdbx {
413 state: Unlocked {
414 inner_header,
415 header: self.state.header,
416 major_version: self.state.major_version,
417 minor_version: self.state.minor_version,
418 composed_key: Some(composed_key),
419 master_key: Some(master_key),
420 database: db,
421 xml_data: Some(data),
422 },
423 }),
424 Err(e) => Err(FailedUnlock(self, e)),
425 }
426 } else {
427 Err(FailedUnlock(self, errors::UnlockError::HmacInvalid))
428 }
429 }
430}