module BraintreeEncryption

Public Class Methods

encrypt(value, public_key) click to toggle source
# File lib/blinkbox/user/braintree_encode.rb, line 6
def self.encrypt(value, public_key)
  # reverse engineered from https://github.com/braintree/braintree.js/blob/master/lib/braintree.js
  # this may need to be updated if braintree change their client-side encryption scripts

  return nil if value.nil?
  return "" if value.respond_to?(:empty?) && value.empty?

  fail "The Braintree client key is not configured" if public_key.nil?
  raw_key = Base64.strict_decode64(public_key)
  rsa = OpenSSL::PKey::RSA.new(raw_key)

  aes = OpenSSL::Cipher::AES256.new(:CBC).encrypt
  aes_key, aes_iv = aes.random_key, aes.random_iv
  encrypted_value = aes.update(value.to_s) + aes.final
  ciphertext = aes_iv + encrypted_value
  encoded_ciphertext = Base64.strict_encode64(ciphertext)

  hmac_key = SecureRandom.random_bytes(32)
  hmac = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, hmac_key, ciphertext)
  signature = Base64.strict_encode64(hmac)

  combined_key = aes_key + hmac_key
  encoded_key = Base64.strict_encode64(combined_key)
  encrypted_key = Base64.strict_encode64(rsa.public_encrypt(encoded_key))

  "$bt4|javascript_1_3_9$#{encrypted_key}$#{encoded_ciphertext}$#{signature}"
end