123456789_123456789_123456789_123456789_123456789_

Class: Mongo::Crypt::ExplicitEncrypter Private

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Forwardable
Inherits: Object
Defined in: lib/mongo/crypt/explicit_encrypter.rb

Overview

An ExplicitEncrypter is an object that performs explicit encryption operations and handles all associated options and instance variables.

Class Method Summary

Instance Method Summary

Constructor Details

.new(key_vault_client, key_vault_namespace, kms_providers, kms_tls_options, timeout_ms = nil, key_expiration_ms = nil) ⇒ ExplicitEncrypter

Create a new ExplicitEncrypter object.

Parameters:

  • key_vault_client (Mongo::Client)

    An instance of ::Mongo::Client to connect to the key vault collection.

  • key_vault_namespace (String)

    The namespace of the key vault collection in the format "db_name.collection_name".

  • kms_providers (Crypt::KMS::Credentials)

    A hash of key management service configuration information.

  • kms_tls_options (Hash)

    TLS options to connect to KMS providers. Keys of the hash should be KSM provider names; values should be hashes of TLS connection options. The options are equivalent to TLS connection options of ::Mongo::Client.

  • timeout_ms (Integer | nil) (defaults to: nil)

    ::Mongo::Timeout for every operation executed on this object.

  • key_expiration_ms (Integer | nil) (defaults to: nil)

    The lifetime of the data encryption key cache, in milliseconds. A value of 0 means the cache never expires. When nil, libmongocrypt's default of 60000 is used.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 43

def initialize(
  key_vault_client, key_vault_namespace, kms_providers, kms_tls_options,
  timeout_ms = nil, key_expiration_ms = nil
)
  Crypt.validate_ffi!
  @crypt_handle = Handle.new(
    kms_providers,
    kms_tls_options,
    explicit_encryption_only: true,
    key_expiration_ms: key_expiration_ms
  )
  @encryption_io = EncryptionIO.new(
    key_vault_client: key_vault_client,
    metadata_client: nil,
    key_vault_namespace: key_vault_namespace
  )
  @timeout_ms = timeout_ms
end

Instance Method Details

#add_key_alt_name(id, key_alt_name) ⇒ BSON::Document | nil

Adds a key_alt_name for the key in the key vault collection with the given id.

Parameters:

  • id (BSON::Binary)

    ::Mongo::Id of the key to add new key alt name.

  • key_alt_name (String)

    New key alt name to add.

Returns:

  • (BSON::Document | nil)

    Document describing the identified key before adding the key alt name, or nil if no such key.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 218

def add_key_alt_name(id, key_alt_name)
  @encryption_io.add_key_alt_name(id, key_alt_name, timeout_ms: @timeout_ms)
end

#create_and_insert_data_key(master_key_document, key_alt_names, key_material = nil) ⇒ BSON::Binary

Generates a data key used for encryption/decryption and stores that key in the KMS collection. The generated key is encrypted with the KMS master key.

Parameters:

  • master_key_document (Mongo::Crypt::KMS::MasterKeyDocument)

    The master key document that contains master encryption key parameters.

  • key_alt_names (Array<String> | nil)

    An optional array of strings specifying alternate names for the new data key.

  • key_material (String | nil) (defaults to: nil)

    Optional 96 bytes to use as custom key material for the data key being created. If key_material option is given, the custom key material is used for encrypting and decrypting data.

Returns:

  • (BSON::Binary)

    The 16-byte UUID of the new data key as a BSON::Binary object with type :uuid.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 77

def create_and_insert_data_key(master_key_document, key_alt_names, key_material = nil)
  data_key_document = Crypt::DataKeyContext.new(
    @crypt_handle,
    @encryption_io,
    master_key_document,
    key_alt_names,
    key_material
  ).run_state_machine(timeout_holder)

  @encryption_io.insert_data_key(
    data_key_document, timeout_ms: timeout_holder.remaining_timeout_ms!
  ).inserted_id
end

#decrypt(value) ⇒ Object

Decrypts a value that has already been encrypted

Parameters:

  • value (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) that will be decrypted

Returns:

  • (Object)

    The decrypted value

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 203

def decrypt(value)
  Crypt::ExplicitDecryptionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: value }
  ).run_state_machine(timeout_holder)['v']
end

#delete_key(id) ⇒ Operation::Result

Removes the key with the given id from the key vault collection.

