module Izokatu

Main module to work with.

Constants

DEFAULT_OPTIONS

Default options for Izokatu call

EXPORTER_MAPPING

Map of exporters and their symbol aliases

IMPORTER_MAPPING

Map of importers and their symbol aliases

VERSION

Gem version

Attributes

action[R]

@return [Symbol] action to execute

asym_cipher_type[R]

@return [Symbol] OpenSSL public key cipher type

cipher[R]

@return [String] OpenSSL private key cipher @note also used for OpenSSL public key ec key generation

exporter[R]

@return [Symbol] alias of Izokatu exporter

importer[R]

@return [Symbol] alias of Izokatu importer

mode[R]

@return [Symbol] mode of encryption/decryption

options[R]

@return [Hash] options from user merged with default

via[R]

@return [Symbol] library used for encryption/decryption

Public Class Methods

call(**options) click to toggle source

Public method to work with

@param options [Hash] options from user

@return [Hash] Encrypted/decrypted data with params or public/private keys

@since 0.1.0 @api public

@example RbNaCl private key cryptography

encrypted_data = Izokatu.call(clear_data_string: 'Some data')
Izokatu.call(action: :decryption, **encrypted_data)
=> {:decrypted_data_string=>"Some data"}

@example RbNaCl public key cryptography

keypair1 = Izokatu.call(action: :keys_generation, mode: :public_key)
keypair2 = Izokatu.call(action: :keys_generation, mode: :public_key)
encrypted_data = Izokatu.call(
  clear_data_string: 'Some data',
  mode: :public_key,
  public_key: keypair1[:public_key],
  private_key: keypair2[:private_key]
)
Izokatu.call(
  action: :decryption,
  mode: :public_key,
  **encrypted_data,
  public_key: keypair2[:public_key],
  private_key: keypair1[:private_key]
)
=> {:decrypted_data_string=>"Some data"}

@example OpenSSL private key cryptography

encrypted_data = Izokatu.call(
  clear_data_string: 'Some data',
  via: :openssl,
  cipher: 'AES-256-GCM'
)
Izokatu.call(
  action: :decryption,
  **encrypted_data,
  via: :openssl,
  cipher: 'AES-256-GCM'
)
=> {:decrypted_data_string=>"Some data"}

@example OpenSSL EC public key cryptography

keypair_options = {
  action: :keys_generation,
  mode: :public_key,
  via: :openssl
}
keypair1 = Izokatu.call(keypair_options)
keypair2 = Izokatu.call(keypair_options)
encrypted_data = Izokatu.call(
  clear_data_string: 'Some data',
  mode: :public_key,
  via: :openssl,
  public_key:
  keypair1[:public_key],
  private_key: keypair2[:private_key]
)
Izokatu.call(
  action: :decryption,
  mode: :public_key,
  via: :openssl,
  **encrypted_data,
  public_key: keypair2[:public_key],
  private_key: keypair1[:private_key]
)
=> {:decrypted_data_string=>"Some data"}

@example OpenSSL RSA public key cryptography

keypair_options = {
  action: :keys_generation,
  mode: :public_key,
  via: :openssl,
  asym_cipher_type: :rsa,
  bit_number: 4096
}
keypair1 = Izokatu.call(keypair_options)
keypair2 = Izokatu.call(keypair_options)
encrypted_data = Izokatu.call(
  clear_data_string: 'Some data',
  mode: :public_key,
  via: :openssl,
  public_key: keypair1[:public_key],
  private_key: keypair2[:private_key],
  asym_cipher_type: :rsa
)
Izokatu.call(
  action: :decryption,
  mode: :public_key,
  via: :openssl,
  **encrypted_data,
  public_key: keypair2[:public_key],
  private_key: keypair1[:private_key],
  asym_cipher_type: :rsa
)
=> {:decrypted_data_string=>"Some data"}
# File lib/izokatu.rb, line 171
def call(**options)
  initialize!(options)
  perform
end

Private Class Methods

ccm_cipher?() click to toggle source

Verifying cipher mode is equal to CCM

