Skip to content

KDBX v2 File Format

Stoom edited this page Jan 10, 2017 · 1 revision

Kdbx File Format

+-------------------------------------------------------------------+
|  4  |  4  |  4  |1| 2 | ... | x{3} |     32     | ...             |
+--+-----+-----+---+--+----+-----+---------+---------+--------------+
   |     |     |   |  |    |     |         |         |
   |     |     |   |  |    |     |         |         +-> Xml document (could be encrypted)
   |     |     |   |  |    |     |         +-> Stream start bytes (must match header correlating header)
   |     |     |   |  |    |     +-> Repeat of header fields until EOH type
   |     |     |   |  |    +->Header Field Data
   |     |     |   |  +-> Header Field Size
   |     |     |   +-> Header Field Type
   |     |     +-> File Ver
   |     +-> Sig 2
   +-> Sig 1

Signatures:

       |   kdb      |  kdbx pre-rel | kdbx relese |
byte 1 | 0x9aa2d903 | 0x9aa2d903    | 0x9aa2d903  |
byte 2 | 0xb54bfb65 | 0xb54bfb66    | 0xb54bfb67  |

File Version:

  • Looks to be keepass version split (major version upper 2 bytes, minor version lower 2 bytes)
  • Mask is 0xffff0000 to split major and minor version
  • Comment says only lower bytes are important and saved file version cannot be greater than fixed value in release (0x00030001)
  • Max version so far is 3.01 (from lib/ser/kdbsfile.cs:80)

Header Fields:

Entire header is hashed with SHA-256.

Cipher ID (16 bytes) (1st field)

UUID custom class that bases new identifiers off of the Guid class

Compression Flags (4 bytes) (2nd field)
0: No compression
1: Gzip compression

Not really a flag...

Master Seed (32 bytes) (3rd field)
Transform Seed (32 bytes) (4th field)
Transform Rounds (8 bytes) (5th field)

Number of rounds to transform key.

Encryption IV (16 bytes) (6th field)
Protected Stream Key (32 bytes) (7th field)
StreamStartBytes (32 bytes) (8th field)

Random data.

Inner Random Stream ID (4 bytes) (9th field)
End Of Header (4 bytes) (10th field)
0x13101310

Stream Decryptor:

A memory stream is used to build the byte array to create a SHA-256 hash.

+----------+----------+
|    32    |    32    |
+-----+----+-----+----+
      |          |
      |          +-> GenerateKey32 (Transform Seed by Rounds) (Kdbx.Read.cs:332)
      +-> Master Seed

The hashed is stored in an variable named aseKey and is feed into KeePass's ICipherEngine along with the IV to decrypt the stream.

Xml Format:

