Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Welcome to the KDBX compendium! This book is intended as an overview of the KeePass KDBX file format for developers implementing support for KeePass databases in their applications.

Notable KDBX format implementations

This book aims to compare different implementations of the KDBX file format, with direct references to the source code of each implementation. This is toidentify gotchas that developers might encounter.

Example: For Argon2, some implementationsKP, KP2A, STBX default to 2 lanes of parallelism, while some default to 4KPXC, KPDX, KPIU, . Libraries generally don’t have a default, and require the caller to specify the number of lanes.

GUI applications

ApplicationShortcodePlatformsLanguageNotes
KeePassKPWindows, (Linux, MacOS)C#No public git repo, will use unofficial mirror
KeePassXCKPXCWindows, Linux, MacOSC++
Keepass2AndroidKP2AAndroidJava
KeePassDXKPDXAndroidKotlin
KeePassiumKPIUiOSSwift
StrongboxSTBXiOS, macOSObjective-C, Swift

Libraries

LibraryShortcodeLanguageRead supportWrite supportNotes
pykeepassPYKPPythonKDBX3, KDBX4?
keepass-rsKPRSRustKDB, KDBX3, KDBX4, KDBX4.1experimental, KDBX4.1maintained by the author of this book
kdbxwebKDBWTypeScriptKDBX3, KDBX4, KDBX4.1KDBX3, KDBX4seems unmaintained, last commit Dec 2024

Other resources

Conventions in this Document

  • All byte offsets are zero-based, so the first byte of a structure is at offset 0.
  • All byte ranges are non-inclusive, so the byte range 0-4 includes bytes at offsets 0, 1, 2, and 3, but not the byte at offset 4.
  • All lengths are in bytes, so a length of 4 means that the value occupies 4 bytes.
  • All hexadecimal numbers are prefixed with 0x, so the number 255 will be represented as 0xFF.

KDBX file format

The KDBX format can be conceptually divided into two layers: the outer database with its header, and the compressed and encrypted HMAC block stream containing the inner database with its header.

Diagram kdbx-structure page 1

Encoding

  • All numbers are stored in little-endian format, so the 32-bit hex number 0x01234567 will be stored as the byte sequence 67 45 23 01
  • All boolean values are stored as a single byte, with 0x00 representing false and 0x01 representing true.
  • All UUIDs are stored as 16 bytes in big-endian format, so the UUID 123e4567-e89b-12d3-a456-426614174000 will be stored as the byte sequence 12 3E 45 67 E8 9B 12 D3 A4 56 42 66 14 17 40 00.
  • All strings are UTF-8 encoded, so the string Hello 😃 will be stored as the byte sequence 48 65 6C 6C 6F 20 F0 9F 98 83.

Outer database

The outer database consists of an identifier followed by the database version, then the outer header, and finally hashes and HMACs for integrity and password verification. After the outer database, the HMAC block stream begins, which contains the compressed and encrypted inner database.

Diagram kdbx-structure page 2

KDBX Identifier (4 bytes)

A KDBX file always starts with the bytes 03 D9 A2 9A corresponding to the little-endian encoding of the 32-bit hex number 0x9aa2d903. In the remainder of this chapter, numbers will be listed in their hex form, keep in mind that they are stored in little-endian format in the file.

Version (8 bytes)

The next 8 bytes are the version number, with the following structure:

Byte(s)Description
0-4Main version
KDB: 0xb54bfb65
KDB2: 0xb54bfb66
KDBX3 / KDBX4: 0xb54bfb67
4-6Minor version
KDBX4: 0x0000
KDBX4.1: 0x0001
6-8Major version
KDBX3: 0x0003
KDBX4: 0x0004

Outer header

The outer header consists of an arbitrary number of entries, each with the following structure:

Byte(s)Description
0Entry type ID
1-4Entry length
4-…Entry value

The header must be terminated by an entry with type 0x00 and length 0x00000000.

Diagram kdbx-structure page 3

Valid entry types are:

NameType IDTypeLengthDescription
End of header0-0Marks the end of the header
Outer encryption2UUID16The UUID of the encryption algorithm used for the HMAC block stream
Compression3UInt324The ID of the compression algorithm used for the inner database
Master seed4Bytes32The master seed used for key derivation
Encryption IV / nonce7Bytes16 or 12The initialization vector (IV) or nonce used for encryption.
AES-256 uses 16 bytes, ChaCha20 uses 12 bytes.
KDF parameters11VariantDictionaryVariableThe parameters for the key derivation function.
Public custom data12VariantDictionaryVariableUnencrypted custom data that may be used by applications.

