class ActiveRecord::Encryption::Encryptor

An encryptor exposes the encryption API that ActiveRecord::Encryption::EncryptedAttributeType uses for encrypting and decrypting attribute values.

It interacts with a KeyProvider for getting the keys, and delegate to ActiveRecord::Encryption::Cipher the actual encryption algorithm.

Constants

DECRYPT_ERRORS
ENCODING_ERRORS
THRESHOLD_TO_JUSTIFY_COMPRESSION

This threshold cannot be changed.

Users can search for attributes encrypted with ‘deterministic: true`. That is possible because we are able to generate the message for the given clear text deterministically, and with that perform a regular string lookup in SQL.

Problem is, messages may have a “c” header that is present or not depending on whether compression was applied on encryption. If this threshold was modified, the message generated for lookup could vary for the same clear text, and searches on exisiting data could fail.

Attributes

The compressor to use for compressing the payload.

Public Class Methods

Options

:compress

Boolean indicating whether records should be compressed before encryption. Defaults to true.

:compressor

The compressor to use. It must respond to deflate and inflate. If not provided, will default to ActiveRecord::Encryption.config.compressor, which itself defaults to Zlib.

# File activerecord/lib/active_record/encryption/encryptor.rb, line 27
def initialize(compress: true, compressor: nil)
  @compress = compress
  @compressor = compressor || ActiveRecord::Encryption.config.compressor
end

Public Instance Methods

# File activerecord/lib/active_record/encryption/encryptor.rb, line 86
def binary?
  serializer.binary?
end

Decrypts an encrypted_text and returns the result as clean text.

Options

:key_provider

Key provider to use for the encryption operation. It will default to ActiveRecord::Encryption.key_provider when not provided.

:cipher_options

Cipher-specific options that will be passed to the Cipher configured in ActiveRecord::Encryption.cipher.

# File activerecord/lib/active_record/encryption/encryptor.rb, line 69
def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
  message = deserialize_message(encrypted_text)
  keys = key_provider.decryption_keys(message)
  raise Errors::Decryption unless keys.present?
  uncompress_if_needed(cipher.decrypt(message, key: keys.collect(&:secret), **cipher_options), message.headers.compressed)
rescue *(ENCODING_ERRORS + DECRYPT_ERRORS)
  raise Errors::Decryption
end

Encrypts clean_text and returns the encrypted result.

Internally, it will:

  1. Create a new ActiveRecord::Encryption::Message.

  2. Compress and encrypt clean_text as the message payload.

  3. Serialize it with ActiveRecord::Encryption.message_serializer (ActiveRecord::Encryption::SafeMarshal by default).

  4. Encode the result with Base64.

Options

:key_provider

Key provider to use for the encryption operation. It will default to ActiveRecord::Encryption.key_provider when not provided.

:cipher_options

Cipher-specific options that will be passed to the Cipher configured in ActiveRecord::Encryption.cipher.

# File activerecord/lib/active_record/encryption/encryptor.rb, line 51
def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
  clear_text = force_encoding_if_needed(clear_text) if cipher_options[:deterministic]

  validate_payload_type(clear_text)
  serialize_message build_encrypted_message(clear_text, key_provider: key_provider, cipher_options: cipher_options)
end

Returns whether the text is encrypted or not.

# File activerecord/lib/active_record/encryption/encryptor.rb, line 79
def encrypted?(text)
  deserialize_message(text)
  true
rescue Errors::Encoding, *DECRYPT_ERRORS
  false
end