keepass_ng/
error.rs

1//! Error types that this crate can return
2
3#[derive(thiserror::Error, Debug)]
4pub enum Error {
5    #[error("std::io::Error {0}")]
6    Io(#[from] std::io::Error),
7
8    #[error("DatabaseError::RecycleBinDisabled")]
9    RecycleBinDisabled,
10
11    #[error("DatabaseError::RecycleBinAlreadyExists")]
12    RecycleBinAlreadyExists,
13
14    #[error("DatabaseOpenError {0}")]
15    DatabaseOpenError(#[from] DatabaseOpenError),
16
17    #[error("DatabaseSaveError {0}")]
18    DatabaseSaveError(#[from] DatabaseSaveError),
19
20    #[cfg(feature = "totp")]
21    #[error("DbOtpError {0}")]
22    DbOtpError(#[from] crate::db::otp::TOTPError),
23
24    #[error("OuterCipherConfigError {0}")]
25    OuterCipherConfigError(#[from] OuterCipherConfigError),
26
27    #[error("InnerCipherConfigError {0}")]
28    InnerCipherConfigError(#[from] InnerCipherConfigError),
29
30    #[error("CompressionConfigError {0}")]
31    CompressionConfigError(#[from] CompressionConfigError),
32
33    #[error("KdfConfigError {0}")]
34    KdfConfigError(#[from] KdfConfigError),
35
36    #[error("CryptographyError {0}")]
37    CryptographyError(#[from] CryptographyError),
38
39    #[error("BlockStreamError {0}")]
40    BlockStreamError(#[from] BlockStreamError),
41
42    #[error("VariantDictionaryError {0}")]
43    VariantDictionaryError(#[from] VariantDictionaryError),
44
45    #[error("XmlParseError {0}")]
46    XmlParseError(#[from] XmlParseError),
47
48    #[error("ParseColorError {0}")]
49    ParseColorError(#[from] ParseColorError),
50
51    #[error("ParseIconIdError {}", icon_id)]
52    ParseIconIdError { icon_id: usize },
53
54    #[cfg(feature = "_merge")]
55    #[error("MergeError {0}")]
56    MergeError(#[from] crate::db::merge::MergeError),
57
58    #[error("String error: {0}")]
59    String(String),
60}
61
62impl From<&str> for Error {
63    fn from(s: &str) -> Self {
64        Error::String(s.to_string())
65    }
66}
67
68impl From<String> for Error {
69    fn from(s: String) -> Self {
70        Error::String(s)
71    }
72}
73
74impl From<&String> for Error {
75    fn from(s: &String) -> Self {
76        Error::String(s.clone())
77    }
78}
79
80pub type Result<T, E = Error> = std::result::Result<T, E>;
81
82pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
83
84/// Errors upon reading a Database
85#[derive(Debug, thiserror::Error)]
86pub enum DatabaseOpenError {
87    /// An I/O error has occurred while reading the database
88    #[error(transparent)]
89    Io(#[from] std::io::Error),
90
91    /// An error with the database's key has occurred
92    #[error(transparent)]
93    Key(#[from] DatabaseKeyError),
94
95    /// The database is corrupted
96    #[error(transparent)]
97    DatabaseIntegrity(#[from] DatabaseIntegrityError),
98
99    /// The database version cannot be read by this library
100    #[error("Opening this database version is not supported")]
101    UnsupportedVersion,
102}
103
104/// Errors stemming from corrupted databases
105#[derive(Debug, thiserror::Error)]
106pub enum DatabaseIntegrityError {
107    /// The database does not have a valid KDBX identifier
108    #[error("Invalid KDBX identifier")]
109    InvalidKDBXIdentifier,
110
111    /// The version of the KDBX file is invalid
112    #[error("Invalid KDBX version: {}.{}.{}", version, file_major_version, file_minor_version)]
113    InvalidKDBXVersion {
114        version: u32,
115        file_major_version: u32,
116        file_minor_version: u32,
117    },
118
119    /// The fixed header has an invalid size
120    #[error("Invalid header size: {}", size)]
121    InvalidFixedHeader { size: usize },
122
123    #[error("Invalid field length for type {}: {} (expected {})", field_type, field_size, expected_field_size)]
124    InvalidKDBFieldLength {
125        field_type: u16,
126        field_size: u32,
127        expected_field_size: u32,
128    },
129
130    #[error("Missing group level")]
131    MissingKDBGroupLevel,
132
133    #[error("Invalid KDBX header field ID: {}", field_id)]
134    InvalidKDBXHeaderFieldID { field_id: u8 },
135
136    #[error("Invalid group level {} (current level {})", group_level, current_level)]
137    InvalidKDBGroupLevel { group_level: u16, current_level: u16 },
138
139    #[error("Missing group ID")]
140    MissingKDBGroupId,
141
142    #[error("Invalid group ID {}", group_id)]
143    InvalidKDBGroupId { group_id: u32 },
144
145    #[error("Invalid group field type: {}", field_type)]
146    InvalidKDBGroupFieldType { field_type: u16 },
147
148    #[error("Invalid entry field type: {}", field_type)]
149    InvalidKDBEntryFieldType { field_type: u16 },
150
151    #[error("Incomplete group")]
152    IncompleteKDBGroup,
153
154    #[error("Incomplete entry")]
155    IncompleteKDBEntry,
156
157    #[error("Invalid fixed cipher ID: {}", cid)]
158    InvalidFixedCipherID { cid: u32 },
159
160    #[error("Header hash masmatch")]
161    HeaderHashMismatch,
162
163    #[error("Invalid outer header entry: {}", entry_type)]
164    InvalidOuterHeaderEntry { entry_type: u8 },
165
166    #[error("Incomplete outer header: Missing {}", missing_field)]
167    IncompleteOuterHeader { missing_field: String },
168
169    #[error("Invalid inner header entry: {}", entry_type)]
170    InvalidInnerHeaderEntry { entry_type: u8 },
171
172    #[error("Incomplete outer header: Missing {}", missing_field)]
173    IncompleteInnerHeader { missing_field: String },
174
175    #[error(transparent)]
176    Cryptography(#[from] CryptographyError),
177
178    #[error(transparent)]
179    Xml(#[from] XmlParseError),
180
181    #[error(transparent)]
182    OuterCipher(#[from] OuterCipherConfigError),
183
184    #[error(transparent)]
185    InnerCipher(#[from] InnerCipherConfigError),
186
187    #[error(transparent)]
188    Compression(#[from] CompressionConfigError),
189
190    #[error(transparent)]
191    BlockStream(#[from] BlockStreamError),
192
193    #[error(transparent)]
194    VariantDictionary(#[from] VariantDictionaryError),
195
196    #[error(transparent)]
197    KdfSettings(#[from] KdfConfigError),
198
199    #[error(transparent)]
200    Io(#[from] std::io::Error),
201}
202
203/// Errors occurring when saving a Database
204#[derive(Debug, thiserror::Error)]
205pub enum DatabaseSaveError {
206    /// The current database version cannot be saved by this library
207    #[error("Saving this database version is not supported")]
208    UnsupportedVersion,
209
210    /// Error while writing out the inner XML database
211    #[error("Error while generating XML")]
212    Xml(#[from] xml::writer::Error),
213
214    /// General I/O issues while writing the database
215    #[error(transparent)]
216    Io(#[from] std::io::Error),
217
218    /// An error with the key occurred while writing the database
219    #[error(transparent)]
220    Key(#[from] DatabaseKeyError),
221
222    /// A cryptography error occurred while writing the database
223    #[error(transparent)]
224    Cryptography(#[from] CryptographyError),
225
226    /// An error getting randomness for keys occurred
227    #[error(transparent)]
228    Random(#[from] getrandom::Error),
229}
230
231/// Errors related to the database key
232#[derive(Debug, thiserror::Error)]
233pub enum DatabaseKeyError {
234    /// The key specified was incorrect, e.g. because of a wrong password
235    #[error("Incorrect key")]
236    IncorrectKey,
237
238    /// An error occurred in an underlying cryptographic operation while computing the key
239    #[error(transparent)]
240    Cryptography(#[from] CryptographyError),
241
242    /// An I/O error occurred while loading the keyfile
243    #[error(transparent)]
244    Io(#[from] std::io::Error),
245
246    /// An XML error occurred while loading the keyfile
247    #[error(transparent)]
248    Xml(#[from] xml::reader::Error),
249
250    /// The keyfile is invalid and did not contain a key
251    #[error("Could not obtain a key from the keyfile")]
252    InvalidKeyFile,
253
254    /// Could not get challenge response key.
255    #[cfg(feature = "challenge_response")]
256    #[error("Error with the challenge-response key: {0}")]
257    ChallengeResponseKeyError(String),
258}
259
260/// Errors with the configuration of the outer encryption
261#[derive(Debug, thiserror::Error)]
262pub enum OuterCipherConfigError {
263    #[error(transparent)]
264    Cryptography(#[from] CryptographyError),
265
266    #[error("Invalid outer cipher ID: {:?}", cid)]
267    InvalidOuterCipherID { cid: Vec<u8> },
268}
269
270/// Errors with the configuration of the inner encryption
271#[derive(Debug, thiserror::Error)]
272pub enum InnerCipherConfigError {
273    #[error(transparent)]
274    Cryptography(#[from] CryptographyError),
275
276    #[error("Invalid inner cipher ID: {}", cid)]
277    InvalidInnerCipherID { cid: u32 },
278}
279
280/// Errors with the configuration of the compression algorithm
281#[derive(Debug, thiserror::Error)]
282pub enum CompressionConfigError {
283    /// The identifier for the compression algorithm specified in the database is invalid
284    #[error("Invalid compression algorithm: {}", cid)]
285    InvalidCompressionSuite { cid: u32 },
286}
287
288/// Errors with the configuration of the Key Derivation Function
289#[derive(Debug, thiserror::Error)]
290pub enum KdfConfigError {
291    #[error("Invalid KDF version: {}", version)]
292    InvalidKDFVersion { version: u32 },
293
294    #[error("Invalid KDF UUID: {:?}", uuid)]
295    InvalidKDFUUID { uuid: Vec<u8> },
296
297    #[error(transparent)]
298    VariantDictionary(#[from] VariantDictionaryError),
299}
300
301/// Errors while performing cryptographic operations
302#[derive(Debug, thiserror::Error)]
303pub enum CryptographyError {
304    #[error(transparent)]
305    InvalidLength(#[from] cipher::InvalidLength),
306
307    #[error(transparent)]
308    Unpadding(#[from] cipher::block_padding::UnpadError),
309
310    #[error(transparent)]
311    Padding(#[from] cipher::inout::PadError),
312
313    #[error(transparent)]
314    Argon2(#[from] argon2::Error),
315}
316
317/// Errors reading from the HMAC block stream
318#[derive(Debug, thiserror::Error)]
319pub enum BlockStreamError {
320    #[error(transparent)]
321    Cryptography(#[from] CryptographyError),
322
323    #[error("Block hash mismatch for block {}", block_index)]
324    BlockHashMismatch { block_index: u64 },
325}
326
327/// Errors while parsing a `VariantDictionary`
328#[derive(Debug, thiserror::Error)]
329pub enum VariantDictionaryError {
330    #[error("Invalid variant dictionary version: {}", version)]
331    InvalidVersion { version: u16 },
332
333    #[error("Invalid value type: {}", value_type)]
334    InvalidValueType { value_type: u8 },
335
336    #[error("Missing key: {}", key)]
337    MissingKey { key: String },
338
339    #[error("Mistyped value: {}", key)]
340    Mistyped { key: String },
341
342    #[error("VariantDictionary did not end with null byte, when it should")]
343    NotTerminated,
344}
345
346/// Errors while parsing the XML document inside of a `KeePass` database
347#[derive(Debug, thiserror::Error)]
348pub enum XmlParseError {
349    #[error(transparent)]
350    Xml(#[from] xml::reader::Error),
351
352    #[error(transparent)]
353    Base64(#[from] base64::DecodeError),
354
355    #[error(transparent)]
356    TimestampFormat(#[from] chrono::ParseError),
357
358    #[error(transparent)]
359    IntFormat(#[from] std::num::ParseIntError),
360
361    #[error(transparent)]
362    BoolFormat(#[from] std::str::ParseBoolError),
363
364    #[error(transparent)]
365    Uuid(#[from] uuid::Error),
366
367    #[error(transparent)]
368    Color(#[from] ParseColorError),
369
370    #[error(transparent)]
371    Cryptography(#[from] CryptographyError),
372
373    #[error("Decompression error: {}", _0)]
374    Compression(#[source] std::io::Error),
375
376    /// An unexpected XML event occurred, such as opening an unexpected tag, or an error in the
377    /// underlying XML reader
378    #[error("Bad XML event: expected {}, got {:?}", expected, event)]
379    BadEvent {
380        expected: &'static str,
381        event: crate::xml_db::parse::SimpleXmlEvent,
382    },
383
384    /// The stream of XML events ended when more events were expected
385    #[error("Unexpected end of XML document")]
386    Eof,
387}
388
389/// Error parsing a color code
390#[derive(Debug, thiserror::Error)]
391#[error("Cannot parse color: '{}'", _0)]
392pub struct ParseColorError(pub String);
393
394// move error type conversions to a module and exclude them from coverage counting.
395mod conversions {
396    use super::{
397        BlockStreamError, CompressionConfigError, CryptographyError, DatabaseIntegrityError, DatabaseOpenError, InnerCipherConfigError,
398        KdfConfigError, OuterCipherConfigError, VariantDictionaryError, XmlParseError,
399    };
400
401    impl From<CryptographyError> for DatabaseOpenError {
402        fn from(e: CryptographyError) -> Self {
403            DatabaseIntegrityError::from(e).into()
404        }
405    }
406
407    impl From<BlockStreamError> for DatabaseOpenError {
408        fn from(e: BlockStreamError) -> Self {
409            DatabaseIntegrityError::from(e).into()
410        }
411    }
412
413    impl From<XmlParseError> for DatabaseOpenError {
414        fn from(e: XmlParseError) -> Self {
415            DatabaseIntegrityError::from(e).into()
416        }
417    }
418
419    impl From<InnerCipherConfigError> for DatabaseOpenError {
420        fn from(e: InnerCipherConfigError) -> Self {
421            DatabaseIntegrityError::from(e).into()
422        }
423    }
424
425    impl From<OuterCipherConfigError> for DatabaseOpenError {
426        fn from(e: OuterCipherConfigError) -> Self {
427            DatabaseIntegrityError::from(e).into()
428        }
429    }
430
431    impl From<KdfConfigError> for DatabaseOpenError {
432        fn from(e: KdfConfigError) -> Self {
433            DatabaseIntegrityError::from(e).into()
434        }
435    }
436
437    impl From<VariantDictionaryError> for DatabaseOpenError {
438        fn from(e: VariantDictionaryError) -> Self {
439            DatabaseIntegrityError::from(e).into()
440        }
441    }
442
443    impl From<CompressionConfigError> for DatabaseOpenError {
444        fn from(e: CompressionConfigError) -> Self {
445            DatabaseIntegrityError::from(e).into()
446        }
447    }
448}