class SymmetricEncryption::Keystore::File

Constants

ALLOWED_PERMISSIONS

Attributes

file_name[RW]
key_encrypting_key[RW]

Public Class Methods

generate_data_key(key_path:, cipher_name:, app_name:, environment:, version: 0, dek: nil, **_args) click to toggle source

Returns [Hash] a new keystore configuration after generating the data key.

Increments the supplied version number by 1.

# File lib/symmetric_encryption/keystore/file.rb, line 12
def self.generate_data_key(key_path:, cipher_name:, app_name:, environment:, version: 0, dek: nil, **_args)
  version >= 255 ? (version = 1) : (version += 1)

  dek ||= SymmetricEncryption::Key.new(cipher_name: cipher_name)
  kek = SymmetricEncryption::Key.new(cipher_name: cipher_name)
  kekek = SymmetricEncryption::Key.new(cipher_name: cipher_name)

  dek_file_name = ::File.join(key_path, "#{app_name}_#{environment}_v#{version}.encrypted_key")
  new(key_filename: dek_file_name, key_encrypting_key: kek).write(dek.key)

  kekek_file_name = ::File.join(key_path, "#{app_name}_#{environment}_v#{version}.kekek")
  new(key_filename: kekek_file_name).write(kekek.key)

  {
    keystore:           :file,
    cipher_name:        dek.cipher_name,
    version:            version,
    key_filename:       dek_file_name,
    iv:                 dek.iv,
    key_encrypting_key: {
      encrypted_key:      kekek.encrypt(kek.key),
      iv:                 kek.iv,
      key_encrypting_key: {
        key_filename: kekek_file_name,
        iv:           kekek.iv
      }
    }
  }
end
new(key_filename:, key_encrypting_key: nil) click to toggle source

Stores the Encryption key in a file. Secures the Encryption key by encrypting it with a key encryption key.

# File lib/symmetric_encryption/keystore/file.rb, line 44
def initialize(key_filename:, key_encrypting_key: nil)
  @file_name          = key_filename
  @key_encrypting_key = key_encrypting_key
end

Public Instance Methods

read() click to toggle source

Returns the Encryption key in the clear.

# File lib/symmetric_encryption/keystore/file.rb, line 50
def read
  unless ::File.exist?(file_name)
    raise(SymmetricEncryption::ConfigError,
          "Symmetric Encryption key file: '#{file_name}' not found")
  end
  unless correct_permissions?
    raise(SymmetricEncryption::ConfigError,
          "Symmetric Encryption key file '#{file_name}' has the wrong "\
          "permissions: #{::File.stat(file_name).mode.to_s(8)}. Expected 100600 or 100400.")
  end
  unless owned?
    raise(SymmetricEncryption::ConfigError,
          "Symmetric Encryption key file '#{file_name}' has the wrong "\
          "owner (#{stat.uid}) or group (#{stat.gid}). "\
          "Expected it to be owned by current user "\
          "#{ENV['USER'] || ENV['USERNAME']}.")
  end

  data = read_from_file(file_name)
  key_encrypting_key ? key_encrypting_key.decrypt(data) : data
end
write(key) click to toggle source

Encrypt and write the key to file.

# File lib/symmetric_encryption/keystore/file.rb, line 73
def write(key)
  data = key_encrypting_key ? key_encrypting_key.encrypt(key) : key
  write_to_file(file_name, data)
end

Private Instance Methods

correct_permissions?() click to toggle source

Returns true if the file is owned by the user running this code and it has the correct mode - readable and writable by its owner and no one else, much like the keys one has in ~/.ssh

# File lib/symmetric_encryption/keystore/file.rb, line 83
def correct_permissions?
  ALLOWED_PERMISSIONS.include?(stat.mode.to_s(8))
end
owned?() click to toggle source
# File lib/symmetric_encryption/keystore/file.rb, line 87
def owned?
  stat.owned?
end
stat() click to toggle source
# File lib/symmetric_encryption/keystore/file.rb, line 91
def stat
  ::File.stat(file_name)
end