Question

I have this algorithm in PHP:

$encoded_key = 'WHllcnRGYTY3eWpUNjQ'; 
$decoded_key = base64_decode($encoded_key); 
// XyertFa67yjT64 
$params_string = implode('', $params); 
//U215250.00121715620http://partner.domain.ru/order/U215/successhttp://partner.domain.ru/order/U215/fail 
$raw_signature = hash_hmac('sha1', $params_string, $decoded_key, true); 
// Byte-encoded, hex: c6881d8665afbb46a93a16b34bd152878a19ab3a 

$encoded_signature = base64_encode($raw_signature); 
// xogdhmWvu0apOhazS9FSh4oZqzo= 

I'm trying to port this code to Ruby and get the same result but Base64 and OpenSSL can't help me. Does any one know whats wrong?

Was it helpful?

Solution

One problem is that you are using HMAC.hexdigest instead of HMAC.digest. Your PHP code is generating a raw HMAC and then encoding it in base 64. Therefore, you need to do the same thing in Ruby.

The other problem is the base 64 decoding step of the key. The key you entered is not padded correctly and will therefore be truncated by Ruby's base 64 library. For example:

encoded_key = "WHllcnRGYTY3eWpUNjQ"

Base64.decode64(encoded_key)
#=> "XyertFa67yjT"
# incomplete!

Base64.decode64("#{encoded_key}=\n")
#=> "XyertFa67yjT64"
# this is what you actually want

The padding and the final newline are there to ensure that the base 64 encoded data is complete, since it marks the end. However, it is possible to manually add the padding and just assume that the data is complete:

require 'base64'
require 'openssl'

def base64_pad(unpadded_str)
  padding = case unpadded_str.size % 3
    when 1 then "=="
    when 2 then "="
  end
  "#{unpadded_str}#{padding}\n"
end

encoded_key = "WHllcnRGYTY3eWpUNjQ"
key = Base64.decode64(base64_pad(encoded_key))
#=> "XyertFa67yjT64"

string = "U215250.00121715620http://partner.domain.ru/order/U215/successhttp://partner.domain.ru/order/U215/fail"

Base64.encode64(OpenSSL::HMAC.digest('SHA1', key, string))
#=> "xogdhmWvu0apOhazS9FSh4oZqzo=\n"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top