KeePass Help Center KeePass Home | Downloads | Translations | Plugins | Donate 
Help Center Home | Forums | Awards | Links 







KDBX 4

Changes from the KDBX 3.1 file format to KDBX 4.


On this page, only the enhancements/changes from KDBX 3.1 to KDBX 4 are described. A complete specification of the latest format can be found here: KDBX File Format Specification.

Introduction

KeePass 2.35 introduces version 4 of the KDBX file format. This new format features both improvements and new capabilities. These are outlined in the following sections.

There are a few changes to the inner XML format since KDBX 3.1 (e.g. the HeaderHash meta element is obsolete now, see Improved Header Authentication; new CustomData element for entries and groups; new SettingsChanged element). The wrapping, binary format heavily changes. Furthermore, the order of encryption and data authentication changes.

Migration Phase. As not all major KeePass ports have finished adding support for KDBX 4 yet, for now KeePass 2.35 saves databases in this new format only when at least one of the following conditions is fulfilled:

  • AES-KDF is not selected as key derivation function (KDBX 3.1 only supports AES-KDF; any other key derivation function, like for instance Argon2, requires KDBX 4).
  • A plugin requests to store custom header data in the KDBX file.
  • A plugin requests to store custom data in an entry or a group.

Since KeePass 2.44, selecting ChaCha20 as file encryption algorithm also enforces the KDBX 4 format.

As soon as all major KeePass ports support KDBX 4, KeePass will always save in this format.


Argon2

As of KDBX 4, the Argon2 key derivation function can be used for transforming the master key (as protection against dictionary attacks).

Argon2 is the winner of the Password Hashing Competition. Up to KDBX 3.1, KeePass used AES-KDF, a key derivation function based on iterating the Advanced Encryption Standard (AES). The main advantage of Argon2 over AES-KDF is that it provides a better resistance against GPU/ASIC attacks (due to being a memory-hard function).

Users can now choose between AES-KDF and Argon2 in the database settings dialog (tab 'Security').

For Developers
The Argon2 implementation can be found in Argon2Kdf.Core.cs. The file Argon2Kdf.cs defines default values for parameters and implements methods for the key derivation infrastructure. Only the Argon2d variant of Argon2 is supported (a strong defense against GPU/ASIC cracking attacks is the most important goal, and Argon2d here is better than Argon2i; side-channel timing attacks are basically irrelevant, because KeePass is a local application, not a remote server).

KeePass' Argon2 implementation supports all parameters that are defined in the official specification, but only the number of iterations, the memory size and the degree of parallelism can be configured by the user in the database settings dialog. For the other parameters, KeePass chooses reasonable defaults: a 256-bit salt is generated by a CSPRNG each time a database is saved, the tag length is 256 bits, no secret key or associated data. All versions of Argon2d (1.0 to 1.3) are supported; KeePass uses the latest version 1.3 by default.


Extensible Key Derivation

Plugins can provide other key derivation functions (for transforming the master key) now.

For Developers
Up to KDBX 3.1, the number of rounds for AES-KDF was stored in the header field with ID 6 (TransformRounds), and the seed for the transformation was stored in the header field with ID 5 (TransformSeed). These two fields are obsolete now.

As of KDBX 4, key derivation function parameters are stored in the header field with ID 11 (KdfParameters). The parameters are serialized as a VariantDictionary (with the KDF UUID being stored in '$UUID'); see the files KdfParameters.cs and VariantDictionary.cs. For details on the parameters being used by AES-KDF and Argon2, see AesKdf.cs and Argon2Kdf.cs.

A VariantDictionary is a key-value dictionary (with the key being a string and the value being an object), which is serialized as follows:
  1. [2 bytes] Version, as UInt16, little-endian, currently 0x0100 (version 1.0). The high byte is critical (i.e. the loading code should refuse to load the data if the high byte is too high), the low byte is informational (i.e. it can be ignored).
  2. [n items] n serialized items (see below).
  3. [1 byte] Null terminator byte.
