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

  1. Generate the encryption key.
    1. 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.
    2. 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
  2. Calcuate a records_digest.
    1. Take the records_digest_salt and combine with it the YAML serialization of the plain text records in the Container.
    2. 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.
  3. 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

  1. Deserialize the YAML file into a Keybox::Storage::Container
  2. 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.
  3. 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.
  4. Decrypt the records_encrypted_data field using the records_init_vector from the YAML file, the actual key calculated above and the OpenSSL libraries.
  5. 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.