KDBX Decryption Process#
To simplify the decryption steps, no data verification is performed during the decryption process.
- Enter the password and compute the SHA256 hash of the password to obtain the password hash value.
- Add the key file content to the password hash value and perform SHA256 hashing again. If there is no key file, perform SHA256 hashing on the password hash value again to obtain a new password hash value, which is SHA256(SHA256(password) + keyfile).
- Obtain the encryption algorithm KDF-related parameters from the file header. The default is AES-KDF. From the KDF parameters, obtain the KDF's Salt/seed and Rounds.
- Use the second SHA256 password hash value, along with the KDF's Salt/seed and Rounds, to perform AES-KDF calculations to obtain the transformed key.
- Obtain the Master salt/seed from the file header and perform SHA256 calculations with the transformed key to obtain the final decryption key.
- Obtain the Encryption IV/nonce from the file header and use the decryption key to perform AES decryption on the encrypted data.
- Decompress the decrypted data using Gzip to obtain the Inner Header and XML content. The password in the XML is encrypted using ChaCha20 by default.
- Obtain the Inner encryption key from the Inner Header, perform SHA512 hashing, where the hash string index from 0 to 31 bytes is the ChaCha20 key, and from 32 to 43 is the ChaCha20 encryption nonce.
- Decrypt the encrypted string using the ChaCha20 key and nonce to obtain the plaintext password. Since it is a stream cipher, decryption needs to be performed sequentially according to the order of the encrypted string.
Creating a KDBX File#
Use the KeePass client to create a KDBX file, using all default parameters. Open the KDBX file with a hex editor and split the file header as shown in the KeePass documentation KDBX File Format Specification - KeePass.
Hexadecimal Detailed Analysis#
1. Header#
The first 12 bytes of the file are divided into three groups, each group is of type UInt32, occupying four bytes, followed by multiple Fields.
Fields consist of id, value length, and value. The id is 1 byte, the value length is of type Int32, occupying 4 bytes, and the corresponding byte data is extracted as the value based on the value length.
For detailed file format specifications, refer to KDBX File Format Specification - KeePass.
KDBX files use little-endian byte order, and numeric types need to be read from right to left.
Signature1#
Signature1 is a fixed value 0x9AA2D903
, of type UInt32, occupying 4 bytes.
Signature2#
Signature2 is a fixed value 0xB54BFB67
, of type UInt32, occupying 4 bytes.
Format Version#
Format version is the file format version, of type UInt32, occupying 4 bytes. The current type is 0x00040000
, and the current version is 4.
Encryption Algorithm#
0x02
converted to Int32 is 2, id 2 corresponds to Encryption algorithm, indicating the encryption algorithm, of type UUID, length 0x00000010
converted to Int32 is 16, indicating a length of 16 bytes, UUID as a hexadecimal string, value is 31C1F2E6BF714350BE5805216AFC5AFF
, corresponding to AES-256 in the above image.
Compression Algorithm#
0x03
converted to Int32 is 3, id 3 corresponds to Compression algorithm, indicating the compression algorithm, of type UInt32, length 0x00000004
converted to Int32 is 4, indicating the value length for the next 4 bytes, hexadecimal 0x00000001
converted to UInt32 is 1
, indicating GZip compression is used.
Master Salt/Seed#
0x04
converted to Int32 is 4, id 4 corresponds to Master salt/seed, indicating the encryption salt/seed, of type 32-byte array, length 0x00000020
converted to Int32 is 32, indicating the value length for the next 32 bytes, corresponding byte array is [0xFA, 0xC9, 0x50, 0x39, 0x79, 0x5F, 0x19, 0x83, 0x21, 0x22, 0x8F, 0x24, 0x8F, 0x59, 0x63, 0xD5, 0x30, 0x38, 0x7A, 0x55, 0xD8, 0x08, 0xD5, 0x19, 0xC4, 0xD6, 0xEC, 0xEC, 0xEE, 0xDF, 0xA8, 0x24]
, which is the salt used for AES encryption.
KDF Parameters#
0x0B
converted to Int32 is 11, corresponding to KDF parameters, indicating the parameters for the Key Derivation Function (KDF), length 0x0000005D
converted to Int32 is 93, indicating the value consists of the next 93 characters, value type is Variant Dictionary, which can be understood as a special object structure, split into version information and an array of multiple dictionary objects, where each dictionary object consists of value type, name length, name, value length, and value.
The Variant Dictionary can be split as follows, the last byte 0x00
has no practical use.
KDF Format Version#
First is the version information of type UInt16, value is 0x0100
, occupying 2 bytes.
KDF UUID#
0x42
indicates []byte type, 0x000005
converted to Int32 is 5, indicating name length of 5 bytes, 0x2455554944
corresponds to ASCII string $UUID
, then 0x00000010
converted to Int32 is 16, indicating UUID length of 16 characters, corresponding hexadecimal string is C9D9F39A628A4460BF740D08C18A4FEA
, which uses AES-KDF by default.
KDF Rounds#
0x05
indicates UInt64 type, 0x000001
converted to Int32 is 1, indicating name length of 1 byte, 0x52
corresponds to ASCII character R
, value length 0x000008
converted to Int32 is 8, indicating Rounds value for the next 8 bytes, 0x00000000000927C0
converted to UInt64 is 600000, indicating the number of iterations is 600000.
KDF Salt/Seed#
0x42
indicates []byte type, 0x000001
converted to Int32 is 1, indicating name length of 1 byte, 0x53
corresponds to ASCII string S
, then 0x00000020
converted to Int32 is 32, indicating Salt/Seed length of 32 characters, corresponding byte array is [0x0C, 0x34, 0x88, 0x19, 0x8E, 0x90, 0xA3, 0x65, 0x40, 0xB4, 0x1C, 0x4E, 0xCC, 0x85, 0x5D, 0x11, 0xC3, 0x0A, 0x20, 0xD6, 0xF4, 0xAA, 0x20, 0xE4, 0xEC, 0xF3, 0xCF, 0xF3, 0xD9, 0x81, 0xC5, 0xED]
, which is also the salt used for KDF encryption.
Encryption IV/Nonce#
0x07
converted to Int32 is 7, id 7 corresponds to Encryption IV/nonce, indicating the initialization vector or random number for the encryption algorithm, length 0x00000010
converted to Int32 is 16, indicating the value consists of the next 16 bytes, the initialization vector is the byte array [0x6C, 0x77, 0x12, 0xF7, 0xE2, 0xD0, 0x2E, 0xAE, 0x63, 0x9D, 0x53, 0x92, 0xD6, 0x03, 0xFD, 0x08]
.
End of Header#
0x00
converted to Int32 is 0, id 0 corresponds to End of header, indicating the end of the header, length 0x00000004
converted to Int32 is 4, value consists of the next 4 bytes, which is a fixed value [0x0D, 0x0A, 0x0D, 0x0A]
.
2. SHA-256 Hash of the Header#
The 32 bytes after [0x0D, 0x0A, 0x0D, 0x0A]
are the SHA-256 hash value of the header, used to verify the integrity of the header information.
3. HMAC-SHA-256 Hash of the Header#
The 32 bytes after the hash of the header are the HMAC-SHA-256 value of the header, which requires the master key to complete the verification.
4. In HMAC-Protected Block Stream#
Unknown Data#
Unknown part, decryption and verification do not use this part of the data, and the documentation does not provide relevant explanations. Decryption needs to skip this part; otherwise, it will result in an error.
Encrypted Data#
The section until the end of the file is the encrypted part (the last four bytes 0x00000000
need to be removed). After decryption, Gzip compressed data is obtained, and the header of the Gzip compressed content is 0x1F8B
.
Gzip Decompress#
After performing Gzip decompression, the Inner Header and XML content are obtained.
Inner Header#
Inner Encryption Algorithm#
0x01
converted to Int32 is 1, id 1 corresponds to Inner encryption algorithm, indicating the internal encryption algorithm, length 0x00000004
converted to Int32 is 4, indicating a value length of 4 bytes, value 0x0000003
converted to Int32 is 3, indicating ChaCha20 encryption is used.
Inner Encryption Key#
0x02
converted to Int32 is 2, id 2 corresponds to Inner encryption key, indicating the internal encryption key, length 0x00000040
indicates a length of 64-byte array, which is [0x68, 0x34, 0xD6, 0x1D, 0xFA, 0x98, 0x64, 0xB1, 0x8A, 0x51, 0x05, 0xAB, 0x26, 0x10, 0x35, 0xC8, 0xB0, 0x22, 0xF5, 0x14, 0x91, 0x0F, 0x47, 0x8C, 0x3D, 0xE7, 0x63, 0x86, 0x9C, 0x87, 0xC1, 0x26, 0xC6, 0xB7, 0xDE, 0x59, 0x77, 0x3B, 0xC6, 0x13, 0xF7, 0x17, 0x6C, 0x05, 0x7E, 0x1C, 0xF3, 0xDC, 0x78, 0x25, 0x64, 0xCA, 0x44, 0x7E, 0xFD, 0xB4, 0x6F, 0xEB, 0x4D, 0xDC, 0xD5, 0x91, 0x7B, 0x5C]
.
The value here needs to be hashed using SHA512, and then the hash value array index from 0 to 31 is the key, and from 32 to 43 is the nonce.
XML Document#
The password in the XML document contains the Protected="True"
attribute, which needs to be Base64 decoded first, and then decrypted using ChaCha20. Since it is a stream cipher, the decryption of the subsequent passwords requires the previous password stream.