module Adyen::Signature

The Signature module generic to sign and verify HMAC SHA-256 signatures

Public Instance Methods

sign(params, type = :hpp) click to toggle source

Sign the parameters with the given shared secret @param [Hash] params The set of parameters to verify. Must include a `shared_secret` param for signing/verification

@param [String] type The type to sign (:hpp or :rest). Default is :hpp @return [String] The signature

   # File lib/adyen/signature.rb
14 def sign(params, type = :hpp)
15   shared_secret = params.delete('sharedSecret')
16   raise ArgumentError, "Cannot sign parameters without a shared secret" unless shared_secret
17   sig = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), Array(shared_secret).pack("H*"), string_to_sign(params, type))
18   Base64.encode64(sig).strip
19 end
verify(params, hmacSignature, type = :hpp) click to toggle source

Compare a signature calculated with anoter HMAC Signature @param [Hash] params The set of parameters to verify. Must include a `shared_secret`

param for signing/verification

@param [String] hmacSignature will be compared to the signature calculated. @return [Boolean] true if the `hmacSignature` matches our calculated signature

   # File lib/adyen/signature.rb
26 def verify(params, hmacSignature, type = :hpp)
27   raise ArgumentError,"hmacSignature cannot be empty for verification" if hmacSignature.empty?
28   our_sig = sign(params, type)
29   secure_compare(hmacSignature, our_sig)
30 end

Private Instance Methods

escape_value(value) click to toggle source
   # File lib/adyen/signature.rb
60 def escape_value(value)
61   value.gsub(':', '\\:').gsub('\\', '\\\\')
62 end
secure_compare(a, b) click to toggle source

Constant-time compare for two fixed-length strings Stolen from github.com/rails/rails/commit/c8c660002f4b0e9606de96325f20b95248b6ff2d

   # File lib/adyen/signature.rb
66 def secure_compare(a, b)
67   return false unless a.bytesize == b.bytesize
68 
69   l = a.unpack "C#{a.bytesize}"
70 
71   res = 0
72   b.each_byte { |byte| res |= byte ^ l.shift }
73   res == 0
74 end
sorted_keys(hash, keys_to_sort = nil) click to toggle source
   # File lib/adyen/signature.rb
48 def sorted_keys(hash, keys_to_sort = nil)
49   hash.sort.map{ |el| el[0] }
50 end
sorted_values(hash, keys_to_sort = nil) click to toggle source
   # File lib/adyen/signature.rb
52 def sorted_values(hash, keys_to_sort = nil)
53   if keys_to_sort.is_a? Array
54     keys_to_sort.map { |key| hash[key] }
55   else
56     hash.sort.map{ |el| el[1] }
57   end
58 end
string_to_sign(params, type) click to toggle source
   # File lib/adyen/signature.rb
34 def string_to_sign(params, type)
35   string = ''
36   if type == :hpp
37     string = sorted_keys(params) + sorted_values(params)
38   elsif type == :rest
39     keys = %w(pspReference originalReference merchantAccountCode merchantReference value currency eventCode success)
40     string = sorted_values(params, keys)
41   else
42     raise NotImplementedError, 'Type sign not implemented'
43   end
44 
45   string.map{ |el| escape_value(el) }.join(':')
46 end