module Mongo::Crypt::Hooks

A helper module that implements cryptography methods required for native Ruby crypto hooks. These methods are passed into FFI as C callbacks and called from the libmongocrypt library.

@api private

Public Class Methods

aes(key, iv, input, decrypt: false, mode: :CBC) click to toggle source

An AES encrypt or decrypt method.

@param [ String ] key The 32-byte AES encryption key @param [ String ] iv The 16-byte AES IV @param [ String ] input The data to be encrypted/decrypted @param [ true | false ] decrypt Whether this method is decrypting. Default is

false, which means the method will create an encryption cipher by default

@param [ Symbol ] mode AES mode of operation

@return [ String ] Output @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 42
def aes(key, iv, input, decrypt: false, mode: :CBC)
  cipher = OpenSSL::Cipher::AES.new(256, mode)

  decrypt ? cipher.decrypt : cipher.encrypt
  cipher.key = key
  cipher.iv = iv
  cipher.padding = 0

  encrypted = cipher.update(input)
end
hash_sha256(input) click to toggle source

A crypto hash (SHA-256) function

@param [ String ] input The data to be hashed

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 87
def hash_sha256(input)
  Digest::SHA2.new(256).digest(input)
end
hmac_sha(digest_name, key, input) click to toggle source

An HMAC SHA-512 or SHA-256 function

@param [ String ] digest_name The name of the digest, either “SHA256” or “SHA512” @param [ String ] key The 32-byte AES encryption key @param [ String ] input The data to be tagged

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 75
def hmac_sha(digest_name, key, input)
  OpenSSL::HMAC.digest(digest_name, key, input)
end
random(num_bytes) click to toggle source

Crypto secure random function

@param [ Integer ] num_bytes The number of random bytes requested

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 61
def random(num_bytes)
  SecureRandom.random_bytes(num_bytes)
end
rsaes_pkcs_signature(key, input) click to toggle source

An RSASSA-PKCS1-v1_5 with SHA-256 signature function.

@param [ String ] key The PKCS#8 private key in DER format, base64 encoded. @param [ String ] input The data to be signed.

@return [ String ] The signature.

# File lib/mongo/crypt/hooks.rb, line 98
def rsaes_pkcs_signature(key, input)
  private_key = if BSON::Environment.jruby?
    # JRuby cannot read DER format, we need to convert key into PEM first.
    key_pem = [
      "-----BEGIN PRIVATE KEY-----",
      Base64.strict_encode64(Base64.decode64(key)).scan(/.{1,64}/),
      "-----END PRIVATE KEY-----",
    ].join("\n")
    OpenSSL::PKey::RSA.new(key_pem)
  else
    OpenSSL::PKey.read(Base64.decode64(key))
  end
  private_key.sign(OpenSSL::Digest::SHA256.new, input)
end

Private Instance Methods

aes(key, iv, input, decrypt: false, mode: :CBC) click to toggle source

An AES encrypt or decrypt method.

@param [ String ] key The 32-byte AES encryption key @param [ String ] iv The 16-byte AES IV @param [ String ] input The data to be encrypted/decrypted @param [ true | false ] decrypt Whether this method is decrypting. Default is

false, which means the method will create an encryption cipher by default

@param [ Symbol ] mode AES mode of operation

@return [ String ] Output @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 42
def aes(key, iv, input, decrypt: false, mode: :CBC)
  cipher = OpenSSL::Cipher::AES.new(256, mode)

  decrypt ? cipher.decrypt : cipher.encrypt
  cipher.key = key
  cipher.iv = iv
  cipher.padding = 0

  encrypted = cipher.update(input)
end
hash_sha256(input) click to toggle source

A crypto hash (SHA-256) function

@param [ String ] input The data to be hashed

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 87
def hash_sha256(input)
  Digest::SHA2.new(256).digest(input)
end
hmac_sha(digest_name, key, input) click to toggle source

An HMAC SHA-512 or SHA-256 function

@param [ String ] digest_name The name of the digest, either “SHA256” or “SHA512” @param [ String ] key The 32-byte AES encryption key @param [ String ] input The data to be tagged

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 75
def hmac_sha(digest_name, key, input)
  OpenSSL::HMAC.digest(digest_name, key, input)
end
random(num_bytes) click to toggle source

Crypto secure random function

@param [ Integer ] num_bytes The number of random bytes requested

@return [ String ] @raise [ Exception ] Exceptions raised during encryption are propagated

to caller.
# File lib/mongo/crypt/hooks.rb, line 61
def random(num_bytes)
  SecureRandom.random_bytes(num_bytes)
end
rsaes_pkcs_signature(key, input) click to toggle source

An RSASSA-PKCS1-v1_5 with SHA-256 signature function.

@param [ String ] key The PKCS#8 private key in DER format, base64 encoded. @param [ String ] input The data to be signed.

@return [ String ] The signature.

# File lib/mongo/crypt/hooks.rb, line 98
def rsaes_pkcs_signature(key, input)
  private_key = if BSON::Environment.jruby?
    # JRuby cannot read DER format, we need to convert key into PEM first.
    key_pem = [
      "-----BEGIN PRIVATE KEY-----",
      Base64.strict_encode64(Base64.decode64(key)).scan(/.{1,64}/),
      "-----END PRIVATE KEY-----",
    ].join("\n")
    OpenSSL::PKey::RSA.new(key_pem)
  else
    OpenSSL::PKey.read(Base64.decode64(key))
  end
  private_key.sign(OpenSSL::Digest::SHA256.new, input)
end