1use std::collections::VecDeque;
26use std::collections::{BTreeMap, HashMap};
27use std::convert::TryInto;
28use std::slice::Iter;
29use std::fs::File;
30use std::io::prelude::*;
31use std::io::Cursor;
32use std::io::{self, SeekFrom};
33use std::process;
34use std::cmp;
35
36use num_derive::{FromPrimitive, ToPrimitive};
37use num_traits::FromPrimitive;
38#[cfg(feature = "write")]
39use num_traits::ToPrimitive;
40
41use log::debug;
42
43use base64::engine::{Engine, general_purpose::STANDARD as base64};
44use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
45use uuid::{uuid, Uuid};
46use chrono::prelude::*;
48use flate2::read::GzDecoder;
49
50use openssl::error::ErrorStack;
51use openssl::symm::{decrypt, Cipher, Crypter, Mode};
52
53#[cfg(feature = "write")]
54use openssl::symm::encrypt;
55
56use ring::digest::{Context, SHA256, SHA512};
57use ring::hmac;
58use sxd_document::parser;
59use sxd_xpath::{evaluate_xpath, Context as XPathContext, Factory, Value};
60
61use xml::attribute::OwnedAttribute;
62use xml::name::OwnedName;
63use xml::reader::{EventReader, ParserConfig, XmlEvent};
64use xml::writer::EventWriter;
65use derive_getters::Getters;
66
67use keepass_db_derive::{KdbxParse, KdbxSerialize};
68
69mod kdb1;
70mod utils;
71pub mod protected_stream;
72
73
74trait KdbxParse<C>: Sized + Default {
82 fn parse<R: Read>(
88 reader: &mut EventReader<R>,
89 name: OwnedName,
90 attributes: Vec<OwnedAttribute>,
91 context: &mut C,
92 ) -> Result<Option<Self>, String>;
93}
94
95trait KdbxSerialize<C>: Sized {
100 fn serialize2<W: Write>(
101 writer: &mut EventWriter<W>,
102 value: Self,
103 context: &mut C,
104 ) -> Result<(), String>;
105}
106
107#[cfg(test)]
108mod tests;
109
110#[derive(FromPrimitive, ToPrimitive)]
111enum Compression {
112 None = 0,
113 Gzip = 1,
114}
115
116#[derive(FromPrimitive, ToPrimitive)]
117enum TlvType {
118 End = 0,
119 Comment = 1,
120 CipherId = 2,
121 CompressionFlags = 3,
122 MasterSeed = 4,
123 TransformSeed = 5,
124 TransformRounds = 6,
125 EncryptionIv = 7,
126 ProtectedStreamKey = 8,
127 StreamStartBytes = 9,
128 InnerRandomStreamId = 10,
129 KdfParameters = 11,
130 PublicCustomData = 12,
131}
132
133fn load_tlvs<R: Read>(
141 input: &mut R,
142 major_version: u16,
143) -> io::Result<(BTreeMap<u8, Vec<Vec<u8>>>, Vec<u8>)> {
144 let mut tlvs = BTreeMap::new();
146 let mut header_blob = Vec::new();
147 loop {
148 let mut tlv_header = if major_version == 3 {
149 vec![0; 3]
150 } else {
151 vec![0; 5]
152 };
153 input.read_exact(&mut tlv_header)?;
154 header_blob.extend(&tlv_header);
155 let mut header_cursor = Cursor::new(tlv_header);
156 let tlv_type = header_cursor.read_u8()?;
157 let tlv_len = if major_version <= 3 {
158 header_cursor.read_u16::<LittleEndian>()? as u32
159 } else {
160 header_cursor.read_u32::<LittleEndian>()?
161 };
162 let mut tlv_data = vec![0; tlv_len as usize];
163 input.read_exact(&mut tlv_data)?;
164 header_blob.extend(&tlv_data);
165 debug!("TLV({}, {}): {:?}", tlv_type, tlv_len, &tlv_data);
166 if tlv_type == 0 {
167 break;
168 }
169 let values = match tlvs.get_mut(&tlv_type) {
170 Some(v) => v,
171 None => {
172 let v = Vec::new();
173 tlvs.insert(tlv_type, v);
174 tlvs.get_mut(&tlv_type).unwrap()
175 }
176 };
177 values.push(tlv_data);
178 }
179 Ok((tlvs, header_blob))
180}
181
182#[cfg(feature = "write")]
183fn save_tlvs<W: Write>(
184 output: &mut W,
185 tlvs: &BTreeMap<u8, Vec<Vec<u8>>>,
186 major_version: u16,
187) -> io::Result<Vec<u8>> {
188 let mut buf = Cursor::new(Vec::new());
189 let term = HashMap::from([(0, vec![vec![]])]);
190 for (key, values) in tlvs.iter().chain(term.iter()) {
191 for value in values {
192 buf.write_u8(*key)?;
193 if major_version <= 3 {
195 buf.write_u16::<LittleEndian>(value.len() as u16)?;
196 } else {
197 buf.write_u32::<LittleEndian>(value.len() as u32)?;
198 }
199 buf.write(value)?;
200 }
201 }
202 let bytes = buf.into_inner();
203 output.write(&bytes)?;
204 Ok(bytes)
205}
206#[derive(PartialEq, Eq, FromPrimitive, ToPrimitive)]
209enum MapType {
210 None = 0,
211 UInt32 = 0x04,
214 UInt64 = 0x05,
215 Bool = 0x08,
216 Int32 = 0x0C,
219 Int64 = 0x0D,
220 String = 0x18,
225 ByteArray = 0x42,
226}
227
228#[derive(PartialEq, Eq, Debug)]
229pub enum MapValue {
230 UInt32(u32),
231 UInt64(u64),
232 Bool(bool),
233 Int32(i32),
234 Int64(i64),
235 String(String),
236 ByteArray(Vec<u8>),
237}
238
239impl From<&MapValue> for MapType {
240 fn from(value: &MapValue) -> Self {
241 match value {
242 MapValue::Bool(_) => MapType::Bool,
243 MapValue::Int32(_) => MapType::Int32,
244 MapValue::Int64(_) => MapType::Int64,
245 MapValue::UInt32(_) => MapType::UInt32,
246 MapValue::UInt64(_) => MapType::UInt64,
247 MapValue::String(_) => MapType::String,
248 MapValue::ByteArray(_) => MapType::ByteArray,
249 }
250 }
251}
252
253fn load_map(tlv_data: &[u8]) -> io::Result<HashMap<String, MapValue>> {
254 let mut custom_data = HashMap::new();
255 let kdf_parameters = &tlv_data;
256 let mut c = Cursor::new(kdf_parameters);
257 let variant_minor = c.read_u8()?;
258 let variant_major = c.read_u8()?;
259 if variant_major != 1 {
260 let _ = eprintln!(
261 "Unsupported variant dictionary version ({}.{})\n",
262 variant_major, variant_minor
263 );
264 return Err(io::Error::new(io::ErrorKind::Other, "Unsupported variant"));
265 };
266
267 loop {
268 let item_type = MapType::from_u8(c.read_u8()?)
269 .ok_or(io::Error::new(io::ErrorKind::Other, "Unknown type"))?;
270 if item_type == MapType::None {
271 break;
272 }
273 let item_key_len = c.read_u32::<LittleEndian>()?;
274 let mut item_key = vec![0; item_key_len as usize];
275 c.read_exact(&mut item_key)?;
276 let item_key_str = String::from_utf8_lossy(&item_key).to_owned();
277 let item_value_len = c.read_u32::<LittleEndian>()?;
278 let mut item_value = vec![0; item_value_len as usize];
279 c.read_exact(&mut item_value)?;
280 debug!("K: {}, V: {:0x?}", item_key_str, item_value);
281 let item_value = match item_type {
282 MapType::Bool => {
283 if item_value.len() != 1 {
284 return Err(io::Error::new(
285 io::ErrorKind::Unsupported,
286 "Invalid bool value",
287 ));
288 }
289 MapValue::Bool(item_value[0] != 0)
290 }
291 MapType::Int32 => {
292 MapValue::Int32(i32::from_le_bytes(item_value.try_into().map_err(|_| {
293 io::Error::new(io::ErrorKind::Unsupported, "Invalid i32 value")
294 })?))
295 }
296 MapType::Int64 => {
297 MapValue::Int64(i64::from_le_bytes(item_value.try_into().map_err(|_| {
298 io::Error::new(io::ErrorKind::Unsupported, "Invalid i64 value")
299 })?))
300 }
301 MapType::UInt32 => {
302 MapValue::UInt32(u32::from_le_bytes(item_value.try_into().map_err(|_| {
303 io::Error::new(io::ErrorKind::Unsupported, "Invalid u32 value")
304 })?))
305 }
306 MapType::UInt64 => {
307 MapValue::UInt64(u64::from_le_bytes(item_value.try_into().map_err(|_| {
308 io::Error::new(io::ErrorKind::Unsupported, "Invalid u64 value")
309 })?))
310 }
311 MapType::String => {
312 MapValue::String(String::from_utf8(item_value).map_err(|_| {
313 io::Error::new(io::ErrorKind::Unsupported, "Invalid string value")
314 })?)
315 }
316 MapType::ByteArray => MapValue::ByteArray(item_value),
317 MapType::None => {
318 unreachable!()
319 }
320 };
321 custom_data.insert(item_key_str.to_owned().to_string(), item_value);
322 }
323 Ok(custom_data)
324}
325
326#[cfg(feature = "write")]
327fn save_map(map: &HashMap<String, MapValue>) -> Vec<u8> {
328 let variant_major = 1;
329 let variant_minor = 0;
330 let mut output = Cursor::new(Vec::new());
331 output.write_u8(variant_minor).unwrap();
332 output.write_u8(variant_major).unwrap();
333 for (k, v) in map {
334 output.write_u8(MapType::from(v).to_u8().unwrap()).unwrap();
335 output.write_u32::<LittleEndian>(k.len() as u32).unwrap();
336 output.write(k.as_bytes()).unwrap();
337 let item_value = match v {
338 MapValue::Bool(v) => {
339 vec![if *v { 1 } else { 0 }]
340 }
341 MapValue::Int32(v) => v.to_le_bytes().to_vec(),
342 MapValue::Int64(v) => v.to_le_bytes().to_vec(),
343 MapValue::UInt32(v) => v.to_le_bytes().to_vec(),
344 MapValue::UInt64(v) => v.to_le_bytes().to_vec(),
345 MapValue::String(v) => v.as_bytes().to_vec(),
346 MapValue::ByteArray(v) => v.clone(),
347 };
348 output
349 .write_u32::<LittleEndian>(item_value.len() as u32)
350 .unwrap();
351 output.write(&item_value).unwrap();
352 }
353 output.write_u8(0).unwrap(); output.into_inner()
355}
356
357struct BlockReader<R: Read> {
358 index: u64,
359 hmac_key_base: Vec<u8>,
361 output: R,
362 buf: VecDeque<u8>,
363 complete: bool,
364}
365
366impl<R: Read> BlockReader<R> {
367 fn new(key: &[u8], output: R) -> Self {
370 Self {
371 index: 0,
372 hmac_key_base: key.to_owned(),
374 output,
375 buf: VecDeque::new(),
377 complete: false,
378 }
379 }
380
381 fn load_next_block(&mut self) -> io::Result<()> {
382 println!("Block {}", self.index);
383 let mut hmac_tag: [u8; 32] = [0; 32];
384 self.output.read_exact(&mut hmac_tag)?;
386 let block_size = self.output.read_u32::<LittleEndian>()?;
445 if block_size == 0 {
446 self.complete = true;
447 return Ok(());
448 }
449 let mut block = vec![0; block_size as usize];
450 self.output.read_exact(&mut block)?;
451
452 let mut hmac_context = Context::new(&SHA512);
453 let mut buf = Cursor::new(Vec::new());
454 buf.write_u64::<LittleEndian>(self.index)?;
455 self.index += 1;
456 hmac_context.update(buf.get_ref());
457 hmac_context.update(&self.hmac_key_base);
458 let hmac_key = hmac_context.finish().as_ref().to_owned();
459 buf.write_u32::<LittleEndian>(block_size)?;
460 buf.write(&block)?;
461 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &hmac_key);
462 println!("Verifying HMAC");
463 hmac::verify(&hmac_key, buf.get_ref(), &hmac_tag).unwrap();
464 println!("Complete");
465 self.buf = block.into();
466 Ok(())
467 }
468}
469
470impl<R: Read> Read for BlockReader<R> {
471 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
472 if self.complete {
473 return Ok(0);
474 } else if self.buf.len() == 0 {
475 self.load_next_block()?;
476 }
477 let mut index = 0;
478 if index >= buf.len() {
479 return Ok(index);
480 }
481 while let Some(val) = self.buf.pop_front() {
482 buf[index] = val;
483 index += 1;
484 if index >= buf.len() {
485 return Ok(index);
486 }
487 }
488 Ok(index)
489 }
490}
491
492struct BlockWriter<W: Write> {
493 index: u64,
494 block_size: u32,
495 hmac_key_base: Vec<u8>,
496 output: W,
497 buf: Vec<u8>,
498}
499
500impl<W: Write> BlockWriter<W> {
501 const DEFAULT_BLOCK_SIZE: u32 = 1024 * 1024;
502
503 fn new(key: &[u8], output: W) -> Self {
504 Self {
505 index: 0,
506 block_size: Self::DEFAULT_BLOCK_SIZE,
507 hmac_key_base: key.to_owned(),
508 output,
509 buf: Vec::new(),
511 }
512 }
513}
514
515impl<W: Write> Write for BlockWriter<W> {
516 fn flush(&mut self) -> io::Result<()> {
517 let mut hmac_context = Context::new(&SHA512);
518 let mut key_buf = Cursor::new(Vec::new());
519 key_buf.write_u64::<LittleEndian>(self.index)?;
520 self.index += 1;
521 hmac_context.update(key_buf.get_ref());
522 hmac_context.update(&self.hmac_key_base);
523 let hmac_key = hmac_context.finish().as_ref().to_owned();
524 key_buf.write_u32::<LittleEndian>(self.buf.len() as u32)?;
525 key_buf.write(&self.buf)?;
526 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &hmac_key);
527 let hmac_tag = hmac::sign(&hmac_key, key_buf.get_ref());
529 self.output.write(hmac_tag.as_ref())?;
531 self.output
532 .write_u32::<LittleEndian>(self.buf.len() as u32)?;
533 self.output.write(&self.buf)?;
534 self.buf.truncate(0);
535 Ok(())
536 }
537
538 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
539 let remaining = cmp::min(
540 self.block_size as usize - cmp::min(self.buf.len(), self.block_size as usize),
541 buf.len(),
542 );
543 self.buf.extend(&buf[..remaining]);
544 if self.buf.len() >= self.block_size as usize {
545 self.flush()?;
546 }
547 Ok(remaining)
548 }
562}
563
564#[derive(Debug)]
565struct CryptoError {
566 _error: ErrorStack,
567}
568
569impl From<ErrorStack> for CryptoError {
570 fn from(error: ErrorStack) -> Self {
571 Self { _error: error }
572 }
573}
574
575struct Crypto<W: Write> {
576 crypter: Crypter,
577 output: W,
578 buf: Vec<u8>,
579 block_size: usize,
580}
581
582impl<W: Write> Crypto<W> {
583 fn new(cipher: Cipher, key: &[u8], iv: Option<&[u8]>, output: W) -> Result<Self, CryptoError> {
584 Ok(Self {
585 crypter: Crypter::new(cipher, Mode::Encrypt, key, iv)?,
586 output,
587 buf: Vec::new(),
588 block_size: cipher.block_size(),
589 })
590 }
591}
592
593impl<W: Write> Drop for Crypto<W> {
594 fn drop(&mut self) {
595 self.output.flush().unwrap();
596 }
604}
605
606impl<W: Write> Write for Crypto<W> {
607 fn flush(&mut self) -> io::Result<()> {
608 self.buf = vec![0; self.block_size];
609 let rest = self
610 .crypter
611 .finalize(&mut self.buf)
612 .expect("Failed to finalize encryption");
613 self.output
614 .write_all(&self.buf[..rest])
615 .expect("Failed to flush");
616 self.buf = vec![];
617 self.output.flush()?;
618 Ok(())
620 }
621
622 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
623 self.buf.resize(data.len() + self.block_size, 0);
624 let count = self.crypter.update(data, &mut self.buf)?;
625 self.output.write_all(&self.buf[..count])?;
626 self.buf = self.buf[count..].to_vec();
627 Ok(data.len())
628 }
629}
630
631struct CryptoReader<R: Read> {
632 crypter: Crypter,
633 output: R,
634 buf: Vec<u8>,
635 block_size: usize,
636}
637
638impl<R: Read> CryptoReader<R> {
639 fn new(cipher: Cipher, key: &[u8], iv: Option<&[u8]>, output: R) -> Result<Self, CryptoError> {
640 Ok(Self {
641 crypter: Crypter::new(cipher, Mode::Decrypt, key, iv)?,
642 output,
643 buf: Vec::new(),
644 block_size: cipher.block_size(),
645 })
646 }
647}
648
649mod key;
667mod kdf;
668pub use kdf::*;
669pub use key::Key;
670
671pub const KDF_AES_KDBX3: Uuid = uuid!("c9d9f39a-628a-4460-bf74-0d08c18a4fea");
672const KDF_AES_KDBX4: Uuid = uuid!("7c02bb82-79a7-4ac0-927d-114a00648238");
673const KDF_ARGON2_D: Uuid = uuid!("ef636ddf-8c29-444b-91f7-a9a403e30a0c");
674const _KDF_ARGON2_ID: Uuid = uuid!("9e298b19-56db-4773-b23d-fc3ec6f0a1e6");
675
676const _CIPHER_ID_AES128_CBC: Uuid = uuid!("61ab05a1-9464-41c3-8d74-3a563df8dd35");
677const CIPHER_ID_AES256_CBC: Uuid = uuid!("31c1f2e6-bf71-4350-be58-05216afc5aff");
678const _CIPHER_ID_TWOFISH_CBC: Uuid = uuid!("ad68f29f-576f-4bb9-a36a-d47af965346c");
679const _CIPHER_ID_CHACHA20: Uuid = uuid!("d6038a2b-8b6f-4cb5-a524-339a31dbb59a");
680
681fn consume_element<R: Read>(
682 reader: &mut EventReader<R>,
683 name: OwnedName,
684 _attributes: Vec<OwnedAttribute>,
685) -> Result<Option<String>, String> {
686 let mut elements = vec![];
687 println!("A tag: {}", &name);
688 elements.push(name);
689
690 let mut string = None;
691
692 let mut event = reader
693 .next()
694 .map_err(|_| "Failed to retrieve next XML event")?;
695 loop {
696 match event {
697 XmlEvent::StartDocument { .. } => {
698 return Err("Malformed XML document, start of document".to_string());
699 }
700 XmlEvent::EndDocument { .. } => {
701 return Err("Malformed XML document, end of document".to_string());
702 }
703 XmlEvent::StartElement { name, .. } => {
704 elements.push(name);
705 }
706 XmlEvent::Characters(k) => {
707 string = Some(k);
708 }
709 XmlEvent::EndElement { name, .. } => {
710 let start_tag = elements.pop().expect("Can't consume a bare end element");
711 if start_tag != name {
712 return Err(format!(
713 "Start tag <{}> mismatches end tag </{}>",
714 start_tag, name
715 ));
716 }
717 }
718 _ => {
719 }
722 };
723 if elements.len() == 0 {
724 return Ok(string);
725 }
726 event = reader
727 .next()
728 .map_err(|_| "Failed to retrieve next XML event")?;
729 }
730}
731
732pub enum ElementEvent {
733 StartElement {
734 name: OwnedName,
735 attributes: Vec<OwnedAttribute>,
736 },
737 EndElement {
738 name: OwnedName,
739 },
740}
741
742fn find_next_element<R: Read>(reader: &mut EventReader<R>) -> Result<ElementEvent, String> {
743 loop {
744 match reader
745 .next()
746 .map_err(|_| "Failed to retrieve next XML event")?
747 {
748 XmlEvent::StartDocument { .. } => {
749 return Err("Malformed XML document".to_string());
750 }
751 XmlEvent::EndDocument { .. } => {
752 return Err("Malformed XML document".to_string());
753 }
754 XmlEvent::StartElement {
755 name, attributes, ..
756 } => {
757 return Ok(ElementEvent::StartElement { name, attributes });
758 }
759 XmlEvent::Characters(_) => {}
760 XmlEvent::CData(_) => {}
761 XmlEvent::Whitespace(_) => {}
762 XmlEvent::ProcessingInstruction { .. } => {}
763 XmlEvent::EndElement { name, .. } => {
764 return Ok(ElementEvent::EndElement { name });
765 }
766 _ => {
767 }
770 };
771 }
772}
773
774fn decode_optional_string<R: Read>(
775 reader: &mut EventReader<R>,
776 name: OwnedName,
777 _attributes: Vec<OwnedAttribute>,
778) -> Result<Option<String>, String> {
779 let mut elements = vec![];
780 elements.push(name);
781
782 let mut string = String::new();
783
784 let mut event = reader
785 .next()
786 .map_err(|_| "Failed to retrieve next XML event")?;
787 loop {
788 match event {
789 XmlEvent::StartDocument { .. } => {
790 return Err("Malformed XML document".to_string());
791 }
792 XmlEvent::EndDocument { .. } => {
793 return Err("Malformed XML document".to_string());
794 }
795 XmlEvent::StartElement { name, .. } => {
796 elements.push(name);
797 }
798 XmlEvent::Characters(k) => {
799 if elements.len() == 1 {
800 string.push_str(&k);
801 }
802 }
803 XmlEvent::Whitespace(k) => {
804 if elements.len() == 1 {
805 string.push_str(&k);
806 }
807 }
808 XmlEvent::CData(k) => {
809 if elements.len() == 1 {
810 string.push_str(&k);
811 }
812 }
813 XmlEvent::EndElement { name, .. } => {
814 let start_tag = elements.pop().expect("Can't consume a bare end element");
815 if start_tag != name {
816 return Err(format!(
817 "Start tag <{}> mismatches end tag </{}>",
818 start_tag, name
819 ));
820 }
821 }
822 _ => {
823 }
826 };
827 if elements.len() == 0 {
828 if string.len() == 0 {
829 return Ok(None);
830 } else {
831 return Ok(Some(string));
832 }
833 }
834 event = reader.next().map_err(|_| "")?;
835 }
836}
837
838fn encode_optional_string<W: Write>(
839 writer: &mut EventWriter<W>,
840 value: Option<&str>,
841) -> Result<(), String> {
842 if let Some(contents) = value {
843 writer
844 .write(xml::writer::XmlEvent::characters(contents))
845 .map_err(|_| "".to_string())
846 } else {
847 Ok(())
848 }
849}
850
851fn decode_string<R: Read>(
852 reader: &mut EventReader<R>,
853 name: OwnedName,
854 attributes: Vec<OwnedAttribute>,
855) -> Result<String, String> {
856 decode_optional_string(reader, name, attributes).map(|x| x.unwrap_or_else(|| "".into()))
857}
858
859impl<C> KdbxParse<C> for String {
860 fn parse<R: Read>(
861 reader: &mut EventReader<R>,
862 name: OwnedName,
863 attributes: Vec<OwnedAttribute>,
864 _context: &mut C,
865 ) -> Result<Option<Self>, String> {
866 decode_optional_string(reader, name, attributes)
867 }
868}
869
870fn encode_string<W: Write>(writer: &mut EventWriter<W>, value: &str) -> Result<(), String> {
871 encode_optional_string(writer, Some(value))
872}
873
874impl<C> KdbxSerialize<C> for String {
875 fn serialize2<W: Write>(
876 writer: &mut EventWriter<W>,
877 value: Self,
878 _context: &mut C,
879 ) -> Result<(), String> {
880 encode_string(writer, &value)
881 }
882}
883
884fn decode_optional_base64<R: Read>(
885 reader: &mut EventReader<R>,
886 name: OwnedName,
887 attributes: Vec<OwnedAttribute>,
888) -> Result<Option<Vec<u8>>, String> {
889 Ok(decode_optional_string(reader, name, attributes)?
890 .map(|x| base64.decode(&x).unwrap() ))
891}
892
893fn encode_optional_base64<W: Write, T: AsRef<[u8]>>(
894 writer: &mut EventWriter<W>,
895 value: Option<T>,
896) -> Result<(), String> {
897 encode_optional_string(writer, value.map(|x| base64.encode(x.as_ref())).as_deref())
900}
901
902fn decode_base64<R: Read>(
903 reader: &mut EventReader<R>,
904 name: OwnedName,
905 attributes: Vec<OwnedAttribute>,
906) -> Result<Vec<u8>, String> {
907 Ok(decode_optional_base64(reader, name, attributes)?.unwrap_or_default())
908}
909
910fn encode_base64<W: Write, T: AsRef<[u8]>>(
911 writer: &mut EventWriter<W>,
912 value: T,
913) -> Result<(), String> {
914 encode_optional_base64(writer, Some(value))
915}
916
917fn decode_optional_bool<R: Read>(
918 reader: &mut EventReader<R>,
919 name: OwnedName,
920 attributes: Vec<OwnedAttribute>,
921) -> Result<Option<bool>, String> {
922 decode_optional_string(reader, name, attributes)
923 .map(|x| x.map(|y| y.eq_ignore_ascii_case("true")))
924}
925
926fn encode_optional_bool<W: Write>(
927 writer: &mut EventWriter<W>,
928 value: Option<bool>,
929) -> Result<(), String> {
930 encode_optional_string(writer, value.map(|x| if x { "True" } else { "False" }))
931}
932
933impl<C> KdbxParse<C> for bool {
942 fn parse<R: Read>(
943 reader: &mut EventReader<R>,
944 name: OwnedName,
945 attributes: Vec<OwnedAttribute>,
946 _context: &mut C,
947 ) -> Result<Option<Self>, String> {
948 decode_optional_bool(reader, name, attributes)
949 }
950}
951
952fn encode_bool<W: Write>(writer: &mut EventWriter<W>, value: bool) -> Result<(), String> {
953 encode_optional_bool(writer, Some(value))
954}
955
956impl<C> KdbxSerialize<C> for bool {
957 fn serialize2<W: Write>(
958 writer: &mut EventWriter<W>,
959 value: Self,
960 _context: &mut C,
961 ) -> Result<(), String> {
962 encode_bool(writer, value)
963 }
964}
965
966fn decode_optional_i64<R: Read>(
967 reader: &mut EventReader<R>,
968 name: OwnedName,
969 attributes: Vec<OwnedAttribute>,
970) -> Result<Option<i64>, String> {
971 decode_optional_string(reader, name, attributes).map(|x| x.map(|y| y.parse().unwrap_or(0)))
972}
973
974fn encode_optional_i64<W: Write>(
975 writer: &mut EventWriter<W>,
976 value: Option<i64>,
977) -> Result<(), String> {
978 encode_optional_string(writer, value.map(|x| format!("{}", x)).as_deref())
979}
980
981fn decode_i64<R: Read>(
982 reader: &mut EventReader<R>,
983 name: OwnedName,
984 attributes: Vec<OwnedAttribute>,
985) -> Result<i64, String> {
986 decode_optional_i64(reader, name, attributes).map(|x| x.unwrap_or(0))
987}
988
989impl<C> KdbxParse<C> for i64 {
990 fn parse<R: Read>(
991 reader: &mut EventReader<R>,
992 name: OwnedName,
993 attributes: Vec<OwnedAttribute>,
994 _context: &mut C,
995 ) -> Result<Option<Self>, String> {
996 Ok(Some(decode_i64(reader, name, attributes)?))
997 }
998}
999
1000fn encode_i64<W: Write>(writer: &mut EventWriter<W>, value: i64) -> Result<(), String> {
1001 encode_optional_i64(writer, Some(value))
1002}
1003
1004impl<C> KdbxSerialize<C> for i64 {
1005 fn serialize2<W: Write>(
1006 writer: &mut EventWriter<W>,
1007 value: Self,
1008 _context: &mut C,
1009 ) -> Result<(), String> {
1010 encode_i64(writer, value)
1011 }
1012}
1013
1014impl<C> KdbxParse<C> for i32 {
1015 fn parse<R: Read>(
1016 reader: &mut EventReader<R>,
1017 name: OwnedName,
1018 attributes: Vec<OwnedAttribute>,
1019 _context: &mut C,
1020 ) -> Result<Option<Self>, String> {
1021 Ok(Some(decode_i64(reader, name, attributes)? as i32))
1023 }
1024}
1025
1026impl<C> KdbxSerialize<C> for i32 {
1027 fn serialize2<W: Write>(
1028 writer: &mut EventWriter<W>,
1029 value: Self,
1030 _context: &mut C,
1031 ) -> Result<(), String> {
1032 encode_i64(writer, value as i64)
1033 }
1034}
1035
1036impl<C> KdbxParse<C> for u32 {
1037 fn parse<R: Read>(
1038 reader: &mut EventReader<R>,
1039 name: OwnedName,
1040 attributes: Vec<OwnedAttribute>,
1041 _context: &mut C,
1042 ) -> Result<Option<Self>, String> {
1043 Ok(Some(decode_i64(reader, name, attributes)? as u32))
1044 }
1045}
1046
1047impl<C> KdbxSerialize<C> for u32 {
1048 fn serialize2<W: Write>(
1049 writer: &mut EventWriter<W>,
1050 value: Self,
1051 _context: &mut C,
1052 ) -> Result<(), String> {
1053 encode_i64(writer, value as i64)
1054 }
1055}
1056
1057static mut KDBX4: bool = true;
1058const KDBX4_TIME_OFFSET: i64 = 62135596800;
1059fn decode_optional_datetime<R: Read>(
1060 reader: &mut EventReader<R>,
1061 name: OwnedName,
1062 attributes: Vec<OwnedAttribute>,
1063) -> Result<Option<DateTime<Utc>>, String> {
1064 let is_new = unsafe { KDBX4 };
1065 if is_new {
1066 decode_optional_string(reader, name, attributes).map(|x| {
1067 x.map(|y| {
1068 Utc.timestamp_opt(
1069 Cursor::new(base64.decode(&y).expect("Valid base64"))
1070 .read_i64::<LittleEndian>()
1071 .unwrap()
1072 - KDBX4_TIME_OFFSET,
1073 0,
1074 ).unwrap()
1075 })
1076 })
1077 } else {
1078 decode_optional_string(reader, name, attributes).map(|x| {
1079 x.map(|y| {
1080 if let Some(suffix) = y.chars().last() {
1081 if suffix.to_ascii_uppercase() == 'Z' {
1082 DateTime::parse_from_rfc3339(&y)
1083 .expect(&format!("failed to parse timestamp: {}", y))
1084 .with_timezone(&Utc)
1085 } else {
1086 NaiveDateTime::parse_from_str(&y, "%Y-%m-%dT%H:%M:%S").expect("invalid local date").and_local_timezone(Local).earliest().unwrap()
1087 .with_timezone(&Utc)
1088 }
1089 } else {
1090 unreachable!("This shouldn't be possible");
1091 }
1092 })
1093 })
1094 }
1095}
1096
1097fn encode_optional_datetime<W: Write>(
1098 writer: &mut EventWriter<W>,
1099 value: Option<DateTime<Utc>>,
1100) -> Result<(), String> {
1101 encode_optional_string(
1102 writer,
1103 value
1104 .map(|x| base64.encode(&(x.timestamp() + KDBX4_TIME_OFFSET).to_le_bytes()))
1105 .as_deref(),
1106 )
1107}
1108
1109struct KdbxContext {
1124 major_version: u16,
1125 inner_cipher_position: usize,
1126 binaries: Vec<Vec<u8>>,
1127}
1128
1129impl Default for KdbxContext {
1130 fn default() -> Self {
1131 KdbxContext {
1132 major_version: 4,
1133 inner_cipher_position: 0,
1134 binaries: vec![],
1135 }
1136 }
1137}
1138
1139impl KdbxParse<KdbxContext> for DateTime<Utc> {
1140 fn parse<R: Read>(
1141 reader: &mut EventReader<R>,
1142 name: OwnedName,
1143 attributes: Vec<OwnedAttribute>,
1144 context: &mut KdbxContext,
1145 ) -> Result<Option<Self>, String> {
1146 unsafe {
1147 KDBX4 = context.major_version >= 4;
1148 };
1149 decode_optional_datetime(reader, name, attributes)
1150 }
1151}
1152
1153fn encode_datetime<W: Write>(
1154 writer: &mut EventWriter<W>,
1155 value: DateTime<Utc>,
1156) -> Result<(), String> {
1157 encode_optional_datetime(writer, Some(value))
1158}
1159
1160impl KdbxSerialize<KdbxContext> for DateTime<Utc> {
1161 fn serialize2<W: Write>(
1162 writer: &mut EventWriter<W>,
1163 value: Self,
1164 context: &mut KdbxContext,
1165 ) -> Result<(), String> {
1166 if context.major_version >= 4 {
1167 encode_datetime(writer, value)
1168 } else {
1169 encode_string(writer, value.format("%FT%TZ").to_string().as_str())
1170 }
1171 }
1172}
1173
1174fn decode_optional_uuid<R: Read>(
1179 reader: &mut EventReader<R>,
1180 name: OwnedName,
1181 attributes: Vec<OwnedAttribute>,
1182) -> Result<Option<Uuid>, String> {
1183 decode_optional_string(reader, name, attributes)
1184 .map(|x| x.map(|y| Uuid::from_slice(&base64.decode(&y).expect("Valid base64")).unwrap()))
1185}
1186
1187fn encode_optional_uuid<W: Write>(
1188 writer: &mut EventWriter<W>,
1189 value: Option<Uuid>,
1190) -> Result<(), String> {
1191 encode_optional_string(writer, value.map(|x| base64.encode(x.as_ref())).as_deref())
1192}
1193
1194fn encode_uuid<W: Write>(writer: &mut EventWriter<W>, value: Uuid) -> Result<(), String> {
1203 encode_optional_uuid(writer, Some(value))
1204}
1205
1206impl<C> KdbxParse<C> for Uuid {
1207 fn parse<R: Read>(
1208 reader: &mut EventReader<R>,
1209 name: OwnedName,
1210 attributes: Vec<OwnedAttribute>,
1211 _context: &mut C,
1212 ) -> Result<Option<Self>, String> {
1213 decode_optional_uuid(reader, name, attributes)
1214 }
1215}
1216
1217impl<C> KdbxSerialize<C> for Uuid {
1218 fn serialize2<W: Write>(
1219 writer: &mut EventWriter<W>,
1220 value: Self,
1221 _context: &mut C,
1222 ) -> Result<(), String> {
1223 encode_uuid(writer, value)
1224 }
1225}
1226
1227fn decode_item<R: Read>(
1228 reader: &mut EventReader<R>,
1229 _name: OwnedName,
1230 _attributes: Vec<OwnedAttribute>,
1231) -> Result<(String, String), String> {
1232 let mut key = String::new();
1233 let mut value = String::new();
1234
1235 loop {
1236 match find_next_element(reader)? {
1237 ElementEvent::StartElement { name, .. } if name.local_name == "Key" => {
1238 key = decode_string(reader, name, vec![])?;
1239 }
1240 ElementEvent::StartElement { name, .. } if name.local_name == "Value" => {
1241 value = decode_string(reader, name, vec![])?;
1242 }
1243 ElementEvent::StartElement { name, .. } => {
1244 consume_element(reader, name, vec![])?;
1245 }
1246 ElementEvent::EndElement { name, .. } if name.local_name == "Item" => {
1247 return Ok((key, value));
1248 }
1249 ElementEvent::EndElement { .. } => {
1250 return Err("Wrong ending".to_string());
1251 }
1252 }
1253 }
1254}
1255
1256fn encode_item<W: Write>(writer: &mut EventWriter<W>, value: (&str, &str)) -> Result<(), String> {
1257 writer
1258 .write(xml::writer::XmlEvent::start_element("Item"))
1259 .map_err(|_| "")?;
1260 writer
1261 .write(xml::writer::XmlEvent::start_element("Key"))
1262 .map_err(|_| "")?;
1263 encode_string(writer, value.0)?;
1264 writer
1265 .write(xml::writer::XmlEvent::end_element())
1266 .map_err(|_| "")?;
1267 writer
1268 .write(xml::writer::XmlEvent::start_element("Value"))
1269 .map_err(|_| "")?;
1270 encode_string(writer, value.1)?;
1271 writer
1272 .write(xml::writer::XmlEvent::end_element())
1273 .map_err(|_| "")?;
1274 writer
1275 .write(xml::writer::XmlEvent::end_element())
1276 .map_err(|_| "")?;
1277 Ok(())
1278}
1279
1280fn decode_custom_data<R: Read>(
1281 reader: &mut EventReader<R>,
1282 pname: OwnedName,
1283 _attributes: Vec<OwnedAttribute>,
1284) -> Result<HashMap<String, String>, String> {
1285 let mut data = HashMap::new();
1289
1290 loop {
1291 match find_next_element(reader)? {
1292 ElementEvent::StartElement { name, .. } if name.local_name == "Item" => {
1293 let (key, value) = decode_item(reader, name, vec![])?;
1294 data.insert(key, value);
1296 }
1297 ElementEvent::StartElement { name, .. } => {
1298 consume_element(reader, name, vec![])?;
1299 }
1300 ElementEvent::EndElement { name, .. } if name == pname => {
1301 return Ok(data);
1302 }
1303 ElementEvent::EndElement { .. } => {
1304 return Err("Wrong ending".to_string());
1305 }
1306 }
1307 }
1308}
1309
1310fn encode_custom_data<W: Write>(
1311 writer: &mut EventWriter<W>,
1312 map: HashMap<String, String>,
1313) -> Result<(), String> {
1314 for (key, value) in map.iter() {
1315 encode_item(writer, (key, value))?;
1316 }
1317 Ok(())
1318}
1319
1320#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1321struct MemoryProtection {
1322 protect_title: bool,
1323 protect_user_name: bool,
1324 protect_password: bool,
1325 #[keepass_db(element = "ProtectURL")]
1326 protect_url: bool,
1327 protect_notes: bool,
1328}
1329
1330#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1331struct Icon {
1332 #[keepass_db(element = "UUID")]
1333 uuid: Uuid,
1334 last_modification_time: Option<DateTime<Utc>>,
1335 data: Vec<u8>,
1336}
1337
1338#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1339#[cfg_attr(test, derive(PartialEq))]
1340pub struct Item {
1341 key: String,
1342 value: String,
1343 last_modification_time: Option<DateTime<Utc>>,
1345}
1346
1347#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1348struct Meta {
1349 generator: String,
1350 header_hash: Option<[u8; 32]>,
1351 settings_changed: Option<DateTime<Utc>>,
1352 database_name: String,
1353 database_name_changed: Option<DateTime<Utc>>,
1354 database_description: String,
1355 database_description_changed: Option<DateTime<Utc>>,
1356 default_user_name: String,
1357 default_user_name_changed: Option<DateTime<Utc>>,
1358 maintenance_history_days: u32,
1359 color: String,
1360 master_key_changed: Option<DateTime<Utc>>,
1361 master_key_change_rec: i64,
1362 master_key_change_force: i64,
1363 master_key_change_force_once: bool,
1364 memory_protection: MemoryProtection,
1365 custom_icons: Vec<Icon>,
1366 recycle_bin_enabled: bool,
1367 #[keepass_db(element = "RecycleBinUUID")]
1368 recycle_bin_uuid: Option<Uuid>,
1369 recycle_bin_changed: DateTime<Utc>,
1370 entry_templates_group: Uuid, entry_templates_group_changed: DateTime<Utc>,
1372 history_max_items: i32, history_max_size: i64, last_selected_group: Uuid, last_top_visible_group: Uuid, custom_data: Vec<Item>,
1378}
1379
1380impl<C> KdbxParse<C> for [u8; 32] {
1381 fn parse<R: Read>(
1382 reader: &mut EventReader<R>,
1383 name: OwnedName,
1384 attributes: Vec<OwnedAttribute>,
1385 _context: &mut C,
1386 ) -> Result<Option<Self>, String> {
1387 Ok(Some(
1390 decode_base64(reader, name, attributes)?
1391 .try_into()
1392 .map_err(|_| "")?,
1393 ))
1394 }
1395}
1396
1397impl<C> KdbxSerialize<C> for [u8; 32] {
1398 fn serialize2<W: Write>(
1399 writer: &mut EventWriter<W>,
1400 value: Self,
1401 _context: &mut C,
1402 ) -> Result<(), String> {
1403 encode_base64(writer, value)
1404 }
1405}
1406
1407impl<C> KdbxParse<C> for Vec<u8> {
1408 fn parse<R: Read>(
1409 reader: &mut EventReader<R>,
1410 name: OwnedName,
1411 attributes: Vec<OwnedAttribute>,
1412 _context: &mut C,
1413 ) -> Result<Option<Self>, String> {
1414 Ok(Some(
1417 decode_base64(reader, name, attributes)?
1418 .try_into()
1419 .map_err(|_| "")?,
1420 ))
1421 }
1422}
1423
1424impl<C> KdbxSerialize<C> for Vec<u8> {
1425 fn serialize2<W: Write>(
1426 writer: &mut EventWriter<W>,
1427 value: Self,
1428 _context: &mut C,
1429 ) -> Result<(), String> {
1430 encode_base64(writer, value)
1431 }
1432}
1433
1434impl<C> KdbxParse<C> for HashMap<String, String> {
1435 fn parse<R: Read>(
1436 reader: &mut EventReader<R>,
1437 name: OwnedName,
1438 attributes: Vec<OwnedAttribute>,
1439 _context: &mut C,
1440 ) -> Result<Option<Self>, String> {
1441 Ok(Some(decode_custom_data(reader, name, attributes)?))
1442 }
1443}
1444
1445impl<C> KdbxSerialize<C> for HashMap<String, String> {
1446 fn serialize2<W: Write>(
1447 writer: &mut EventWriter<W>,
1448 value: Self,
1449 _context: &mut C,
1450 ) -> Result<(), String> {
1451 encode_custom_data(writer, value)
1452 }
1453}
1454
1455#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1457#[cfg_attr(test, derive(PartialEq))]
1459pub struct Times {
1460 creation_time: DateTime<Utc>,
1462 last_modification_time: DateTime<Utc>,
1464 last_access_time: DateTime<Utc>,
1466 expiry_time: DateTime<Utc>,
1468 expires: bool,
1470 usage_count: i32,
1472 location_changed: DateTime<Utc>,
1474}
1475
1476#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1477#[cfg_attr(test, derive(PartialEq))]
1478struct ProtectedString {
1479 key: String,
1480 value: ProtectedValue,
1481}
1482
1483#[derive(Clone, Debug)]
1484#[cfg_attr(test, derive(PartialEq))]
1485pub enum ProtectedValue {
1486 Unprotected(String),
1487 Protected(usize, Vec<u8>),
1488}
1489
1490use protected_stream::CipherValue;
1491
1492impl ProtectedValue {
1493 pub fn unprotect(&self, cipher: &mut CipherValue) -> Result<String, String> {
1494 match self {
1495 Self::Unprotected(ref v) => Ok(v.clone()),
1496 Self::Protected(offset, bytes) => {
1497 let mut value = bytes.clone();
1498 cipher.apply_keystream_pos(&mut value, *offset);
1499 String::from_utf8(value).map_err(|_| "Invalid UTF-8".to_string())
1500 }
1501 }
1502 }
1503}
1504
1505impl Default for ProtectedValue {
1506 fn default() -> Self {
1507 Self::Unprotected("".to_string())
1508 }
1509}
1510
1511impl KdbxParse<KdbxContext> for ProtectedValue {
1512 fn parse<R: Read>(
1513 reader: &mut EventReader<R>,
1514 name: OwnedName,
1515 attributes: Vec<OwnedAttribute>,
1516 context: &mut KdbxContext,
1517 ) -> Result<Option<Self>, String> {
1518 let protected = attributes.iter().filter(|a| a.name.local_name == "Protected").last().map(|v| v.value.to_ascii_lowercase() == "true").unwrap_or(false);
1519 if protected {
1520 decode_optional_base64(reader, name, attributes).map(|o| o.map(|v| { let offset = context.inner_cipher_position; context.inner_cipher_position += v.len(); Self::Protected(offset, v)}))
1521 } else {
1522 decode_optional_string(reader, name, attributes).map(|o| o.map(|v| Self::Unprotected(v)))
1523 }
1524 }
1525}
1526
1527impl<C> KdbxSerialize<C> for ProtectedValue {
1528 fn serialize2<W: Write>(
1529 _writer: &mut EventWriter<W>,
1530 _value: Self,
1531 _context: &mut C,
1532 ) -> Result<(), String> {
1533 Ok(())
1535 }
1536}
1537
1538#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1539#[cfg_attr(test, derive(PartialEq))]
1540struct ProtectedBinary {
1541 key: String,
1542 value: BinaryRef,
1543}
1544
1545#[derive(Clone, Debug)]
1546#[cfg_attr(test, derive(PartialEq))]
1547struct BinaryRef(Vec<u8>);
1548
1549impl BinaryRef {
1550}
1551
1552impl Default for BinaryRef {
1553 fn default() -> Self {
1554 Self(vec![])
1555 }
1556}
1557
1558impl KdbxParse<KdbxContext> for BinaryRef {
1559 fn parse<R: Read>(
1560 reader: &mut EventReader<R>,
1561 _name: OwnedName,
1562 attributes: Vec<OwnedAttribute>,
1563 context: &mut KdbxContext,
1564 ) -> Result<Option<Self>, String> {
1565 use std::str::FromStr;
1566 let id = attributes.iter().filter(|a| a.name.local_name == "Ref").last().and_then(|v| usize::from_str(v.value.as_str()).ok()).unwrap_or(0);
1567 loop {
1568 let event = reader.next().unwrap();
1569 match event {
1570 XmlEvent::StartDocument { .. } => {
1571 return Err("Malformed XML document".to_string());
1572 }
1573 XmlEvent::EndDocument { .. } => {
1574 return Err("Malformed XML document".to_string());
1575 }
1576 XmlEvent::StartElement { .. } => {
1577 reader.skip().map_err(|e| format!("Malformed XML document: {e}"))?;
1578 }
1579 XmlEvent::EndElement { .. } => {
1580 return Ok(Some(Self(context.binaries.get(id).map(|v| v.clone()).unwrap_or_else(|| vec![]))));
1581 }
1582 _ => {}
1583 }
1584 }
1585 }
1586}
1587
1588impl<C> KdbxSerialize<C> for BinaryRef {
1589 fn serialize2<W: Write>(
1590 _writer: &mut EventWriter<W>,
1591 _value: Self,
1592 _context: &mut C,
1593 ) -> Result<(), String> {
1594 Ok(())
1596 }
1597}
1598
1599
1600#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize, Getters)]
1602pub struct Group {
1603 #[keepass_db(element = "UUID")]
1604 uuid: Uuid,
1605 name: String,
1606 notes: String,
1608 #[keepass_db(element = "IconID")]
1610 icon_id: u32,
1611 #[keepass_db(element = "CustomIconUUID")]
1613 custom_icon_uuid: Option<Uuid>,
1614 times: Times,
1615 is_expanded: bool,
1616 default_auto_type_sequence: String,
1617 enable_auto_type: bool,
1618 enable_searching: bool,
1619 last_top_visible_entry: Uuid,
1620 previous_parent_group: Option<Uuid>,
1622 tags: Option<String>, #[keepass_db(flatten)]
1624 #[getter(rename = "entries")]
1625 entry: Vec<Entry>,
1626 #[keepass_db(flatten)]
1627 #[getter(rename = "groups")]
1628 group: Vec<Group>,
1629}
1630
1631impl Group {
1632pub fn all_groups(&self) -> GroupIter {
1642 return GroupIter {
1643 first: true,
1644 group: self,
1645 children: self.group.iter(),
1646 next_group: None,
1647 }
1648 }
1649
1650 pub fn all_entries(&self) -> EntryIter {
1652 let mut groups = self.all_groups();
1653 return EntryIter {
1654 entries: groups.next().map(|e| e.entries().iter()),
1655 groups,
1656 }
1657 }
1658}
1659
1660pub struct GroupIter<'a> {
1661 first: bool,
1662 group: &'a Group,
1663 children: Iter<'a, Group>,
1664 next_group: Option<Box<GroupIter<'a>>>,
1665}
1666
1667impl<'a> Iterator for GroupIter<'a> {
1668 type Item = &'a Group;
1669
1670 fn next(&mut self) -> Option<Self::Item> {
1671 if self.first {
1672 self.first = false;
1673 self.next_group = self.children.next().map(|c| Box::new(c.all_groups()));
1674 Some(self.group)
1675 } else {
1676 if let Some(ref mut child) = self.next_group {
1677 if let Some(g) = child.next() {
1678 Some(g)
1679 } else {
1680 self.next_group = self.children.next().map(|c| Box::new(c.all_groups()));
1681 if let Some(ref mut child) = self.next_group {
1682 if let Some(g) = child.next() {
1683 Some(g)
1684 } else {
1685 None
1686 }
1687 } else {
1688 None
1689 }
1690 }
1691 } else {
1692 None
1693 }
1694 }
1695 }
1696}
1697
1698pub struct EntryIter<'a> {
1700 entries: Option<Iter<'a, Entry>>,
1701 groups: GroupIter<'a>,
1702}
1703
1704impl<'a> Iterator for EntryIter<'a> {
1705 type Item = &'a Entry;
1706
1707 fn next(&mut self) -> Option<Self::Item> {
1708 while let Some(ref mut d) = self.entries {
1709 if let Some(e) = d.next() {
1710 return Some(e);
1711 } else {
1712 self.entries = self.groups.next().map(|e| e.entries().iter());
1713 }
1714 }
1715 None
1716 }
1717}
1718
1719#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1720#[cfg_attr(test, derive(PartialEq))]
1721struct Association {
1722 window: String,
1723 keystroke_sequence: String,
1724}
1725
1726#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1727#[cfg_attr(test, derive(PartialEq))]
1728struct AutoType {
1729 enabled: bool,
1730 data_transfer_obfuscation: i64,
1731 default_sequence: Option<String>,
1732 #[keepass_db(flatten)]
1733 association: Vec<Association>,
1734}
1735
1736#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize, Getters)]
1738#[cfg_attr(test, derive(PartialEq))]
1739pub struct Entry {
1740 #[keepass_db(element = "UUID")]
1742 uuid: Uuid,
1743 #[keepass_db(element = "IconID")]
1745 icon_id: u32,
1746 #[keepass_db(element = "CustomIconUUID")]
1748 custom_icon_uuid: Option<Uuid>,
1749 foreground_color: String,
1751 background_color: String,
1753 #[keepass_db(element = "OverrideURL")]
1754 override_url: String,
1755 quality_check: Option<bool>,
1756 tags: String,
1758 previous_parent_group: Option<Uuid>,
1759 times: Times,
1760 custom_data: Vec<Item>,
1761 #[keepass_db(flatten)]
1762 #[getter(skip)]
1763 string: Vec<ProtectedString>,
1764 #[keepass_db(flatten)]
1765 #[getter(skip)]
1766 binary: Vec<ProtectedBinary>,
1767 #[getter(skip)]
1768 auto_type: AutoType,
1769 history: Option<Vec<Entry>>,
1770}
1771
1772const TITLE_FIELD: &str = "Title";
1773const USER_NAME_FIELD: &str = "UserName";
1774const PASSWORD_FIELD: &str = "Password";
1775const URL_FIELD: &str = "URL";
1776const NOTES_FIELD: &str = "Notes";
1777
1778impl Entry {
1779 pub fn title(&self) -> ProtectedValue {
1780 self.string.iter().find(|p| p.key == TITLE_FIELD).map(|p| p.value.clone()).unwrap_or(ProtectedValue::Unprotected("".to_string()))
1781 }
1782
1783 pub fn username(&self) -> ProtectedValue {
1784 self.string.iter().find(|p| p.key == USER_NAME_FIELD).map(|p| p.value.clone()).unwrap_or(ProtectedValue::Unprotected("".to_string()))
1785 }
1786
1787 pub fn password(&self) -> ProtectedValue {
1788 self.string.iter().find(|p| p.key == PASSWORD_FIELD).map(|p| p.value.clone()).unwrap_or(ProtectedValue::Unprotected("".to_string()))
1789 }
1790
1791 pub fn url(&self) -> ProtectedValue {
1792 self.string.iter().find(|p| p.key == URL_FIELD).map(|p| p.value.clone()).unwrap_or(ProtectedValue::Unprotected("".to_string()))
1793 }
1794
1795 pub fn notes(&self) -> ProtectedValue {
1796 self.string.iter().find(|p| p.key == NOTES_FIELD).map(|p| p.value.clone()).unwrap_or(ProtectedValue::Unprotected("".to_string()))
1797 }
1798
1799 pub fn get_binary(&self, index: usize) -> (&str, &[u8]) {
1800 (self.binary[index].key.as_ref(), self.binary[index].value.0.as_ref())
1801 }
1802}
1803
1804#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1805pub struct DeletedObject {
1806 #[keepass_db(element = "UUID")]
1807 uuid: Uuid,
1808 deletion_time: DateTime<Utc>,
1809}
1810
1811#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize, Getters)]
1812pub struct Root {
1813 #[keepass_db(flatten)]
1814 group: Group,
1815 deleted_objects: Vec<DeletedObject>,
1816}
1817
1818#[derive(Clone, Debug, Default, KdbxParse, KdbxSerialize)]
1824pub struct KeePassFile {
1825 meta: Meta,
1826 root: Root,
1827}
1828
1829impl KeePassFile {
1830 pub fn root_group(&self) -> &Group {
1831 &self.root.group
1832 }
1833}
1834
1835const KDBX_MAGIC: u32 = 0x9AA2D903;
1836
1837const KDBX1_MAGIC_TYPE: u32 = 0xB54BFB65;
1838const KDBX2_BETA_MAGIC_TYPE: u32 = 0xB54BFB66;
1839const KDBX2_MAGIC_TYPE: u32 = 0xB54BFB67;
1840
1841#[derive(Default)]
1843pub struct KeePassDoc {
1844 pub file: KeePassFile,
1845 pub cipher: CipherValue,
1846}
1847
1848impl KeePassDoc {
1849 pub fn load_file(filename: &str, key: &Key) -> io::Result<Self> {
1851 let composite_key = key.composite_key();
1852
1853 let mut file = File::open(filename)?;
1854 let magic = file.read_u32::<LittleEndian>()?;
1855 let magic_type = file.read_u32::<LittleEndian>()?;
1856
1857 if magic != KDBX_MAGIC {
1858 eprintln!("Invalid database file\n");
1859 process::exit(1);
1860 }
1861
1862 let mut custom_data = HashMap::<String, Vec<u8>>::new();
1863 let mut custom_data2 = HashMap::<_, _>::new();
1864
1865 match magic_type {
1866 KDBX1_MAGIC_TYPE => {
1867 use kdb1::read_kdb1_header;
1868 read_kdb1_header(&mut file, &key)?;
1869 return Ok(KeePassDoc::default());
1870 }
1871 KDBX2_MAGIC_TYPE | KDBX2_BETA_MAGIC_TYPE => {
1877 println!("Opening KeePass 2.x database");
1878 }
1879 _ => {
1880 eprintln!("Unknown KeePass database format\n");
1882 process::exit(1);
1883 }
1884 };
1885
1886 let minor_version = file.read_u16::<LittleEndian>()?;
1890 let major_version = file.read_u16::<LittleEndian>()?;
1891 match major_version {
1892 3 => {
1893 unsafe {
1894 KDBX4 = false;
1895 };
1896 custom_data.insert(
1897 KDF_PARAM_UUID.to_string(),
1898 KDF_AES_KDBX3.as_bytes().to_vec(),
1899 );
1900 }
1901 4 => {}
1902 1 => {
1903 custom_data.insert(
1904 KDF_PARAM_UUID.to_string(),
1905 KDF_AES_KDBX3.as_bytes().to_vec(),
1906 );
1907 }
1908 _ => {
1909 eprintln!(
1910 "Unsupported KeePass 2.x database version ({}.{})\n",
1911 major_version, minor_version
1912 );
1913 process::exit(1);
1914 }
1915 };
1916 let mut tlvs = HashMap::new();
1917 let mut inner_tlvs = BTreeMap::<u8, Vec<Vec<u8>>>::new();
1918 inner_tlvs.insert(3u8, vec![]);
1919 loop {
1920 let tlv_type = file.read_u8()?;
1921 let tlv_len = if major_version == 4 {
1922 file.read_u32::<LittleEndian>()?
1923 } else {
1924 file.read_u16::<LittleEndian>()? as u32
1926 };
1927 let mut tlv_data = vec![0; tlv_len as usize];
1928 file.read_exact(&mut tlv_data)?;
1929 debug!("TLV({}, {}): {:?}", tlv_type, tlv_len, tlv_data);
1930 match tlv_type {
1931 0 => {
1932 break;
1933 }
1934 5 => {
1935 custom_data.insert(KDF_PARAM_SALT.to_string(), tlv_data.clone());
1936 custom_data2.insert(KDF_PARAM_SALT.to_string(), MapValue::ByteArray(tlv_data));
1937 }
1938 6 => {
1939 custom_data.insert(KDF_PARAM_ROUNDS.to_string(), tlv_data.clone());
1940 custom_data2.insert(
1941 KDF_PARAM_ROUNDS.to_string(),
1942 MapValue::UInt64(u64::from_le_bytes(tlv_data[0..8].try_into().unwrap())),
1943 );
1944 }
1945 8 => {
1946 inner_tlvs.insert(2u8, vec![tlv_data]);
1947 }
1948 10 => {
1949 inner_tlvs.insert(1u8, vec![tlv_data]);
1950 }
1951 11 => {
1952 custom_data2 = load_map(&tlv_data).unwrap();
1953 let kdf_parameters = &tlv_data;
1954 let mut c = Cursor::new(kdf_parameters);
1955 let variant_minor = c.read_u8()?;
1956 let variant_major = c.read_u8()?;
1957 if variant_major != 1 {
1958 eprintln!(
1959 "Unsupported variant dictionary version ({}.{})\n",
1960 variant_major, variant_minor
1961 );
1962 process::exit(1);
1963 };
1964
1965 loop {
1966 let item_type = c.read_u8()?;
1967 if item_type == 0 {
1968 break;
1969 }
1970 let item_key_len = c.read_u32::<LittleEndian>()?;
1971 let mut item_key = vec![0; item_key_len as usize];
1972 c.read_exact(&mut item_key)?;
1973 let item_key_str = String::from_utf8_lossy(&item_key).to_owned();
1974 let item_value_len = c.read_u32::<LittleEndian>()?;
1975 let mut item_value = vec![0; item_value_len as usize];
1976 c.read_exact(&mut item_value)?;
1977 debug!("K: {}, V: {:0x?}", item_key_str, item_value);
1978 custom_data.insert(item_key_str.to_owned().to_string(), item_value);
1979 }
1980 }
1981 _ => {
1982 tlvs.insert(tlv_type, tlv_data);
1983 }
1984 }
1985 }
1986
1987 let cipher_id = Uuid::from_slice(&tlvs[&2u8]).unwrap();
1993 println!("D: {:?}", cipher_id);
1994 if cipher_id != CIPHER_ID_AES256_CBC {
1995 eprintln!("Unknown cipher\n");
1996 process::exit(1);
1997 }
1998 println!("AES");
1999 let mut c = Cursor::new(&tlvs[&3u8]);
2000 let compression_flags = c.read_u32::<LittleEndian>()?;
2001 enum Compression {
2002 None,
2003 Gzip,
2004 }
2005 let compress = match compression_flags {
2006 0 => {
2007 Compression::None
2011 }
2012 1 => {
2013 println!("Gzip compression");
2014 Compression::Gzip
2015 }
2016 _ => {
2017 eprintln!("Unsupported compression method\n");
2019 process::exit(1);
2020 }
2021 };
2022
2023 let master_seed = &tlvs[&4u8];
2024 let encryption_iv = &tlvs[&7u8];
2025
2026 let mut context = Context::new(&SHA256);
2028 let pos = file.seek(SeekFrom::Current(0))?;
2029 file.seek(SeekFrom::Start(0))?;
2030 let mut header = vec![0; (pos) as usize];
2031 file.read_exact(&mut header)?;
2032 file.seek(SeekFrom::Start(pos))?;
2033 context.update(&header);
2034 let digest = context.finish();
2035 if major_version == 4 {
2036 let mut expected_hash = [0; 32];
2037 file.read_exact(&mut expected_hash)?;
2038 if digest.as_ref() != expected_hash {
2039 eprintln!("Possible header corruption\n");
2040 process::exit(1);
2041 }
2042 }
2043
2044 let kdf_id = Uuid::from_slice(&custom_data[KDF_PARAM_UUID]).unwrap();
2045 println!("KDF: {:?}", kdf_id);
2046
2047 let transform_key = match kdf_id {
2048 x if x == KDF_AES_KDBX3 => {
2049 AesKdf::load(&custom_data2)?.transform_key(&composite_key)?
2051 }
2053 x if x == KDF_AES_KDBX4 => {
2054 unimplemented!("KDBX 4 AES-KDF not supported!");
2055 }
2056 x if x == KDF_ARGON2_D => {
2057 transform_argon2(&composite_key, &custom_data)?
2058 }
2060 _ => {
2061 unimplemented!("Unknown");
2062 }
2063 };
2064
2065 println!("Key OUT: {:0x?}", transform_key);
2066
2067 println!("Calculating master key");
2068 let mut hmac_context = Context::new(&SHA512);
2069
2070 let mut master_key = master_seed.to_owned();
2071 master_key.extend(transform_key);
2072 let mut context = Context::new(&SHA256);
2073 context.update(&master_key);
2074 hmac_context.update(&master_key);
2075 hmac_context.update(&[1u8]);
2076 master_key = context.finish().as_ref().to_owned();
2077 let hmac_key_base = hmac_context.finish().as_ref().to_owned();
2078 println!("Master OUT: {:0x?}", master_key);
2079 println!("HMAC OUT: {:0x?}", hmac_key_base);
2080
2081 let mut hmac_context = Context::new(&SHA512);
2082 hmac_context.update(&[0xff; 8]);
2083 hmac_context.update(&hmac_key_base);
2084 let hmac_key = hmac_context.finish().as_ref().to_owned();
2085
2086 let mut hmac_tag = [0; 32];
2087 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &hmac_key);
2089 if major_version == 4 {
2090 file.read_exact(&mut hmac_tag)?;
2091 println!("Verifying HMAC");
2092 hmac::verify(&hmac_key, &header, &hmac_tag).map_err(|_| io::Error::new(io::ErrorKind::Other, "Bad password or key file"))?;
2093 println!("Complete");
2094 }
2095
2096 let contents = if major_version == 4 {
2097 let mut ciphertext = vec![];
2098 for idx in 0.. {
2099 println!("Block {}", idx);
2100 file.read_exact(&mut hmac_tag)?;
2101 let block_size = file.read_u32::<LittleEndian>()?;
2102 if block_size == 0 {
2103 break;
2104 }
2105 let mut block = vec![0; block_size as usize];
2106 file.read_exact(&mut block)?;
2107
2108 let mut hmac_context = Context::new(&SHA512);
2109 let mut buf = Cursor::new(Vec::new());
2110 buf.write_u64::<LittleEndian>(idx)?;
2111 hmac_context.update(buf.get_ref());
2112 hmac_context.update(&hmac_key_base);
2113 let hmac_key = hmac_context.finish().as_ref().to_owned();
2114 buf.write_u32::<LittleEndian>(block_size)?;
2115 buf.write(&block)?;
2116 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &hmac_key);
2117 println!("Verifying HMAC");
2118 hmac::verify(&hmac_key, buf.get_ref(), &hmac_tag).unwrap();
2119 println!("Complete");
2120 ciphertext.extend(block);
2121 }
2122
2123 let data = decrypt(
2124 Cipher::aes_256_cbc(),
2125 &master_key,
2126 Some(encryption_iv),
2127 &ciphertext,
2128 )
2129 .unwrap();
2130 let mut gz: Box<dyn Read> = match compress {
2131 Compression::Gzip => Box::new(GzDecoder::new(Cursor::new(data))),
2132 Compression::None => Box::new(Cursor::new(data)),
2133 };
2134
2135 inner_tlvs = load_tlvs(&mut gz, major_version)?.0;
2136 let mut contents = String::new();
2137 gz.read_to_string(&mut contents)?;
2138 contents
2139 } else {
2140 let mut ciphertext = vec![];
2143 file.read_to_end(&mut ciphertext)?;
2144 let data = decrypt(
2145 Cipher::aes_256_cbc(),
2146 &master_key,
2147 Some(encryption_iv),
2148 &ciphertext,
2149 )
2150 .unwrap();
2151 let mut c = Cursor::new(data);
2152
2153 let mut start_stream = vec![0; 32];
2155 c.read_exact(&mut start_stream)?;
2156 assert_eq!(&start_stream, &tlvs[&9u8]);
2157 println!("Master Key appears valid");
2158
2159 let mut buf = vec![];
2160 for idx in 0.. {
2161 println!("Block {}", idx);
2162 let block_id = c.read_u32::<LittleEndian>()?;
2163 assert_eq!(idx as u32, block_id);
2164 let mut block_hash_expected = vec![0; 32];
2165 c.read_exact(&mut block_hash_expected)?;
2166 let block_size = c.read_u32::<LittleEndian>()?;
2167 let mut block_data = vec![0; block_size as usize];
2168 c.read_exact(&mut block_data)?;
2169 let mut context = Context::new(&SHA256);
2170 context.update(&block_data);
2171 let block_hash = context.finish().as_ref().to_owned();
2172 if block_size == 0 {
2173 break;
2174 }
2175 assert_eq!(block_hash_expected, block_hash, "Failed hash");
2176 buf.extend(block_data);
2177 }
2178 let mut gz: Box<dyn Read> = match compress {
2179 Compression::Gzip => Box::new(GzDecoder::new(Cursor::new(buf))),
2180 Compression::None => Box::new(Cursor::new(buf)),
2181 };
2182 let mut xml_file = File::create("data2.xml")?;
2183 let mut contents = String::new();
2184 gz.read_to_string(&mut contents)?;
2185 let _ = xml_file.write(&contents.as_bytes());
2186 if &contents[0..3] == "\u{feff}" {
2188 contents = contents[3..].to_string();
2189 }
2190 let package = parser::parse(&contents).unwrap();
2191 let document = package.as_document();
2192 let header_hash = evaluate_xpath(&document, "/KeePassFile/Meta/HeaderHash/text()")
2193 .expect("Missing header hash");
2194 if header_hash.string() != "" {
2195 println!("Header Hash: '{}'", header_hash.string());
2196 let expected_hash = base64.decode(&header_hash.string()).expect("Valid base64");
2197 if expected_hash != digest.as_ref() {
2198 eprintln!("Possible header corruption\n");
2199 process::exit(1);
2200 }
2201 }
2202 contents
2203 };
2204
2205 let default = vec![vec![1, 0, 0, 0]];
2206 let inner_stream_cipher = &inner_tlvs.get(&1u8).unwrap_or(&default)[0]; if inner_stream_cipher.len() != 4 {
2208 panic!("Invalid inner cipher");
2209 }
2210 let inner_cipher_type = u32::from_le_bytes(inner_stream_cipher[..].try_into().unwrap());
2211 println!("Inner Cipher: {inner_cipher_type}");
2212 let p_key = &inner_tlvs[&0x02u8][0];
2213 println!("p_key: {p_key:02x?} ({})", p_key.len());
2214 let mut inner_cipher = protected_stream::new_stream(inner_cipher_type, p_key).expect("Unknown inner cipher");
2215
2216 let mut xml_file = File::create("data.xml")?;
2217 let _ = xml_file.write(&contents.as_bytes());
2218 const KDBX4_TIME_OFFSET: i64 = 62135596800;
2219 println!("XML Body len: {}", contents.len());
2220 let package = parser::parse(&contents).unwrap();
2221 let document = package.as_document();
2222 println!(
2223 "Root element: {}",
2224 document.root().children()[0]
2225 .element()
2226 .unwrap()
2227 .name()
2228 .local_part()
2229 );
2230 let database_name_node = evaluate_xpath(&document, "/KeePassFile/Meta/DatabaseName/text()")
2231 .expect("Missing database name");
2232 println!("Database Name: {}", database_name_node.string());
2233 let database_name_changed_node =
2234 evaluate_xpath(&document, "/KeePassFile/Meta/DatabaseNameChanged/text()")
2235 .expect("Missing database name changed");
2236 let change_time = if database_name_changed_node.string() == "" {
2237 "<missing>".to_owned()
2238 } else {
2239 let datetime: DateTime<Local> = if major_version <= 3 {
2240 DateTime::parse_from_rfc3339(&database_name_changed_node.string())
2241 .expect("failed to parse timestamp")
2242 .with_timezone(&Local)
2243 } else {
2244 let timestamp =
2245 Cursor::new(base64.decode(&database_name_changed_node.string()).expect("Valid base64"))
2246 .read_i64::<LittleEndian>()?
2247 - KDBX4_TIME_OFFSET;
2248 Local.timestamp_opt(timestamp, 0).unwrap()
2251 };
2252 datetime.format("%Y-%m-%d %l:%M:%S %p %Z").to_string()
2253 };
2254 println!("Database Name Changed: {}", change_time);
2255
2256 let xpath_context = XPathContext::new();
2257 let protected_nodes = evaluate_xpath(&document, "//Value[@Protected = 'True']/text()")
2258 .expect("Missing database entries");
2259 let xpath_current = Factory::new()
2260 .build(".")
2261 .expect("Failed to compile XPath")
2262 .expect("Empty XPath expression");
2263 let mut protected_offset = 0;
2264 match protected_nodes {
2265 Value::Nodeset(nodes) => {
2266 for entry in nodes.document_order() {
2267 let p = xpath_current
2268 .evaluate(&xpath_context, entry)
2269 .expect("Missing entry text");
2270 println!("P: {:?}, ('{}')", p, p.string());
2271 let mut p_ciphertext = base64.decode(&p.string()).expect("Valid base64");
2272 println!("Protected Value Ciphertext: {p_ciphertext:#04X?} (+{protected_offset})");
2273 protected_offset += p_ciphertext.len();
2274 inner_cipher.apply_keystream(&mut p_ciphertext);
2275 println!("Protected Value Plaintext: {p_ciphertext:#04X?}");
2276 let value = String::from_utf8(p_ciphertext)
2277 .unwrap_or("«Failed to decrypt value»".to_owned());
2278 println!("Protected Value: {:?}", &value);
2279 match entry {
2280 sxd_xpath::nodeset::Node::Text(t) => {
2281 t.set_text(&value);
2282 }
2283 _ => {}
2284 }
2285 }
2286 }
2287 _ => {
2288 panic!("XML corruption");
2289 }
2290 }
2291 let xpath_username = Factory::new()
2292 .build("String[Key/text() = 'UserName']/Value/text()")
2293 .expect("Failed to compile XPath")
2294 .expect("Empty XPath expression");
2295 let xpath_last_mod_time = Factory::new()
2296 .build("Times/LastModificationTime/text()")
2297 .expect("Failed to compile XPath")
2298 .expect("Empty XPath expression");
2299 let xpath_password = Factory::new()
2300 .build("String[Key/text() = 'Password']/Value[@Protected = 'True']/text()")
2301 .expect("Failed to compile XPath")
2302 .expect("Empty XPath expression");
2303 let entry_nodes = evaluate_xpath(&document, "//Entry").expect("Missing database entries");
2305 match entry_nodes {
2306 Value::Nodeset(nodes) => {
2307 for entry in nodes.document_order() {
2308 let n = xpath_username
2310 .evaluate(&xpath_context, entry)
2311 .expect("Missing entry username");
2312 let t = xpath_last_mod_time
2313 .evaluate(&xpath_context, entry)
2314 .expect("Missing entry modification");
2315 let p = xpath_password
2316 .evaluate(&xpath_context, entry)
2317 .expect("Missing entry password");
2318 println!("Name: {}", n.string());
2319 let change_time = if database_name_changed_node.string() == "" {
2320 "<missing>".to_owned()
2321 } else {
2322 let datetime: DateTime<Local> = if major_version <= 3 {
2323 DateTime::parse_from_rfc3339(&t.string())
2324 .expect("failed to parse timestamp")
2325 .with_timezone(&Local)
2326 } else {
2327 println!("Inner: {:?}", &t.string());
2328 let timestamp =
2329 Cursor::new(base64.decode(&t.string()).expect("Valid base64"))
2330 .read_i64::<LittleEndian>()?
2331 - KDBX4_TIME_OFFSET;
2332 Local.timestamp_opt(timestamp, 0).unwrap()
2335 };
2336 datetime.format("%Y-%m-%d %l:%M:%S %p %Z").to_string()
2337 };
2338 println!("Changed: {}", change_time);
2339 println!("Password: {:?}", p.string());
2340 }
2341 }
2342 _ => {
2343 panic!("XML corruption");
2344 }
2345 };
2346
2347 let content_cursor = Cursor::new(&contents);
2348 let mut reader = ParserConfig::new()
2349 .cdata_to_characters(true)
2350 .create_reader(content_cursor);
2351 let mut my_doc = None;
2352 loop {
2353 let event = reader.next().unwrap();
2354 match event {
2355 XmlEvent::StartDocument { .. } => {
2356 println!("Start");
2357 }
2358 XmlEvent::StartElement {
2359 name, attributes, ..
2360 } => {
2361 let mut context = KdbxContext::default();
2363 context.major_version = major_version;
2364 context.binaries = inner_tlvs.remove(&3u8).unwrap();
2365 my_doc = Some(KeePassFile::parse(&mut reader, name, attributes, &mut context)
2366 .map_err(|x| ::std::io::Error::new(::std::io::ErrorKind::Other, x))?
2367 .unwrap());
2368 }
2369 XmlEvent::EndDocument => {
2370 println!("End");
2371 break;
2372 }
2373 _ => {}
2374 }
2375 }
2376
2377 Ok(KeePassDoc {
2378 file: my_doc.expect("Missing top-level element"),
2379 cipher: inner_cipher,
2380 })
2381 }
2382
2383 #[cfg(feature = "write")]
2384 pub fn save_file(&self, major_version: u16) -> io::Result<()> {
2385 let mut file = File::create("data-out.kdbx")?;
2386 let minor_version = 0;
2387 let mut header = vec![];
2388 header.write_u32::<LittleEndian>(KDBX_MAGIC)?;
2389 header.write_u32::<LittleEndian>(KDBX2_MAGIC_TYPE)?;
2390 header.write_u16::<LittleEndian>(minor_version)?;
2391 header.write_u16::<LittleEndian>(major_version)?;
2392 let mut key = Key::new();
2393 key.set_user_password("asdf");
2394 let composite_key = key.composite_key();
2395 let kdf = AesKdf::default();
2396 let mut custom_data = HashMap::new();
2397 custom_data.insert(
2398 KDF_PARAM_UUID.to_string(),
2399 MapValue::ByteArray(KDF_AES_KDBX3.into_bytes().to_vec()),
2400 );
2401 kdf.save(&mut custom_data);
2402 let transform_key = kdf
2403 .transform_key(&composite_key)
2404 .expect("Failed to transform key");
2405 let master_seed = [0u8; 32];
2406 let iv = [0u8; 16];
2407 let stream_cipher = 2u32;
2408 let stream_key = [0u8; 32];
2409 let mut tlvs = BTreeMap::new();
2410 tlvs.insert(
2411 TlvType::MasterSeed.to_u8().unwrap(),
2412 vec![master_seed.to_vec()],
2413 );
2414 tlvs.insert(
2415 TlvType::CipherId.to_u8().unwrap(),
2416 vec![CIPHER_ID_AES256_CBC.into_bytes().to_vec()],
2417 );
2418 tlvs.insert(TlvType::EncryptionIv.to_u8().unwrap(), vec![iv.to_vec()]);
2419 tlvs.insert(
2420 TlvType::CompressionFlags.to_u8().unwrap(),
2421 vec![Compression::None.to_u32().unwrap().to_le_bytes().to_vec()],
2422 );
2423 let start_stream = vec![0; 32]; if major_version < 4 {
2425 tlvs.insert(
2426 TlvType::TransformSeed.to_u8().unwrap(),
2427 vec![master_seed.to_vec()],
2428 );
2429 tlvs.insert(
2430 TlvType::TransformRounds.to_u8().unwrap(),
2431 vec![match custom_data[KDF_PARAM_ROUNDS] {
2432 MapValue::UInt64(x) => x.to_le_bytes().to_vec(),
2433 _ => panic!("Wrong"),
2434 }],
2435 );
2436 tlvs.insert(
2437 TlvType::StreamStartBytes.to_u8().unwrap(),
2438 vec![start_stream.to_vec()],
2439 );
2440 tlvs.insert(
2441 TlvType::ProtectedStreamKey.to_u8().unwrap(),
2442 vec![stream_key.to_vec()],
2443 );
2444 tlvs.insert(
2445 TlvType::InnerRandomStreamId.to_u8().unwrap(),
2446 vec![stream_cipher.to_le_bytes().to_vec()],
2447 );
2448 } else {
2449 tlvs.insert(
2450 TlvType::KdfParameters.to_u8().unwrap(),
2451 vec![save_map(&custom_data)],
2452 );
2453 }
2454 header.append(&mut save_tlvs(&mut io::sink(), &tlvs, major_version).unwrap());
2455 file.write(&header)?;
2456 let mut context = Context::new(&SHA256);
2457 context.update(&header);
2458 let digest = context.finish();
2459 if major_version >= 4 {
2460 file.write(digest.as_ref())?;
2461 }
2463
2464 let mut master_key = master_seed.to_vec();
2465 master_key.extend(transform_key);
2466 let mut context = Context::new(&SHA256);
2467 let mut hmac_context = Context::new(&SHA512);
2468 context.update(&master_key);
2469 hmac_context.update(&master_key);
2470 hmac_context.update(&[1u8]);
2471 master_key = context.finish().as_ref().to_owned();
2472 let hmac_key_base = hmac_context.finish().as_ref().to_owned();
2473
2474 let mut hmac_context = Context::new(&SHA512);
2475 hmac_context.update(&[0xff; 8]);
2476 hmac_context.update(&hmac_key_base);
2477 let hmac_key = hmac_context.finish().as_ref().to_owned();
2478
2479 let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &hmac_key);
2480 let hmac_tag = hmac::sign(&hmac_key, &header);
2481 if major_version >= 4 {
2482 file.write(hmac_tag.as_ref())?;
2483 } else {
2484 let output = Cursor::new(Vec::<u8>::new());
2485 let mut context = KdbxContext::default();
2486 context.major_version = major_version;
2487 let mut writer = xml::writer::EventWriter::new(output);
2488 writer
2489 .write(xml::writer::XmlEvent::start_element("KeePassFile"))
2490 .expect("Success!");
2491 KeePassFile::serialize2(&mut writer, self.file.clone(), &mut context).unwrap();
2492 writer
2493 .write(xml::writer::XmlEvent::end_element())
2494 .expect("Success!");
2495 let output = writer.into_inner().into_inner();
2496 let mut buf = Cursor::new(Vec::<u8>::new());
2497 buf.write_all(&start_stream).unwrap();
2498 buf.write_all(&0u32.to_le_bytes()).unwrap();
2499 let mut context = Context::new(&SHA256);
2500 context.update(&output);
2501 buf.write_all(&context.finish().as_ref().to_owned()).unwrap();
2502 buf.write_all(&(output.len() as u32).to_le_bytes()).unwrap();
2503 buf.write_all(&output).unwrap();
2504 buf.write_all(&1u32.to_le_bytes()).unwrap();
2505 let context = Context::new(&SHA256);
2506 buf.write_all(&context.finish().as_ref().to_owned()).unwrap();
2507 buf.write_all(&0u32.to_le_bytes()).unwrap();
2509 let data = encrypt(
2510 Cipher::aes_256_cbc(),
2511 &master_key,
2512 Some(&iv),
2513 &buf.into_inner(),
2514 ).unwrap();
2515 file.write_all(&data).unwrap();
2516 return Ok(());
2517 }
2518
2519 let output = BlockWriter::new(&hmac_key_base, file);
2520 let cipher = Cipher::aes_256_cbc();
2521 let mut output = Crypto::new(cipher, &master_key, Some(&iv), output).unwrap();
2522
2523 if major_version >= 4 {
2524 let mut inner_tlvs = BTreeMap::new();
2525 inner_tlvs.insert(1, vec![stream_cipher.to_le_bytes().to_vec()]);
2526 inner_tlvs.insert(2, vec![stream_key.to_vec()]);
2527 save_tlvs(&mut output, &inner_tlvs, major_version).unwrap();
2528 }
2529 let mut writer = xml::writer::EventWriter::new(output);
2530 writer
2531 .write(xml::writer::XmlEvent::start_element("KeePassFile"))
2532 .expect("Success!");
2533 KeePassFile::serialize2(&mut writer, self.file.clone(), &mut KdbxContext::default()).unwrap();
2534 writer
2535 .write(xml::writer::XmlEvent::end_element())
2536 .expect("Success!");
2537 let mut output = writer.into_inner();
2538 output.flush()?;
2539 Ok(())
2543 }
2544}
2545
2546impl std::fmt::Debug for KeePassDoc {
2547 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2548 f.debug_struct("KeePassDoc")
2549 .field("file", &self.file)
2550 .finish()
2551 }
2552}