Password Safe v3 Database Format

The PasswordSafe file format is fully described in the formatV3.txt that ships with the source code for PasswordSafe. It is summarized here. The users’ pass phrase is denoted as P’.

The general format is a Header followed by individual content Records followed by an EOF record and a message digest of the Content records.

File Format

Header Fields
TAG 4 bytes The 4 ASCII Chacters ‘PWS3’
SALT 32 bytes 256 random bit value generated at file creation
ITER 32 bit LE value number of rounds in the key stretch algorithm
H(P’) 32 bytes SHA-256 of the user’s passphrase
B1 16 bytes Encrypted 128 random value using P’ with Twofish algorithm
B2 16 bytes Encrypted 128 random value using P’ with Twofish algorithm
B3 16 bytes Encrypted 128 random value using P’ with Twofish algorithm
B4 16 bytes Encrypted 128 random value using P’ with Twofish algorithm
Init Vector 16 bytes 128 bit random value that is the Initiazliation Vector for the content’s encryption
Header N bytes General information for the database
Records N bytes The records in the database
EOF unencrypted string “PWS3-EOFPWS3-EOF”
HMAC 32 bytes 256 bit SHA-256 hash of the plaintext contents, starting with the version number in the header and ending with the last field of the last record

Field data in Password Safe

A field record in PasswordSafe V3 has a length in blocks, where each block has a length that is dependent upon the block size of the underlying encryption algorithm. In the case of Password Safe that is TwoFish.

If the record’s data does not fit directly into ‘block’ size chunks then it is padded with random data.

A record starts with a 4 byte LE integer of the length of the data. The first byte of the data is a 1 byte type identifier.

Header (HDR)

Name Type Data format
Version 0×00 2 byte LE of the database format
UUID 0×01 16 byte UUID of the database used for synchronization
Prefs 0×02 Preferens for the application in a particular format, ignore
Tree Status 0×03 Display status for the tree of data, ignore
last save 0×04 32 bit, LE unsigned int. epoch time.
last save by 0×05 text string nnnnu…uh…h where N’s forms length of u..u
last save what 0×06 text string Application that last saved data
end of entry 0xff empty

Records

Name Type Data format
UUID 0×01 16 byte UUID of the database used for synchronization
Group 0×02 Text
title 0×03 Text
Username 0×04 Text
Notes 0×05 Text
Password 0×06 Text
Creation Time 0×07 time_t 32 bit, LE unsigned int, epoch time
Pass Mod time 0×08 time_t 32 bit, LE unsigned int, epoch time
Last access 0×09 time_t 32 bit, LE unsigned int, epoch time
Password Life 0×0A time_t 32 bit, LE unsigned int, epoch time – how long before regen of password
Password Policy 0×0B 4 bytes, ignore
Mod Time 0×0C time_t, last time any field of this field was updated, created, etc
URL 0×0D Text
Autotype 0×0E What keyboard patterns to type if autotype is turned on
Password History 0×0F Text, history encoded in a format
End of Entry 0xFF empty

Encrypt/Decrypt process

The decrypted B1 + B2 form a 256 bit random key K that is used to encrypt the actual records

The decrypted B3 + B4 form a 256 bit random key L that is used to calculate the HMAC of the encrypted data. This is the message digest at the end of the file.

  1. Set P = user passphrase
  2. Stretch P to P’ with the SHA-256 algorithm
  3. Decrypt B1 and B2 using Twofish in ECB mode. K = D(P’,B1) + D(P’,B2).
  4. Decrypt B3 and B4 using Twofish in ECB mode. L = D(P’,B3) + D(P’,B4).
  5. Initialize Another TwoFish cipher with IV
  6. Decrypt rest of data up to EOF marker with TwoFish instance using K as the key.
    • Plaintext = TwoFish (IV,K,CipherText)
  7. Verify final HMAC == HMAC (L,PlainText).