<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<KeePassFile>
  <Meta>
    <Generator>string</Generator>
    <HeaderHash>base64=</HeaderHash>
    <DatabaseName />
    <DatabaseNameChanged>yyyy-mm-ddThh:mm:ssZ</DatabaseNameChanged>
    <DatabaseDescription />
    <DatabaseDescriptionChanged>yyyy-mm-ddThh:mm:ssZ</DatabaseDescriptionChanged>
    <DefaultUserName />
    <DefaultUserNameChanged>yyyy-mm-ddThh:mm:ssZ</DefaultUserNameChanged>
    <MaintenanceHistoryDays>int</MaintenanceHistoryDays>
    <Color />
    <MasterKeyChanged>yyyy-mm-ddThh:mm:ssZ</MasterKeyChanged>
    <MasterKeyChangeRec>int</MasterKeyChangeRec>
    <MasterKeyChangeForce>int</MasterKeyChangeForce>
    <MemoryProtection>
      <ProtectTitle>bool</ProtectTitle>
      <ProtectUserName>bool</ProtectUserName>
      <ProtectPassword>bool</ProtectPassword>
      <ProtectURL>bool</ProtectURL>
      <ProtectNotes>bool</ProtectNotes>
    </MemoryProtection>
    <RecycleBinEnabled>bool</RecycleBinEnabled>
    <RecycleBinUUID>base64==</RecycleBinUUID>
    <RecycleBinChanged>yyyy-mm-ddThh:mm:ssZ</RecycleBinChanged>
    <EntryTemplatesGroup>base64==</EntryTemplatesGroup>
    <EntryTemplatesGroupChanged>yyyy-mm-ddThh:mm:ssZ</EntryTemplatesGroupChanged>
    <HistoryMaxItems>int</HistoryMaxItems>
    <HistoryMaxSize>int</HistoryMaxSize>
    <LastSelectedGroup>base64==</LastSelectedGroup>
    <LastTopVisibleGroup>base64==</LastTopVisibleGroup>
    <Binaries />
    <CustomData />
  </Meta>
  <Root>
    <Group>
      <UUID>base64==</UUID>
      <Name>string</Name>
      <Notes />
      <IconID>int</IconID>
      <Times>
        <CreationTime>yyyy-mm-ddThh:mm:ssZ</CreationTime>
        <LastModificationTime>yyyy-mm-ddThh:mm:ssZ</LastModificationTime>
        <LastAccessTime>yyyy-mm-ddThh:mm:ssZ</LastAccessTime>
        <ExpiryTime>yyyy-mm-ddThh:mm:ssZ</ExpiryTime>
        <Expires>bool</Expires>
        <UsageCount>int</UsageCount>
        <LocationChanged>yyyy-mm-ddThh:mm:ssZ</LocationChanged>
      </Times>
      <IsExpanded>bool</IsExpanded>
      <DefaultAutoTypeSequence />
      <EnableAutoType>null</EnableAutoType>
      <EnableSearching>null</EnableSearching>
      <LastTopVisibleEntry>base64==</LastTopVisibleEntry>
      <Entry>
        <UUID>base64==</UUID>
        <IconID>int</IconID>
        <ForegroundColor />
        <BackgroundColor />
        <OverrideURL />
        <Tags />
        <Times>
          <CreationTime>yyyy-mm-ddThh:mm:ssZ</CreationTime>
          <LastModificationTime>yyyy-mm-ddThh:mm:ssZ</LastModificationTime>
          <LastAccessTime>yyyy-mm-ddThh:mm:ssZ</LastAccessTime>
          <ExpiryTime>yyyy-mm-ddThh:mm:ssZ</ExpiryTime>
          <Expires>bool</Expires>
          <UsageCount>int</UsageCount>
          <LocationChanged>yyyy-mm-ddThh:mm:ssZ</LocationChanged>
        </Times>
        <String>
          <Key>Notes</Key>
          <Value>string</Value
        </String>
        <String>
          <Key>Password</Key>
          <Value Protected="True">base64=</Value>
        </String>
        <String>
          <Key>Title</Key>
          <Value>string</Value>
        </String>
        <String>
          <Key>URL</Key>
          <Value>string</Value>
        </String>
        <String>
          <Key>UserName</Key>
          <Value>string</Value>
        </String>
        <AutoType>
          <Enabled>bool</Enabled>
          <DataTransferObfuscation>int</DataTransferObfuscation>
        </AutoType>
        <History />
      </Entry>
      <Entry>
        ........
      </Entry>
      <Group>
          <UUID>base64==</UUID>
          <Name>string</Name>
          <Notes />
          <IconID>int</IconID>
          <Times>
            <CreationTime>yyyy-mm-ddThh:mm:ssZ</CreationTime>
            <LastModificationTime>yyyy-mm-ddThh:mm:ssZ</LastModificationTime>
            <LastAccessTime>yyyy-mm-ddThh:mm:ssZ</LastAccessTime>
            <ExpiryTime>yyyy-mm-ddThh:mm:ssZ</ExpiryTime>
            <Expires>bool</Expires>
            <UsageCount>int</UsageCount>
            <LocationChanged>yyyy-mm-ddThh:mm:ssZ</LocationChanged>
          </Times>
          <IsExpanded>bool</IsExpanded>
          <DefaultAutoTypeSequence />
          <EnableAutoType>null</EnableAutoType>
          <EnableSearching>null</EnableSearching>
          <LastTopVisibleEntry>base64==</LastTopVisibleEntry>
          <Entry>
            .......
          </Entry>
        </Group>
        <Group>
          .....
        </Group>
    <DeletedObjects>
      <DeletedObject>
         <UUID>base64==</UUID>
         <DeletionTime>yyyy-mm-ddThh:mm:ssZ</DeletionTime>
      </DeletedObject>
      <DeletedObject>
        .....
      </DeletedObject>
    </DeletedObjects>
  </Root>
</KeePassFile>

####Notes: Look into CryptoRandom class.

Clone this wiki locally
You can’t perform that action at this time.