class Mongo::Crypt::ExplicitEncrypter

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

@api private

Public Class Methods

new(key_vault_client, key_vault_namespace, kms_providers, kms_tls_options) click to toggle source

Create a new ExplicitEncrypter object.

@param [ Mongo::Client ] key_vault_client An instance of Mongo::Client

to connect to the key vault collection.

@param [ String ] key_vault_namespace The namespace of the key vault

collection in the format "db_name.collection_name".

@param [ Crypt::KMS::Credentials ] kms_providers A hash of key management service

configuration information.

@param [ Hash ] kms_tls_options 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.
# File lib/mongo/crypt/explicit_encrypter.rb, line 37
def initialize(key_vault_client, key_vault_namespace, kms_providers, kms_tls_options)
  Crypt.validate_ffi!
  @crypt_handle = Handle.new(
    kms_providers,
    kms_tls_options,
    explicit_encryption_only: true
  )
  @encryption_io = EncryptionIO.new(
    key_vault_client: key_vault_client,
    metadata_client: nil,
    key_vault_namespace: key_vault_namespace
  )
end

Public Instance Methods

add_key_alt_name(id, key_alt_name) click to toggle source

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

@param [ BSON::Binary ] id Id of the key to add new key alt name. @param [ String ] key_alt_name New key alt name to add.

@return [ BSON::Document | nil ] Document describing the identified key

before adding the key alt name, or nil if no such key.
# File lib/mongo/crypt/explicit_encrypter.rb, line 196
def add_key_alt_name(id, key_alt_name)
  @encryption_io.add_key_alt_name(id, key_alt_name)
end
create_and_insert_data_key(master_key_document, key_alt_names, key_material = nil) click to toggle source

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.

@param [ Mongo::Crypt::KMS::MasterKeyDocument ] master_key_document The master

key document that contains master encryption key parameters.

@param [ Array<String> | nil ] key_alt_names An optional array of strings specifying

alternate names for the new data key.

@param [ String | nil ] key_material 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.

@return [ BSON::Binary ] The 16-byte UUID of the new data key as a

BSON::Binary object with type :uuid.
# File lib/mongo/crypt/explicit_encrypter.rb, line 66
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

  @encryption_io.insert_data_key(data_key_document).inserted_id
end
decrypt(value) click to toggle source

Decrypts a value that has already been encrypted

@param [ BSON::Binary ] value A BSON Binary object of subtype 6 (ciphertext)

that will be decrypted

@return [ Object ] The decrypted value

# File lib/mongo/crypt/explicit_encrypter.rb, line 181
def decrypt(value)
  Crypt::ExplicitDecryptionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: value }
  ).run_state_machine['v']
end
encrypt(value, options) click to toggle source

Encrypts a value using the specified encryption key and algorithm

@param [ Object ] value The value to encrypt @param [ Hash ] options

@option options [ BSON::Binary ] :key_id A BSON::Binary object of type :uuid

representing the UUID of the encryption key as it is stored in the key
vault collection.

@option options [ String ] :key_alt_name The alternate name for the

encryption key.

@option options [ String ] :algorithm 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".

@option options [ Integer | nil ] :contention_factor Contention factor

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

@option options [ String | nil ] query_type Query type to be applied if encryption algorithm is set to “Indexed”. Query type should be set

only if encryption algorithm is set to "Indexed". The only allowed
value is "equality".

@note The :key_id and :key_alt_name options are mutually exclusive. Only

one is required to perform explicit encryption.

@return [ BSON::Binary ] A BSON Binary object of subtype 6 (ciphertext)

representing the encrypted value

@raise [ ArgumentError ] if either contention_factor or query_type

is set, and algorithm is not "Indexed".
# File lib/mongo/crypt/explicit_encrypter.rb, line 107
def encrypt(value, options)
  Crypt::ExplicitEncryptionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: value },
    options
  ).run_state_machine['v']
end
encrypt_expression(expression, options) click to toggle source

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

@example Encrypt Match Expression.

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

@example Encrypt Aggregate Expression.

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

Only supported when queryType is “rangePreview” and algorithm is “RangePreview”. @note: The Range algorithm is experimental only. It is not intended

for public use. It is subject to breaking changes.

@param [ Hash ] expression Expression to encrypt. # @param [ Hash ] options @option options [ BSON::Binary ] :key_id A BSON::Binary object of type :uuid

representing the UUID of the encryption key as it is stored in the key
vault collection.

@option options [ String ] :key_alt_name The alternate name for the

encryption key.

@option options [ String ] :algorithm The algorithm used to encrypt the

expression. The only allowed value is "RangePreview"

@option options [ Integer | nil ] :contention_factor Contention factor

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

@option options [ String | nil ] query_type Query type to be applied.

The only allowed value is "rangePreview".

@option options [ Hash | nil ] :range_opts Specifies index options for

a Queryable Encryption field supporting "rangePreview" queries.
Allowed options are:
- :min
- :max
- :sparsity
- :precision
min, max, sparsity, and range 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.

@note The RangePreview algorithm is experimental only. It is not intended for public use.

@note The :key_id and :key_alt_name options are mutually exclusive. Only

one is required to perform explicit encryption.

@return [ BSON::Binary ] A BSON Binary object of subtype 6 (ciphertext)

representing the encrypted expression.

@raise [ ArgumentError ] if disallowed values in options are set.

# File lib/mongo/crypt/explicit_encrypter.rb, line 166
def encrypt_expression(expression, options)
  Crypt::ExplicitEncryptionExpressionContext.new(
    @crypt_handle,
    @encryption_io,
    { v: expression },
    options
  ).run_state_machine['v']
end
rewrap_many_data_key(filter, opts = {}) click to toggle source

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.

@param [ Hash ] filter Filter used to find keys to be updated. @param [ Hash ] options

@option options [ String ] :provider KMS provider to encrypt keys. @option options [ Hash | nil ] :master_key Document describing master key

to encrypt keys.

@return [ Crypt::RewrapManyDataKeyResult ] Result of the operation.

# File lib/mongo/crypt/explicit_encrypter.rb, line 249
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

  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))
end

Private Instance Methods

master_key_for_provider(opts) click to toggle source

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

@param [ Hash ] opts the options hash

@option [ String ] :provider KMS provider to encrypt keys.

@return [ KMS::MasterKeyDocument | nil ] the new master key document,

or nil if no provider was given.
# File lib/mongo/crypt/explicit_encrypter.rb, line 290
def master_key_for_provider(opts)
  return nil unless opts[:provider]

  options = opts.dup
  provider = options.delete(:provider)
  KMS::MasterKeyDocument.new(provider, options)
end
updates_from_data_key_documents(documents) click to toggle source

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

@param [ Array<Hash> ] documents the data key documents

@return [ Array<Hash> ] the update documents

# File lib/mongo/crypt/explicit_encrypter.rb, line 304
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) click to toggle source

Ensures the consistency of the options passed to rewrap_many_data_keys.

@param [ Hash ] opts the options hash to validate

@raise [ ArgumentError ] if the options are not consistent or

compatible.
# File lib/mongo/crypt/explicit_encrypter.rb, line 275
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