lib/tbk/webpay/encryption.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: us-ascii
module TBK
  module Webpay
    module Encryption
      # Constants
      KEY_ID = 101
      KEY = TBK.parse_key('webpay.101')
      TEST_KEY = TBK.parse_key('webpay_test.101')
      IV_PADDING = "\x10\xBB\xFF\xBF\x00\x00\x00\x00\x00\x00\x00\x00\xF4\xBF"

      def webpay_key_id
        KEY_ID
      end

      def webpay_key
        self.production? ? KEY : TEST_KEY
      end

      def webpay_key_length
        webpay_key.n.num_bytes
      end

      def webpay_encrypt(text)
        signature = self.key.sign(OpenSSL::Digest::SHA512.new, text)

        key = SecureRandom.random_bytes(32)
        encripted_key = webpay_key.public_encrypt(key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)

        iv = SecureRandom.random_bytes(16)

        cipher = OpenSSL::Cipher.new('AES-256-CBC')
        cipher.encrypt
        cipher.key = key
        cipher.iv = iv + IV_PADDING
        encripted_text = cipher.update(signature + text) + cipher.final

        Base64.encode64( iv + encripted_key + encripted_text).strip
      rescue RuntimeError => error
        raise TBK::Webpay::EncryptionError.new("Encryption failed",error)
      end

      def webpay_decrypt(encripted_text)
        data = Base64.decode64(encripted_text)

        iv = data[0...16]
        encripted_key = data[16...(16 + self.key_bytes)]
        key = self.key.private_decrypt(encripted_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)

        cipher = OpenSSL::Cipher.new('AES-256-CBC')
        cipher.decrypt
        cipher.key = key
        cipher.iv = iv + IV_PADDING
        decrypted_text = cipher.update(data[(16 + self.key_bytes)..-1]) + cipher.final
        signature = decrypted_text[0...(webpay_key_length)]
        text = decrypted_text[(webpay_key_length)..-1]

        unless webpay_key.verify(OpenSSL::Digest::SHA512.new, signature, text)
          raise TBK::Webpay::EncryptionError, "Invalid message signature"
        end

        {
          :body => text,
          :signature => signature.unpack('H*').first
        }
      rescue TBK::Error
        raise
      rescue => error
        raise TBK::Webpay::EncryptionError.new("Decryption failed",error)
      end

    end
  end

  Commerce.send :include, Webpay::Encryption
end