Outer encryption

The outer encryption algorithm is used to encrypt the HMAC block stream. The outer encryption algorithm is specified by its UUID, which is stored in the outer header. The following outer encryption algorithms exist:

NameUUIDNotes
AES-12861ab05a1-9464-41c3-8d74-3a563df8dd35AES-128 in CBC mode with PKCS7 padding. This algorithm is deprecated.
AES-25631c1f2e6-bf71-4350-be58-05216afc5affAES-256 in CBC mode with PKCS7 padding.
Twofishad68f29f-576f-4bb9-a36a-d47af965346cTwofish in CBC mode with PKCS7 padding. This algorithm is deprecated.
ChaCha20d6038a2b-8b6f-4cb5-a524-339a31dbb59aChaCha20

Compression

The compression algorithm is used to compress the inner database before encryption. The compression algorithm is specified by its ID, which is stored in the outer header. The following compression algorithms exist:

NameIDNotes
None0No compression.
GZip1GZip compression.

Master seed and encryption IV / nonce

Every time a KDBX file is saved, a new random master seed and encryption IV / nonce should be generated.

KDF parameters

The parameters for the key derivation function (KDF) are stored in the outer header as a VariantDictionary.

Key derivation functions are identified by a UUID and are configured using a set of parameters. The following key derivation functions are defined:

NameUUIDNotes
AES-KDFKP,KPXCc9d9f39a-628a-4460-bf74-0d08c18a4fea[1]
Argon2dKP,KPXCef636ddf-8c29-444b-91f7-a9a403e30a0c
Argon2idKP,KPXC9e298b19-56db-4773-b23d-fc3ec6f0a1e6

[1]: There is an alternate AES-KDF UUID 7c02bb82-79a7-4ac0-927d-114a00648238 that should be recognized as AES-KDF, but databases should never be saved with this UUID.

The following parameters are defined:

KeyTypeKDFsDescription
$UUIDUUIDAllThe UUID of the key derivation function.
SByte[32]AES-KDFThe salt used for key derivation. This should be re-generated on every database save.
RUInt32AES-KDFThe number of rounds.
VUInt32Argon2The version number. This should be set to 0x13 for version 1.3 (recommended) or 0x10 for version 1.0.
SByte[]Argon2The salt used for key derivation. Minimum 8 bytes, maximum 0x3FFFFFFF bytes, 32 bytes recommended. This should be re-generated on every database save.
IUInt32Argon2The number of iterations. Minimum 1, maximum 0xFFFFFFFF
MUInt32Argon2The amount of memory in bytes. Minimum 8192, maximum 0x7FFFFFFF
PUInt32Argon2The degree of parallelism. Minimum 1, maximum 0x00FFFFFF

Public custom data

Public, unencrypted custom data stored as a VariantDictionary. The keys should be unique and prefixed with the name of the application, e.g. MyApplication_MyItem

VariantDictionary

Diagram kdbx-structure page 4

A variant dictionary is a typed key-value store used to store the parameters for the key derivation function and the public custom data in the outer header. It consists of an arbitrary number of entries, each with the following structure:

Byte(s)TypeDescription
0UInt8Value type ID
1-5UInt32Key length K
5-(5+K)StringKey
(5+K)-(5+K+4)UInt32Value length V
(5+K+4)-(5+K+4+V)BytesValue (type depends on value type ID)

Valid value type IDs are:

Type IDLengthDescription
0x044UInt32
0x058UInt64
0x081Boolean
0x0c4Int32
0x0d8Int64
0x18VariableString (UTF-8 encoded)
0x42VariableByte array

VariantDictionaries must be terminated by a single null byte (0x00).

Outer header verification

All data from the start of the KDBX file up to and including the end of the outer header is used to verify the integrity of the outer header by computing a SHA-256 hash of this data and comparing it to the hash stored after the outer header. A mismatch indicates that the file is corrupted.

Key derivation and verification

The outer header contains the parameters for the key derivation function (KDF) used to derive the master key from the user-provided secrets.

CompositeKey = SHA-256(concatenate-if-present(
    SHA256(masterPassword),
    keyFromKeyfile,
    keyFromKeyProvider,
    keyFromWindowsUserAccount
))

