Skip to content

Instantly share code, notes, and snippets.

@enoliglesias
Last active November 25, 2016 17:35
Show Gist options
  • Save enoliglesias/7d01a443700f9bb94752 to your computer and use it in GitHub Desktop.
Save enoliglesias/7d01a443700f9bb94752 to your computer and use it in GitHub Desktop.
Ds_Signature creation for Sermepa with SHA256
def confirmation(credentials)
return false if params['ds_signature'].blank?
# The DES3-CBC key generation it's the same that in the creation gist
# You can take a look at the explanation
secret_key = credentials[:secret_key]
secret_key_base64 = Base64.strict_decode64(secret_key)
des3 = OpenSSL::Cipher::Cipher.new('des-ede3-cbc')
block_length = 8
des3.padding = 0
des3.encrypt
des3.key = secret_key_base64
order_number = params["ds_order"]
order_number += "\0" until order_number.bytesize % block_length == 0
key_des3 = des3.update(order_number) + des3.final
# params["ds_merchantparameters"] it's the merchant parameters json in base64
# So, we don't need to encrypt again. We can use it directly :)
result = OpenSSL::HMAC.digest('sha256', key_des3, params["ds_merchantparameters"])
# Here is the new 'magic' for Sermepa
# We MUST replace '+' with '-'
# We MUST replace '/' with '_'
# Maybe they use this signature in some GET route, or something like that
# And they return it with this characters replaced
sig = Base64.strict_encode64(result).gsub("+", "-").gsub("/", "_")
sig == params['ds_signature']
end
def sermepa_signature
# By default OpenSSL generates an all-zero array for the encriptation vector
# You can read it here: http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-iv-3D
# If you want to declare it, you can take a look at the next couple of lines
#bytes = Array.new(8,0)
#iv = bytes.map(&:chr).join
# We need to decode the secret key
key = Base64.strict_decode64("COMERCE SECRET KEY")
# In thee cipher initialization we need to speficy the encryptation like method-length-mode (http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-c-new).
# Sermepa needs DES3 in CBC mode
# The direct way the declare it's: des-ede3-cbc
# You can also declare like 'des3' wich use CBC mode by default
des3 = OpenSSL::Cipher::Cipher.new('des-ede3-cbc')
# OpenSSL use by default PKCS padding. But Sermepa (mcrypt_encrypt PHP function) use zero padding.
# OpenSSL do not allow zero padding. So we need to disable the default padding and make zero padding by hand
# Padding in cryptography is to fill the data with especial characteres in order to use the data in blocks of N (https://en.wikipedia.org/wiki/Padding_(cryptography))
# We need to use blocks of 8 bytes
block_length = 8
# We tell OpenSSL not to pad
des3.padding = 0
# We want to encrypt
des3.encrypt
# Key set
des3.key = key
#des3.iv = iv
order_number = "YOUR Ds_Merchant_Order"
# Here is the 'magic'. Instead use the default OpenSSL padding (PKCS). We fill with \0 till the data have
# a multiple of the block size (8, 16, 24...)
order_number += "\0" until order_number.bytesize % block_length == 0
# For example: the string "123456789" will be transform in "123456789\x00\x00\x00\x00\x00\x00\x00"
# data must be in blocks of 8 or the update will break
key_des3 = des3.update(order_number) + des3.final
# The next step is to encrypt in SHA256 the resulting des3 key with the base64 json
result = OpenSSL::HMAC.digest('sha256', key_des3, "YOUR MERCHANT PARAMETERS JSON IN BASE64")
# The last step is to encode the data in base64
Base64.strict_encode64(result)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment