Class: ActiveRecord::Encryption::Encryptor
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Inherits: | Object |
Defined in: | activerecord/lib/active_record/encryption/encryptor.rb |
Overview
An encryptor exposes the encryption API that EncryptedAttributeType
uses for encrypting and decrypting attribute values.
It interacts with a KeyProvider
for getting the keys, and delegate to Cipher
the actual encryption algorithm.
Constant Summary
-
DECRYPT_ERRORS =
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 93[OpenSSL::Cipher::CipherError, Errors::EncryptedContentIntegrity, Errors::Decryption]
-
ENCODING_ERRORS =
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 94[EncodingError, Errors::Encoding]
-
THRESHOLD_TO_JUSTIFY_COMPRESSION =
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 95140.bytes
Class Method Summary
-
.new(compress: true, compressor: nil) ⇒ Encryptor
constructor
Options.
Instance Attribute Summary
- #binary? ⇒ Boolean readonly
-
#compressor
readonly
The compressor to use for compressing the payload.
- #compress? ⇒ Boolean readonly Internal use only
Instance Method Summary
-
#decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
Decrypts an
encrypted_text
and returns the result as clean text. -
#encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
Encrypts
clean_text
and returns the encrypted result. -
#encrypted?(text) ⇒ Boolean
Returns whether the text is encrypted or not.
- #build_encrypted_message(clear_text, key_provider:, cipher_options:) private
- #cipher private
- #compress(data) readonly private
-
#compress_if_worth_it(string)
private
Under certain threshold, ZIP compression is actually worse that not compressing.
- #default_key_provider private
- #deserialize_message(message) private
- #force_encoding_if_needed(value) private
- #forced_encoding_for_deterministic_encryption private
- #serialize_message(message) private
- #serializer private
- #uncompress(data) private
- #uncompress_if_needed(data, compressed) private
- #validate_payload_type(clear_text) private
Constructor Details
.new(compress: true, compressor: nil) ⇒ Encryptor
Options
-
:compress
- Boolean indicating whether records should be compressed before encryption. Defaults totrue
. -
:compressor
- The compressor to use.-
If compressor is provided, it will be used.
-
If not, it will use ActiveRecord::Encryption.config.compressor which default value is
Zlib
.
If you want to use a custom compressor, it must respond to
deflate
andinflate
. -
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 25
def initialize(compress: true, compressor: nil) @compress = compress @compressor = compressor || ActiveRecord::Encryption.config.compressor end
Instance Attribute Details
#binary? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 84
def binary? serializer.binary? end
#compress? ⇒ Boolean
(readonly)
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 88
def compress? # :nodoc: @compress end
#compressor (readonly)
The compressor to use for compressing the payload
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 15
attr_reader :compressor
Instance Method Details
#build_encrypted_message(clear_text, key_provider:, cipher_options:) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 111
def (clear_text, key_provider:, cipher_options:) key = key_provider.encryption_key clear_text, was_compressed = compress_if_worth_it(clear_text) cipher.encrypt(clear_text, key: key.secret, ** ).tap do || .headers.add(key. ) .headers.compressed = true if was_compressed end end
#cipher (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 107
def cipher ActiveRecord::Encryption.cipher end
#compress(data) (readonly, private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 144
def compress(data) @compressor.deflate(data).tap do |compressed_data| compressed_data.force_encoding(data.encoding) end end
#compress_if_worth_it(string) (private)
Under certain threshold, ZIP compression is actually worse that not compressing
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 136
def compress_if_worth_it(string) if compress? && string.bytesize > THRESHOLD_TO_JUSTIFY_COMPRESSION [compress(string), true] else [string, false] end end
#decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
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 67
def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {}) = (encrypted_text) keys = key_provider.decryption_keys( ) raise Errors::Decryption unless keys.present? uncompress_if_needed(cipher.decrypt(, key: keys.collect(&:secret), ** ), .headers.compressed) rescue *(ENCODING_ERRORS + DECRYPT_ERRORS) raise Errors::Decryption end
#default_key_provider (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 97
def default_key_provider ActiveRecord::Encryption.key_provider end
#deserialize_message(message) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 125
def ( ) serializer.load rescue ArgumentError, TypeError, Errors::ForbiddenClass raise Errors::Encoding end
#encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
Encrypts clean_text
and returns the encrypted result
Internally, it will:
-
Create a new
Message
-
Compress and encrypt
clean_text
as the message payload -
Serialize it with
ActiveRecord::Encryption.message_serializer
(ActiveRecord::Encryption::SafeMarshal
by default) -
Encode the result with
::ActiveRecord::Base
64
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 49
def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {}) clear_text = force_encoding_if_needed(clear_text) if [:deterministic] validate_payload_type(clear_text) (clear_text, key_provider: key_provider, cipher_options: ) end
#encrypted?(text) ⇒ Boolean
Returns whether the text is encrypted or not
# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 77
def encrypted?(text) (text) true rescue Errors::Encoding, *DECRYPT_ERRORS false end
#force_encoding_if_needed(value) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 164
def force_encoding_if_needed(value) if forced_encoding_for_deterministic_encryption && value && value.encoding != forced_encoding_for_deterministic_encryption value.encode(forced_encoding_for_deterministic_encryption, invalid: :replace, undef: :replace) else value end end
#forced_encoding_for_deterministic_encryption (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 172
def forced_encoding_for_deterministic_encryption ActiveRecord::Encryption.config.forced_encoding_for_deterministic_encryption end
#serialize_message(message) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 121
def ( ) serializer.dump( ) end
#serializer (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 131
def serializer ActiveRecord::Encryption. end
#uncompress(data) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 158
def uncompress(data) @compressor.inflate(data).tap do |uncompressed_data| uncompressed_data.force_encoding(data.encoding) end end
#uncompress_if_needed(data, compressed) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 150
def uncompress_if_needed(data, compressed) if compressed uncompress(data) else data end end
#validate_payload_type(clear_text) (private)
[ GitHub ]# File 'activerecord/lib/active_record/encryption/encryptor.rb', line 101
def validate_payload_type(clear_text) unless clear_text.is_a?(String) raise ActiveRecord::Encryption::Errors::ForbiddenClass, "The encryptor can only encrypt string values (#{clear_text.class})" end end