Parameters:

  • id (BSON::Binary)

    ::Mongo::Id of the key to delete.

Returns:

  • (Operation::Result)

    The response from the database for the delete_one operation that deletes the key.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 228

def delete_key(id)
  @encryption_io.delete_key(id, timeout_ms: @timeout_ms)
end

#encrypt(value, options) ⇒ BSON::Binary

Note:

The :key_id and :key_alt_name options are mutually exclusive. Only one is required to perform explicit encryption.

Encrypts a value using the specified encryption key and algorithm

Parameters:

  • value (Object)

    The value to encrypt

  • options (Hash)

Options Hash (options):

  • :key_id (BSON::Binary)

    A BSON::Binary object of type :uuid representing the UUID of the encryption key as it is stored in the key vault collection.

  • :key_alt_name (String)

    The alternate name for the encryption key.

  • :algorithm (String)

    The algorithm used to encrypt the value. Valid algorithms are "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "Indexed", "Unindexed", "Range", "String".

  • :contention_factor (Integer | nil)

    Contention factor to be applied if encryption algorithm is set to "Indexed", "Range", or "String". If not provided, it defaults to a value of 0. Contention factor should be set only if encryption algorithm is set to "Indexed", "Range", or "String".

  • :query_type (String | nil)

    Query type to be applied if encryption algorithm is set to "Indexed", "Range", or "String". Allowed values are "equality" (for "Indexed"), "range" (for "Range"), and "prefix", "suffix", "substring" (for "String").

  • :range_opts (Hash | nil)

    Specifies index options for a Queryable Encryption field supporting "range" queries. Required when algorithm is "Range".

  • :string_opts (Hash | nil)

    Specifies index options for a Queryable Encryption field supporting "prefix", "suffix", or "substring" queries. Required when algorithm is "String".

Returns:

  • (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) representing the encrypted value

Raises:

  • (ArgumentError)

    if either contention_factor or query_type is set, and algorithm is not "Indexed", "Range", or "String".

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 128

def encrypt(value, options)
  Crypt::ExplicitEncryptionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: value },
    options
  ).run_state_machine(timeout_holder)['v']
end

#encrypt_expression(expression, options) ⇒ BSON::Binary

Note:

The Range algorithm is experimental only. It is not

Note:

The :key_id and :key_alt_name options are mutually exclusive. Only one is required to perform explicit encryption.

Encrypts a Match Expression or Aggregate Expression to query a range index.

Only supported when queryType is "range" and algorithm is "Range". @note: The Range algorithm is experimental only. It is not intended for public use. It is subject to breaking changes.

@param [ Hash ] options

intended for public use.

Examples:

Encrypt Match Expression.

encryption.encrypt_expression(
  {'$and' =>  [{'field' => {'$gt' => 10}}, {'field' =>  {'$lt' => 20 }}]}
)

Encrypt Aggregate Expression.

encryption.encrypt_expression(
  {'$and' =>  [{'$gt' => ['$field', 10]}, {'$lt' => ['$field', 20]}}
)
{$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]

Parameters:

  • expression (Hash)

    Expression to encrypt.

  • options (Hash)

    a customizable set of options

Options Hash (options):

  • :key_id (BSON::Binary)

    A BSON::Binary object of type :uuid representing the UUID of the encryption key as it is stored in the key vault collection.

  • :key_alt_name (String)

    The alternate name for the encryption key.

  • :algorithm (String)

    The algorithm used to encrypt the expression. The only allowed value is "Range"

  • :contention_factor (Integer | nil)

    Contention factor to be applied If not provided, it defaults to a value of 0.

  • query_type (String | nil)

    Query type to be applied. The only allowed value is "range".

  • :range_opts (Hash | nil)

    Specifies index options for a Queryable Encryption field supporting "range" queries. Allowed options are:

    • :min
    • :max
    • :trim_factor
    • :sparsity
    • :precision min, max, trim_factor, sparsity, and precision must match the values set in the encryptedFields of the destination collection. For double and decimal128, min/max/precision must all be set, or all be unset.

Returns:

  • (BSON::Binary)

    A BSON Binary object of subtype 6 (ciphertext) representing the encrypted expression.

Raises:

  • (ArgumentError)

    if disallowed values in options are set.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 188

def encrypt_expression(expression, options)
  Crypt::ExplicitEncryptionExpressionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: expression },
    options
  ).run_state_machine(timeout_holder)['v']
end

