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