TransformedKey = KDF(CompositeKey)
MasterKey = SHA-256(concatenate(MasterSeed, TransformedKey))

The AES-KDF is simply a repeated encryption of the composite key with itself as the key. The number of rounds is determined by the R parameter in the KDF parameters. The result of the final round is hashed with SHA-256 to produce the transformed key.

The Argon2 KDFs are used with the parameters specified in the KDF parameters and a 32 byte output length to produce the transformed key.

The correctness of the master key is verified by computing the HMAC of the header data as follows:

HMACKey = SHA-512(concatenate(MasterSeed, TransfomedKey, 0x01))
HMACBlockKey = SHA-512(concatenate(0xFFFFFFFFFFFFFFFF, HMACKey))
CheckHMAC = HMAC(HMACBlockKey, headerData)

The data in CheckHMAC is compared to the data stored after the outer header hash. A mismatch indicates that the master key is incorrect.

HMAC block stream

The HMAC block stream is a stream of blocks (typically 1 MiB in sizeKP, KPXC) where each block is authenticated with an HMAC.

Diagram kdbx-structure page 5

For the i-th block, the HMAC key is verified as follows:

HMACBlockKey = SHA-512(concatenate(i as UInt64, HMACKey))
CheckHMac = HMAC(HMACBlockKey, blockData)

From HMAC block stream to inner database

The HMAC block stream is decrypted using the outer encryption algorithm specified in the outer header, resulting in the compressed inner database. The compressed inner database is then decompressed using the compression algorithm specified in the outer header, resulting in the inner database.

Inner database

The inner database is the result of decrypting and decompressing the HMAC block stream. It consists of the inner header and the XML database.

Diagram kdbx-structure page 6

Inner Header

The inner header consists of an arbitrary number of entries, each with the following structure:

Diagram kdbx-structure page 7

Byte(s)Description
0Entry type ID
1-4Entry length
4-…Entry value

The header must be terminated by an entry with type 0x00 and length 0x00000000.

Valid entry types are:

NameType IDTypeLengthDescription
End of header0-0Marks the end of the header
Inner encryption1UInt324The ID of the encryption algorithm used for the inner database
Inner encryption key2BytesVariableThe key used for encrypting the inner database. This should be re-generated on each database save.
Binary attachment3BytesVariableA binary file attachment

Inner encryption

Inner encryption is used to encrypt protected fields within the XML database. The inner encryption key is specified as a field of the inner header, and independent of the outer encryption key.

Valid inner encryption algorithm IDs are:

NameIDDescription
AES1AES encryption in CBC mode with PKCS7 padding.
Twofish2Twofish encryption in CBC mode with PKCS7 padding.
ChaCha203ChaCha20 encryption.

Binary attachments

Binary attachments are used to store binary files within the database. They are referenced in the XML database by their ID, which is the index of the binary attachment entry in the inner header.

Binary attachments have the following structure:

Byte(s)Description
0Flags. 0x01 indicates the binary content should be protected in process memory, but does not indicate that the content is encrypted in the file.
1-…Binary content

XML Database

The XML database is a UTF-8 encoded XML document that contains most actual data of the database, including groups, entries, and their fields. The structure of the XML database is defined by the KDBX XML Schema. This section fills in some details about the XML database that are important for implementors.

Value types

Some value types have special encoding rules within the XML database, which are described here.

(Nullable) Booleans

There are two boolean types in the XML database - TBool and TNullableBoolEx. TBool values are stored as the string True or False, while TNullableBoolEx values are stored as True, False, or the string Null.

Most boolean fields in the XML database are of type TBool, which means that an unspecified value will default to a field-specific default value. KP, KPXC

For TNullableBoolEx fields, an unspecified or Null value will be treated as inheriting the parent group’s value. The two fields of type TNullableBoolEx are EnableAutoType and EnableSearching. KP, KPXC

Colors

Colors are stored as RGB values in the format “#RRGGBB”. Empty strings should be treated as default values, chosen by the application. KP, KPXC

Example: an orangeish color could be expressed as #FF6600.

UUID values

UUID values are stored as 128-bit unsigned integers that are base64 encoded. KP, KPXC

Example: the UUID 00010203-0405-0607-0809-0a0b0c0d0e0f would be represented as the byte sequence 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f, which is base64 encoded as AAECAwQFBgcICQoLDA0ODw==.