@return [Bool] result of verifying cipher mode is equal to CCM

@since 0.1.0

# File lib/izokatu.rb, line 390
def ccm_cipher?
  cipher.include?('CCM')
end
cipher_authenticated?() click to toggle source

Verifying cipher as authenticated. If cipher is authenticated, authenticated tag will be computed from encrypted data. @note passing EC ciphers as authenticated. Those ciphers used only for key generation

@return [Bool] result of verifying cipher as authenticated

@since 0.1.0

# File lib/izokatu.rb, line 402
def cipher_authenticated?
  return true if Openssl::PBKEY_EC_CIPHERS.include?(cipher)

  OpenSSL::Cipher.new(cipher).encrypt.authenticated? && openssl_auth_exception?
end
format_cipher(cipher) click to toggle source

Formatting name of OpenSSL private key ciphers

@param cipher [String] cipher name from user

@return [String] formatted cipher name

@since 0.1.0

# File lib/izokatu.rb, line 217
def format_cipher(cipher)
  Openssl::PKEY_CIPHERS.include?(cipher) ? cipher.upcase : cipher
end
initialize!(options) click to toggle source

Initializing Izokatu variables

@param options (options)

@since 0.1.0

# File lib/izokatu.rb, line 184
def initialize!(options)
  options = merge_options!(options)
  @via = options[:via]
  @mode = options[:mode]
  @action = options[:action]
  @asym_cipher_type = options[:asym_cipher_type]
  @exporter = options[:exporter]
  @importer = options[:importer]
  @cipher = format_cipher(options[:cipher])
  @options = options
end
izokatu_export(data:, params:, encode:) click to toggle source

Izokatu export function

@param data [Hash] encrypted/decrypted data for export @param params [Hash] decrypter params for export

@return [Hash] result of action class call

@since 0.1.0

# File lib/izokatu.rb, line 343
def izokatu_export(data:, params:, encode:)
  # WTF: Somehow, even Contract Any => Any for this method is violated
  case action
  when :encryption
    export_encrypted!(encrypted_data: data, decrypter_params: params || {}, encode: encode)
  when :decryption
    export_decrypted!(decrypted_data: data, encode: false)
  else
    data
  end
end
merge_options!(options) click to toggle source

Merging user option with default

@param options [Hash] options from user

@return [Hash] user options merged with default

@since 0.1.0

# File lib/izokatu.rb, line 205
def merge_options!(options)
  options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS
end
openssl_auth_exception?() click to toggle source

Verifying cipher is not using CBC mode or equal to RC4-HMAC-MD5. These conditions specifying ciphers which passing authenticated? check from OpenSSL, but are not authenticated.

@return [Bool] result of verifying cipher as OpenSSL exceptions from authenticated? check

@since 0.1.0

# File lib/izokatu.rb, line 415
def openssl_auth_exception?
  # In tests of openssl gem, I don't saw assigment of auth_tag or auth_data for cbc ciphers, only padding
  # (https://github.com/ruby/openssl/blob/master/test/openssl/test_cipher.rb)
  # Get this error:
  # OpenSSL::Cipher::CipherError: retrieving the authentication tag failed: ctrl operation not implemented
  # If not assigning authentication tag, get this error:
  # ':in `iv_len=': cipher does not support AEAD (OpenSSL::Cipher::CipherError)'
  !cipher.include?('CBC') && cipher != 'RC4-HMAC-MD5'
end
perform() click to toggle source

Verifying and processing merged options

@return [Hash] Encrypted/decrypted data with params or public/private keys

@since 0.1.0

# File lib/izokatu.rb, line 227
def perform
  verify_izokatu_options!
  verify_exporter_class!
  verify_importer_class!
  verify_izokatu_cipher!
  select_exporter_class!
  select_importer_class!
  process_izokatu_options!
end
process_izokatu_options!() click to toggle source

Importing encrypted data, selecting action class with options to call, exporting result of call

@return [Hash] Encrypted/decrypted data with params or public/private keys

@since 0.1.0