#get_key(id) ⇒ BSON::Document | nil

Finds a single key with the given id.

Parameters:

Returns:

  • (BSON::Document | nil)

    The found key document or nil if not found.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 238

def get_key(id)
  @encryption_io.get_key(id, timeout_ms: @timeout_ms)
end

#get_key_by_alt_name(key_alt_name) ⇒ BSON::Document | nil

Returns a key in the key vault collection with the given key_alt_name.

Parameters:

  • key_alt_name (String)

    Key alt name to find a key.

Returns:

  • (BSON::Document | nil)

    The found key document or nil if not found.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 248

def get_key_by_alt_name(key_alt_name)
  @encryption_io.get_key_by_alt_name(key_alt_name, timeout_ms: @timeout_ms)
end

#get_keysCollection::View

Returns all keys in the key vault collection.

Name of this method is defined in the FLE spec

Returns:

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 257

def get_keys
  @encryption_io.get_keys(timeout_ms: @timeout_ms)
end

#master_key_for_provider(opts) ⇒ KMS::MasterKeyDocument | nil (private)

If a :provider is given, construct a new master key document with that provider.

Parameters:

  • opts (Hash)

    the options hash

  • [ (Hash)

    a customizable set of options

Returns:

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 327

def master_key_for_provider(opts)
  return nil unless opts[:provider]

  options = opts.dup
  provider = options.delete(:provider)
  KMS::MasterKeyDocument.new(provider, options)
end

#remove_key_alt_name(id, key_alt_name) ⇒ BSON::Document | nil

Removes a key_alt_name from a key in the key vault collection with the given id.

Parameters:

  • id (BSON::Binary)

    ::Mongo::Id of the key to remove key alt name.

  • key_alt_name (String)

    Key alt name to remove.

Returns:

  • (BSON::Document | nil)

    Document describing the identified key before removing the key alt name, or nil if no such key.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 269

def remove_key_alt_name(id, key_alt_name)
  @encryption_io.remove_key_alt_name(id, key_alt_name, timeout_ms: @timeout_ms)
end

#rewrap_many_data_key(filter, opts = {}) ⇒ Crypt::RewrapManyDataKeyResult

Decrypts multiple data keys and (re-)encrypts them with a new master_key, or with their current master_key if a new one is not given.

Parameters:

  • filter (Hash)

    Filter used to find keys to be updated.

  • options (Hash)

Returns:

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 284

def rewrap_many_data_key(filter, opts = {})
  validate_rewrap_options!(opts)

  master_key_document = master_key_for_provider(opts)

  rewrap_result = Crypt::RewrapManyDataKeyContext.new(
    @crypt_handle,
    @encryption_io,
    filter,
    master_key_document
  ).run_state_machine(timeout_holder)

  return RewrapManyDataKeyResult.new(nil) if rewrap_result.nil?

  updates = updates_from_data_key_documents(rewrap_result.fetch('v'))
  RewrapManyDataKeyResult.new(
    @encryption_io.update_data_keys(updates, timeout_ms: @timeout_ms)
  )
end

#timeout_holder (private)

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 358

def timeout_holder
  CsotTimeoutHolder.new(
    operation_timeouts: {
      operation_timeout_ms: @timeout_ms
    }
  )
end

#updates_from_data_key_documents(documents) ⇒ Array<Hash> (private)

Returns the corresponding update document for each of the given data key documents.

Parameters:

  • documents (Array<Hash>)

    the data key documents

Returns:

  • (Array<Hash>)

    the update documents

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 341

def updates_from_data_key_documents(documents)
  documents.map do |doc|
    {
      update_one: {
        filter: { _id: doc[:_id] },
        update: {
          '$set' => {
            masterKey: doc[:masterKey],
            keyMaterial: doc[:keyMaterial]
          },
          '$currentDate' => { updateDate: true },
        },
      }
    }
  end
end

#validate_rewrap_options!(opts) (private)

Ensures the consistency of the options passed to #rewrap_many_data_keys.

Parameters:

  • opts (Hash)

    the options hash to validate

Raises:

  • (ArgumentError)

    if the options are not consistent or compatible.

[ GitHub ]

  
# File 'lib/mongo/crypt/explicit_encrypter.rb', line 312

def validate_rewrap_options!(opts)
  return unless opts.key?(:master_key) && !opts.key?(:provider)

  raise ArgumentError, 'If :master_key is specified, :provider must also be given'
end