Timestamps

Timestamps should be stored as seconds since the special epoch of 2000-01-01T00:00:00Z in UTC, as a 64-bit signed integer that is base64 encoded. KP, KPXC

Some older versions of the KDBX format used ISO 8601 datetime strings, so parsing from this format should be supported for backward compatibility.

Example: the timestamp 2000-01-01T00:00:01Z, one second after the epoch, would be stored as the byte sequence 01 00 00 00 00 00 00 00, which is base64 encoded as AQAAAAAAAA==.

DataTransferObfuscation aka AutoTypeObfuscation

DataTransferObfuscation is an integer-valued field for entries in the XML database. It corresponds to an enumeration of obfuscation methods used for AutoType:

ValueMethod
0No obfuscation
1Use clipboard

Protected values

Values in the XML database can be marked as protected with an attribute Protected="True". Protected values are stored as Base64-encoded encrypted data, using the encryption method and key specified in the inner header. There is also a ProtectInMemory="True" attribute, but it is only used for plaintext XML exports.

While some implementations allow protections on any field KPXC , the official KeePass implementation only allows the string and binary fields of entries to be protected KP

Attachment references

In KDBX4, attachments are stored as binary entries in the inner header, and referenced in the XML database by their ID, which is the index of the binary attachment entry in the inner header. In KDBX3, attachments are stored as Base64-encoded data with an optional Compressed="True" and Protected="True" attributes, and are not referenced by ID KP, KPXC .

KDBX4 example:

<Binary>
    <Key>myfile.txt</Key>
    <Value Ref="1"/>
</Binary>

KDBX3 example:

<Binary>
    <Key>myfile.txt</Key>
    <Value Compressed="True">H4sIAAAAAAAAA/NIzcnJVyjJyCxWAKLk/NyCotTi4tQUhZTEkkQuAFCFZIEeAAAA</Value>
</Binary>

Tags

Tags are stored as a single string with individual tags delimited by semicolons KP, KP2A, KPRS , though some implementations use commas instead KPXC, KPDX .

When parsing, the string should be split by commas, semicolons, and tab characters to ensure compatibility with different implementations KP, KPXC, KP2A, KPDX, KPRS , and whitespace around individual tags should be trimmed. Duplicates can be removed and the tags can be sorted alphabetically KP, KPXC, KP2A , though some implementations preserve the original order and don’t remove duplicates KPRS .

Suggestions for improvement

As implementors of the KDBX file format, we have identified several areas where the format could be improved in a future version. This chapter outlines some of these suggestions.

