class Eth::Key::Decrypter

def self.perform(data, password)

def self.perform(data, password)
  new(data, password).perform
end

def check_macs

def check_macs
  mac1 = keccak256(key[(key_length/2), key_length] + ciphertext)
  mac2 = hex_to_bin crypto_data['mac']
  if mac1 != mac2
    raise "Message Authentications Codes do not match!"
  end
end

def cipher

def cipher
  @cipher ||= OpenSSL::Cipher.new(cipher_name).tap do |cipher|
    cipher.decrypt
    cipher.key = key[0, (key_length/2)]
    cipher.iv = iv
  end
end

def cipher_name

def cipher_name
  "aes-128-ctr"
end

def ciphertext

def ciphertext
  hex_to_bin crypto_data['ciphertext']
end

def crypto_data

def crypto_data
  @crypto_data ||= data['crypto'] || data['Crypto']
end

def decrypted_data

def decrypted_data
  @decrypted_data ||= cipher.update(ciphertext) + cipher.final
end

def derive_key(password)

def derive_key(password)
  case kdf
  when 'pbkdf2'
    @key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
  when 'scrypt'
    # OpenSSL 1.1 inclues OpenSSL::KDF.scrypt, but it is not available usually, otherwise we could do: OpenSSL::KDF.scrypt(password, salt: salt, N: n, r: r, p: p, length: key_length)
    @key = SCrypt::Engine.scrypt(password, salt, n, r, p, key_length)
  else
    raise "Unsupported key derivation function: #{kdf}!"
  end
end

def digest

def digest
  OpenSSL::Digest.new digest_name
end

def digest_name

def digest_name
  "sha256"
end

def initialize(data, password)

def initialize(data, password)
  @data = JSON.parse(data)
  @password = password
end

def iterations

def iterations
  crypto_data['kdfparams']['c'].to_i
end

def iv

def iv
  hex_to_bin crypto_data['cipherparams']['iv']
end

def kdf

def kdf
  crypto_data['kdf']
end

def key_length

def key_length
  crypto_data['kdfparams']['dklen'].to_i
end

def n

def n
  crypto_data['kdfparams']['n'].to_i
end

def p

def p
  crypto_data['kdfparams']['p'].to_i
end

def perform

def perform
  derive_key password
  check_macs
  bin_to_hex decrypted_data
end

def r

def r
  crypto_data['kdfparams']['r'].to_i
end

def salt

def salt
  hex_to_bin crypto_data['kdfparams']['salt']
end