module Adyen::Signature
The Signature
module generic to sign and verify HMAC SHA-256 signatures
Public Instance Methods
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
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
# File lib/adyen/signature.rb 60 def escape_value(value) 61 value.gsub(':', '\\:').gsub('\\', '\\\\') 62 end
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
# File lib/adyen/signature.rb 48 def sorted_keys(hash, keys_to_sort = nil) 49 hash.sort.map{ |el| el[0] } 50 end
# 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
# 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