KeePassX Database Format
This information was distilled from reading the source code of the KeePassX Project. So it could be wrong too.
The entire encrypted database is read into memory at the beginning checked to make sure that it is greater than the minimum size of just the DB_HEADER.
The Contents of the binary file format are in the general format of an unencrypted 124 byte header followed by the encrypted data. The encrypted data has 2 sections, the Groups section followed by the Entries section. The number of Groups and Entries are listed in the header.
Header
| Database Header fields, total byte length 124 | ||
|---|---|---|
| Signature 1 | 4 byte int LE order | constant: PWM_DBSIG_1 0×9AA2D903 |
| Signature 2 | 4 byte int LE order | constant: PWM_DBSIG_2 0xB54BFB65 |
| Flags | 4 byte int LE order | Determine what algorithms are used |
| Version | 4 byte int LE order | Version of the database format |
| Final Random Seed | 16 bytes | Initial random number to start on the sha256 of the key |
| Init Vector | 16 bytes | Initialization vector used for all algorithms |
| Num Groups | 4 byte int LE order | Number of Groups in the Groups portion of the data |
| Num Entries | 4 byte int LE order | Number of Entries in the Entries portion of the data |
| Content Hash | 32 bytes | |
| Transformed Random Seed | 32 bytes | Random seed used to combine with the master key when calculating the final key |
| Key Encoding Rounds | 4 byte int LE order | Number of rounds to do AES block encryption on the Master Key |
| Flags for ‘Flags’ variable in header | |
|---|---|
| PWM_FLAG_RIJNDAEL | use the AES algorithm for entries |
| PWM_FLAG_TWOFISH | use the twofish algorithm for entries |
| PWM_FLAG_ARCFOUR | use the arc for algorithm for entires (unused) |
| PWM_FLAG_SHA2 | use SHA256 for key stretching |
Groups section
Immediately following the Header, and part of the encrypted content is the Groups section. The number of Groups in the Groups section is in the header as Num Groups.
A Single Group is really a collection of all the Group records until the END OF GROUP record is encountered. Then this counts as 1 group.
Each record in Groups has the format:
| Group record format | ||
|---|---|---|
| Field Type | 2 byte int LE order | The type of the field, one of valid field types |
| Field Size | 4 byte int LE order | the number of bytes in the field’s data |
| Field data | N bytes of data | depends upon the Field Type |
And the Field Types and their associated Field Data Structures are :
| Field Type | Field Type | Field Data structure |
|---|---|---|
| Ignore | 0×0000 | Ignore the data |
| ID | 0×0001 | 4 byte int LE order |
| Name | 0×0002 | UTF 8 encoded string |
| Creation Date | 0×0003 | 5 bytes packed date for the creation date of the group |
| Last Modified | 0×0004 | 5 bytes packed date for the last modified date of the group |
| Last access | 0×0005 | 5 bytes packed date for the last access date of the group |
| Expiration | 0×0006 | 5 bytes packed date for the expiration date of the group |
| Image ID | 0×0007 | 4 byte int LE order, the id of an image for the group |
| Level | 0×0008 | 2 byte int LE order, the level of the group |
| Flags | 0×0009 | 4 byte int LE order, bitvector flags of the group |
| END OF GROUP | 0xffff | NA |
Entries section
Following the Groups section is the Entries section. The number of Entries in this section is listed in the file header as Num Entries.
A Single Entry is really a collection of all the Entry records until the END OF GROUP record is encountered. Then this counts as 1 entry.
Each record in Entries has the format:
| Entry record format | ||
|---|---|---|
| Field Type | 2 byte int LE order | The type of the field, one of valid field types |
| Field Size | 4 byte int LE order | the number of bytes in the field’s data |
| Field data | N bytes of data | depends upon the Field Type |
And the Field Types and their associated Field Data Structures are :
| Field Type | Field Type | Field Data structure |
|---|---|---|
| Ignore | 0×0000 | Ignore the data |
| UUID | 0×0001 | 16 byte UUID |
| group id | 0×0002 | Group id this entry belongs to |
| ImageID | 0×0003 | Image ID of the icon for this entry |
| Title | 0×0004 | UTF8 String with the title of this entry |
| URL | 0×0005 | UTF8 encoded string of a URL |
| User Name | 0×0006 | UTF8 encoded string of the username |
| Password | 0×0007 | UTF8 encoded string of the password |
| Additional | 0×0008 | UTF8 encoded string of additional data |
| Creation Date | 0×0009 | 5 bytes packed date for the creation date of the entry |
| Last Modified | 0×000A | 5 bytes packed date for the last modified date of the entry |
| Last Access | 0×000B | 5 bytes packed date for the last accessed date of the entry |
| Expiration | 0×000C | 5 bytes packed date for the expiration date of the entry |
| Binary Desc | 0×000D | Binary Description |
| Binary Data | 0×000E | Binary Data |
| END OF ENTRY | 0xffff | NA |
Encrypt/Decrypt Process
- P = user pass phrase
- MasterKey = SHA-256(P)
- TMasterKey = AES-encrypt(RandomSeed, MasterKey, Rounds)
- FMasterKey = SHA-256(TMasterKey,FinalRandomSeed)
- Plaintext = AES-decrypt(FMasterKey, IV, Cipher Text)
- ContentHash = SHA-256(Plaintext)
A Master Key is calculated with either a password or file or both. Depending on the combination of password and file or both a SHA256 has is created of the input password information.
This Master Key SHA256 is Encrypted Key Encoding Rounds times with AES using Transformed Random Seed as the initialization of the encryption process. This producess a Transformed Master Key. This key is hashed together with the Final Random Seed to create the Final Key used for encryption.
After the Final Key has been created, the contents are decrypted and a sha256 hash of the decrypted contents is compared to the Content Hash in the header.
Then Num Groups groups are read from the decrypted data stream. Following that Num Entries are read.
Once the Groups and Entries are decoded and stored, the meta data streams in the entries are filtered and removed from the entry data rightly.
| MetaData Entry Has | |
|---|---|
| BinaryData | not null |
| Additional | not the empty string |
| BinaryDesc | is “bin-stream” |
| Title | is “Meta-Info” |
| UserName | is “SYSTEM” |
| URL | is ”$” |
| ImageID | is 0 |