Keybox Database Format
The Keybox database is an instance of Keybox::Storage::Container serialized to YAML. The container is responsible for serializing and deserializing itself.
Initial Creation
When the Container is instantiated for the first time with a passphrase and the location to store the YAML file, 3 pieces of random data are generated.
- A 256 bit salt is generated and stored as plain text in the YAML file as the key_digest_salt.
- A 256 bit salt is generated and stored as plain text in the YAML file as the records_digest_salt.
- A 128 bit salt is generated and stored as plain text in the YAML file as the records_init_vector.
Encryption Process
- Generate the encryption key.
- Take the key_digest_salt and combine with the passphrase and run 2048 cycles of SHA-256 on the data. This creates a stretched key and is the actual encryption key.
- Calculate a key_digest by applying SHA-256 hash to the actual encryption key. This is stored in plain text the YAML file as key_digest
- Calcuate a records_digest.
- Take the records_digest_salt and combine with it the YAML serialization of the plain text records in the Container.
- Calculate a records_digest by applying the SHA-256 to the data from the previous step. This records_digest is stored in plain text in the YAML file.
- Encrypt the records using ruby’s OpenSSL interface (aes-256-cbc algorithm).
- Initialization vector is records_init_vector generated earlier
- The data encrypted is a YAML serialization of the records in the Keybox::Storage::Container.
The resulting YAML file has the following structure.
--- !ruby/object:Keybox::Storage::Container
creation_time: <Timestamp the Container was create>
modification_time: <Timestamp of the last container modification>
last_access_time: <Timestamp of the last container access>
data_members:
:key_digest_algorithm: sha256
:records_digest_salt: <256 bits of data>
:key_digest: <sha-256 hash>
:records_digest_algorithm: sha256
:version:
- 1
- 0
- 0
:records_digest: <sha-246 hash>
:records_init_vector: <128 bits of data>
:key_calc_iterations: 2048
:records_cipher_algorithm: aes-256-cbc
:key_digest_salt: <256 bits of dat>
:records_encrypted_data: <Encrypted Ddata>
uuid: !ruby/object:Keybox::UUID
bytes: <serialized uuid>
Decryption Process
- Deserialize the YAML file into a Keybox::Storage::Container
- Calculate the actual encryption key in the same manner as step 2 in the encryption process. The key_digest_salt is taken from the YAML file.
- Confirm that the passphrase given will decrypt this file by calculating the key_digest of the encryption key and validating that this calculated value matches the key_digest stored in the YAML file.
- Decrypt the records_encrypted_data field using the records_init_vector from the YAML file, the actual key calculated above and the OpenSSL libraries.
- Validate that the data decrypted is accurate by calculating a SHA-256 hash of the records_digest_salt and the decrypted data. Compare this with the records_digest from the YAML file to ensure that all the data was decrypted successfully.