class AdyenCse::Encrypter

Constants

PREFIX
VERSION

Attributes

public_key[R]

Public Class Methods

new(public_key) click to toggle source
# File lib/adyen_cse/encrypter.rb, line 13
def initialize(public_key)
  @public_key = public_key
end
parse_public_key(public_key) click to toggle source
# File lib/adyen_cse/encrypter.rb, line 45
def self.parse_public_key(public_key)
  exponent, modulus = public_key.split("|").map { |n| n.to_i(16) }

  if RUBY_VERSION < '2.4.0'
    OpenSSL::PKey::RSA.new.tap do |rsa|
      rsa.e = OpenSSL::BN.new(exponent)
      rsa.n = OpenSSL::BN.new(modulus)
    end
  else
    rsa = OpenSSL::PKey::RSA.new
    rsa.set_key(OpenSSL::BN.new(modulus), OpenSSL::BN.new(exponent), nil)
  end
end

Public Instance Methods

encrypt!(params = {}) click to toggle source
# File lib/adyen_cse/encrypter.rb, line 17
def encrypt!(params = {})
  validate!(params.keys)

  key   = SecureRandom.random_bytes(32)
  nonce = SecureRandom.random_bytes(12)
  generation_time = params.fetch(:generation_time, Time.now)

  # keys sorted alphabetically
  json_data = {
    "cvc" => params[:cvc],
    "expiryMonth" => params[:expiry_month],
    "expiryYear" => params[:expiry_year],
    "generationtime" => generation_time.utc.strftime("%FT%T.%LZ"),
    "holderName" => params[:holder_name],
    "number" => params[:number],
  }.to_json

  ccm = OpenSSL::CCM.new("AES", key, 8)
  encrypted_card = ccm.encrypt(json_data, nonce)

  rsa = self.class.parse_public_key(public_key)
  encrypted_aes_key = rsa.public_encrypt(key)

  encrypted_card_component = nonce + encrypted_card

  [PREFIX, VERSION, "$", Base64.strict_encode64(encrypted_aes_key), "$", Base64.strict_encode64(encrypted_card_component)].join
end

Private Instance Methods

validate!(params) click to toggle source
# File lib/adyen_cse/encrypter.rb, line 61
def validate!(params)
  %i(holder_name number expiry_month expiry_year cvc).each do |param|
    raise ArgumentError, "param `#{param}' is required" unless params.include?(param)
  end
end