# File lib/izokatu.rb, line 327
def process_izokatu_options!
  import_encrypted!(options: options, decode: true) if action == :decryption
  action_class = select_action
  action_options = select_action_options(action_class)
  data, params = action_class.call(**action_options)
  izokatu_export(data: data, params: params, encode: true)
end
select_action() click to toggle source

Selecting action class to be called, based on options

@return [Class] action class

@since 0.1.0

# File lib/izokatu.rb, line 361
def select_action
  ActionCallSelector.call(
    via: via,
    mode: mode,
    action: action,
    asym_cipher_type: asym_cipher_type,
    ccm_cipher: ccm_cipher?,
    auth_cipher: cipher_authenticated?
  )
end
select_action_options(action_class) click to toggle source

Selecting options for action class, based on action class

@param action_class [Class] selected action class

@return [Hash] options for action class

@since 0.1.0

# File lib/izokatu.rb, line 380
def select_action_options(action_class)
  ActionCallOptionsSelector.call(action_class: action_class, options: options)
end
select_exporter_class!() click to toggle source

Changing exporter options value from alias of exporter class to exporter class

@return [Class] exporter class

@since 0.1.0

# File lib/izokatu.rb, line 305
def select_exporter_class!
  options[:exporter] = EXPORTER_MAPPING[exporter]
  @exporter = options[:exporter]
end
select_importer_class!() click to toggle source

Changing importer options value from alias of importer class to importer class

@return [Class] importer class

@since 0.1.0

# File lib/izokatu.rb, line 316
def select_importer_class!
  options[:importer] = IMPORTER_MAPPING[importer]
  @importer = options[:importer]
end
unknown_cipher?() click to toggle source

Verifying cipher is not from OpenSSL private key ciphers or EC ciphers

@return [Bool] result of verifying cipher is not from OpenSSL private key ciphers of EC ciphers

@since 0.1.0

# File lib/izokatu.rb, line 285
def unknown_cipher?
  !Openssl::PKEY_CIPHERS.include?(cipher) && !Openssl::PBKEY_EC_CIPHERS.include?(cipher)
end
verify_exporter_class!() click to toggle source

Verifying exporter alias

@raise [RuntimeError] if exporter alias is unknown

@since 0.1.0

# File lib/izokatu.rb, line 254
def verify_exporter_class!
  raise 'ERROR: Unknown exporter!' unless %i[stdout file function].include?(exporter)
end
verify_importer_class!() click to toggle source

Verifying importer alias

@raise [RuntimeError] if importer alias is unknown

@since 0.1.0

# File lib/izokatu.rb, line 263
def verify_importer_class!
  raise 'ERROR: Unknown importer!' unless %i[file function].include?(importer)
end
verify_izokatu_cipher!() click to toggle source

Verifying cipher

@raise [RuntimeError] if cipher name is unknowm

@note also raising exception if cipher is using unsupported WRAP mode

@since 0.1.0

# File lib/izokatu.rb, line 274
def verify_izokatu_cipher!
  raise 'ERROR: Unknown cipher!' if unknown_cipher?
  raise 'ERROR: Wrap ciphers are not supported!' if wrap_cipher?
end
verify_izokatu_options!() click to toggle source

Verifying options value

@raise [RuntimeError] if option value is unknown

@since 0.1.0

# File lib/izokatu.rb, line 242
def verify_izokatu_options!
  raise 'ERROR: Unknown library!' unless %i[openssl rbnacl].include?(via)
  raise 'ERROR: Unknown mode!' unless %i[private_key public_key].include?(mode)
  raise 'ERROR: Unknown action!' unless %i[encryption decryption keys_generation].include?(action)
  raise 'ERROR: Unknown asym_cipher_type!' unless %i[ec rsa].include?(asym_cipher_type)
end
wrap_cipher?() click to toggle source

Verifying cipher is using WRAP mode

@return [Bool] result of verifying cipher is using WRAP mode

@since 0.1.0

# File lib/izokatu.rb, line 295
def wrap_cipher?
  cipher.include?('wrap') || cipher.include?('WRAP')
end