Each of the n serialized items has the following form:
  1. [1 byte] Value type, can be one of the following:
    • 0x04: UInt32.
    • 0x05: UInt64.
    • 0x08: Bool.
    • 0x0C: Int32.
    • 0x0D: Int64.
    • 0x18: String (UTF-8, without BOM, without null terminator).
    • 0x42: Byte array.
  2. [4 bytes] Length k of the key name in bytes, Int32, little-endian.
  3. [k bytes] Key name (string, UTF-8, without BOM, without null terminator).
  4. [4 bytes] Length v of the value in bytes, Int32, little-endian.
  5. [v bytes] Value. Integers are stored in little-endian encoding, and a Bool is one byte (false = 0, true = 1); the other types are clear.

For Developers
Up to KDBX 3.1, header field lengths were 2 bytes wide. As of KDBX 4, they are 4 bytes wide. This change makes the implementation of other key derivation functions possible, whose parameters may require more than 64 KB space. Furthermore, plugin-provided header data can be longer than 64 KB.


Improved Header Authentication

In KDBX 4, header data is authenticated using HMAC-SHA-256.

Up to KDBX 3.1, header data was authenticated using a SHA-256 hash stored in the encrypted part of the database file. The HMAC-SHA-256 approach used in KDBX 4 has various advantages. One advantage is that KeePass can verify the header before trying to decrypt the remaining part, which prevents trying to decrypt incorrect data.

For Developers
In KDBX 4, the HeaderHash element in the XML part is now obsolete and is not stored anymore. The new header authentication using HMAC-SHA-256 is mandatory.

Directly after the header, a (non-encrypted) SHA-256 hash of the header is stored (which allows the detection of unintentional corruptions, without knowing the master key). Directly after the hash, the HMAC-SHA-256 value of the header is stored.


Improved Data Authentication

In KDBX 4, a data block is authenticated via a HMAC-SHA-256 of the ciphertext (an Encrypt-then-MAC scheme).