Many of the topics are drawn from the KDBX Standard Discussion (#6229) on the KeePassXC GitHub repository, where maintainers and developers of various KeePass-compatible clients discussed desired improvements to the KDBX format.

Serialize tags as XML elements

Instead of the heterogeneous way tags are processed from strings, the list of tags could be stored using XML elements, with one XML element per tag.

Identify attachments by UUIDs

Currently, attachments in the inner header are referenced in the XML database by their order of appearance. This is the only case where elements in the XML database are not identified by UUIDs, and having attachment UUIDs would simplify unambiguous identification of attachments, e.g. during merge operations.

Argon2id as the Standard KDF

The discussion proposed standardizing on Argon2id instead of Argon2d as the key derivation function. Argon2id is a hybrid variant that provides better resistance to both side-channel and GPU-based attacks compared to Argon2d alone, making it a stronger default choice for password databases.

Source: #6229 (opening post)

Password Modification Datetime

A dedicated timestamp recording when the password field of an entry was last changed was proposed as a “must have.” The use case is that the generic “last modified” timestamp of an entry changes whenever any field is edited — not just the password — so it cannot reliably track password age for rotation policies.

KeePass developer DReichl argued against adding this field, noting that: a user may create an entry for an account that predates the entry; a failed password-change attempt could result in an incorrect automatic timestamp; and KeePass already approximates this via a “Last Password Modification Time (Based on History)” column. KeePassXC maintainer droidmonkey disagreed, arguing that edge cases should not block a broadly useful feature and that the application can detect password field changes through text-change events.

Source: #6229 — DReichl, May 2021; droidmonkey reply

Built-in Entry Layout Specification

The format currently provides no standard way to describe how an entry’s fields should be presented in a UI. A built-in entry layout specification would allow clients to declare structured display templates for different entry types (e.g., credit cards, identity documents, SSH keys), ensuring consistent rendering across all KDBX-compatible applications.

Source: #6229 (opening post); related issue #863

Built-in TOTP Specification

Multiple incompatible TOTP implementations exist across the KeePass ecosystem: KeePass’s own multi-field approach, KeePassXC’s system, and various historical plugin formats. The proposal is to standardize on a single otp attribute using the widely-adopted otpauth:// URL format as the canonical representation.

KeePassXC maintainers confirmed they already prefer otpauth URLs and maintain legacy formats only for backwards compatibility. KeePass’s multi-field approach was criticized for being the only client to implement that particular scheme.

Source: #6229 — sirtao, Apr 2021; phoerious reply; droidmonkey reply

Built-in Hardware Key Specification

The proposal asks for a standardized way to specify hardware key (e.g., YubiKey) parameters as part of the KDBX credential set, including support for multiple hardware keys to allow backup keys. Currently each client implements hardware key support differently, preventing interoperability.

Related: Discussion #9506

Source: #6229 (opening post)

Built-in Quick Unlock Specification

The proposal asks for the KDBX format to define a standard quick unlock mechanism — allowing users to re-open a locked database with a shorter credential (e.g., a PIN or biometric) without repeating the expensive key derivation step. The implementation model would store the fully-derived database key encrypted in memory, with the quick unlock credential as the encryption key for that in-memory store.

KeePass developer DReichl argued the feature should remain application-level rather than database-level, because: different devices need different unlock methods; device capabilities vary; multiple open databases would create ambiguous unlock semantics; and the feature is inherently tied to the operating environment. KeePassDX developer J-Jamet provided a taxonomy of two technical approaches (in-memory re-encryption vs. OS credential store), noting both have different security trade-offs.

Source: #6229 — DReichl, Mar 2021; droidmonkey, Apr 2021; J-Jamet, Apr 2021

Built-in Favorites / Pinned Items

A standard mechanism to mark entries as “favorites” or “pinned” was proposed, allowing clients to surface important entries without requiring workarounds like special group names or tags. Some participants noted that tags can already serve this purpose and that a vendor-specific predefined tag (as done in Enpass) achieves the same effect, but a first-class standard field would ensure cross-client portability.

Source: #6229 (opening post); user858753257, Feb 2020

Key File Format Simplification

The proposal is to support only two key file formats going forward: plain binary key files, and the structured .key/.keyx XML format. Eliminating other ad-hoc formats would simplify implementation across clients and reduce the risk of weak key files being accepted.

Source: #6229 (opening post)

Multi-Valued Fields

Both core fields (e.g., URL) and custom fields should support multiple values natively within the KDBX schema, rather than requiring clients to invent their own conventions (e.g., URL2, KP2A_URL_1, WebDomain[1]). The lack of a standard for multiple values has led to divergent, incompatible implementations across clients.

A related problem raised in the discussion is that KeePassDX uses WebDomain / WebDomain[counter] while Keepass2Android uses KP2A_URL / KP2A_URL_<counter> for storing additional URLs, causing browser autofill failures when switching clients. Standardizing a single prefix — or natively supporting multiple URL values — would resolve this.

Source: #6229 (opening post); ghost comment, Nov 2020; related issues #398, #3558, KeePassDX #524

Passkey / WebAuthn Credential Storage

Strongbox developer strongbox-mark raised the need to standardize passkey (WebAuthn) credential storage across KeePass clients before incompatible implementations emerge. A de facto convention was already present in a KeePassXC work-in-progress PR: the private key is stored as a PEM file attachment named webauthn.pem, the WebAuthn-generated username is stored in the password field, and the user-chosen username/email is stored in the username field. Entries are identified as passkey entries by scanning for the webauthn.pem attachment name.

Open issues noted in the discussion include: how to export WebAuthn credentials portably for import into other password managers; and uncertainty about whether major browsers would expose APIs allowing third-party passkey providers.

Source: #6229 — strongbox-mark, Jan 2023; varjolintu reply; related PR #8825

Database-Level Transactional History

Currently, history is tracked at the entry level only. The proposal asks for transactional history at the database level, enabling undo of destructive operations such as entry deletions and group moves, and ensuring overall database consistency across operations. This would require the format to store a global change log rather than — or in addition to — per-entry history snapshots.

Source: #6229 (opening post)

Algorithms

Merging

Browser Extensions