Up to KDBX 3.1, a data block was authenticated by verifying a SHA-256 hash of the block after decrypting it (like a MAC-then-Encrypt scheme). Although the Encrypt-then-MAC scheme (KDBX 4) in general is considered to be more secure than a MAC-then-Encrypt scheme (KDBX 3.1), we do not believe that KDBX 3.1 files were insecure (because in the specific case of a KDBX file, the authenticated data blocks usually are large and a block cipher in CBC mode is used). Anyway, we believe it is a good idea to switch to the scheme that in general is considered to be the most secure (even if it doesn't actually make any real difference in the KDBX case). Furthermore, Encrypt-then-MAC has practical advantages. For example, one advantage is that KeePass can verify the authenticity of a data block before trying to decrypt it; this avoids block cipher padding exceptions (for KDBX 3.1, KeePass automatically translated these to file corruption exceptions; although this worked, detecting incorrect data before running into such exceptions is cleaner).

For Developers
For the stream that loads/saves data blocks authenticated using HMAC-SHA-256, see the new file HmacBlockStream.cs. This stream is similar to the HashedBlockStream used for KDBX 3.1, but uses a HMAC instead of just a hash. Furthermore, in KDBX 4 the HMAC is computed over the ciphertext, whereas in KDBX 3.1 plaintext hashes were computed (and then encrypted together with the plaintext).

The ith block produced by HmacBlockStream looks as follows:
  1. [32 bytes] HMAC-SHA-256 value (see below).
  2. [4 bytes] Block size n (in bytes, 0 indicates the last block, little-endian encoding).
  3. [n bytes] Block data C (ciphertext).
The HMAC is computed over inC (where little-endian encoding is used for the 64-bit sequence number i and the 32-bit block size n; i is implicit and does not need to be stored). The key for the HMAC is different for each block; it is computed as Ki := SHA-512(iK), where K is a 512-bit key derived from the user's master key and the master seed stored in the KDBX header.

After the header and its HMAC, the encrypted data follows, splitted into arbitrarily many blocks of the form above. When KeePass 2.35 writes a KDBX file, it uses n = 220, i.e. the encrypted data is splitted into 1 MB blocks.


Extensible Header

The header of KDBX 4 files is extensible by plugins.

For Developers
Plugin-provided header data is stored in the header field with ID 12. The value is a serialized VariantDictionary.

For Plugin Developers
Note that the header data is not encrypted and is only present in KDBX files (not in XML exports). Unless the additional header data really must be available without decryption, it is highly recommended that plugins store additional data in the CustomData dictionary of PwDatabase instead. CustomData is serialized in the XML part, i.e. for KDBX files it is encrypted, and it is also present in XML exports.


ChaCha20

Support for the ChaCha20 encryption algorithm (with 256-bit key and 96-bit nonce, as specified in RFC 7539/8439) has been added.

ChaCha20 is the successor of the Salsa20 algorithm (which is included in the eSTREAM portfolio).

It can be activated as KDBX file encryption algorithm in the database settings dialog.

Furthermore, ChaCha20 supersedes Salsa20 as default for generating the inner random stream of KDBX 4 files.

For Developers
Up to KDBX 3.1, the encryption IV stored in the KDBX header (field with ID 7, EncryptionIV) was always 16 bytes (128 bits) long. As of KDBX 4, the encryption IV length is retrieved from the cipher implementation and the KDBX header field stores an encryption IV of exactly this length. For ChaCha20, that is 12 bytes (96 bits).

For Plugin Developers
Encryption algorithm plugin developers, please note the following. The default IV length continues to be 16 bytes (128 bits). If your cipher engine implements the ICipherEngine2 interface, you can specify a different IV length via the IVLength property.

Via the KeyLength property of ICipherEngine2, you can specify a key length. The default continues to be 32 bytes (256 bits). If you specify a different key length, KeePass uses a cryptographically secure method to derive a key of the requested length from the master key.


Extensible Entries and Groups

Plugins can now store custom data in entries and groups.

Up to now, plugins for instance have stored custom data in string fields of entries. This worked, but cluttered up the entry string list and wasn't nice from a design point of view. As of KDBX 4, every entry and every group has a key-value dictionary, in which plugins can store their data.

For Developers
PwEntry and PwGroup now have a CustomData property. This property has the same type as CustomData of PwDatabase, and is serialized analogously (same XML structure).


Inner Header

KDBX 4 files have an inner, binary header. This header precedes the XML part; especially, it is compressed (if the compression option is turned on) and encrypted (which is the reason why we call it the inner header). Directly after the inner header, the XML part follows (in the same compression and encryption stream).

The inner header can store entry attachments, which is the primary motivation for the introduction of the inner header. Up to KDBX 3.1, entry attachments were encoded using Base64 and stored in the XML part. Compared to this, the KDBX 4 inner header approach results in a reduced database file size and improved loading/saving performance.

For Developers
The structure of the inner header is similar to the one of the outer header. It consists of arbitrarily many items of the following form:
  1. [1 byte] Item type.
  2. [4 bytes] Data length n (Int32, little-endian).
  3. [n bytes] Data D.
The following item types are supported:
  • 0x00: End of header.
  • 0x01: Inner random stream ID (this supersedes the inner random stream ID stored in the outer header of a KDBX 3.1 file).
  • 0x02: Inner random stream key (this supersedes the inner random stream key stored in the outer header of a KDBX 3.1 file).
  • 0x03: Binary (entry attachment). D = FM, where F is one byte and M is the binary content (i.e. the actual entry attachment data). F stores flags for the binary; supported flags are:
    • 0x01: The user has turned on process memory protection for this binary.
The inner header must end with an item of type 0x00 (and n = 0).


Page History

  • 1.0
    • Final version (no file format changes since 0.3, minor documentation improvements).
  • 0.3
  • 0.2
    • Directly after the KDBX 4 header, a (non-encrypted) SHA-256 hash of the header is stored now. This allows the detection of unintentional corruptions of the header (without knowing the master key). The hash has no effect on the security.
    • In encrypted KDBX 4 files (not in plaintext XML exports), all times are now stored as Base64 string of the Int64 number of seconds elapsed since 0001-01-01 00:00 UTC. This improves the performance and reduces the file size.
    • Entry attachments are now stored in an inner header.
    • The inner random stream cipher ID and key (to support process memory protection) are now stored in the inner header instead of in the outer header.
  • 0.1
    • Initial draft.








Get KeePass