Ruby and PHP Hmacs Not Agreeing

Ruby and PHP HMACs not agreeing

ruby's OpenSSL::HMAC.hexdigest expects first key and then message.

irb(main):002:0> OpenSSL::HMAC.hexdigest('sha256','3D2143BD-6F86-449F-992C-65ADC97B968B','A522EBF2-5083-484D-99D9-AA97CE49FC6C,1234567890,/api/comic/aWh62,GET')
=> "e5f6995ba1496b2fb144329b2d1b3b23c8fa3211486e57bfaec5d993a1da9d15"

Rails and PHP encode64 not agreeing

You have 2 problems:

  1. Your ruby output is returned as ascii hex, not raw, and you are not base64 encoding it
  2. You have the argument order for the PHP hash_hmac() function wrong.

Ruby:

appsecret = '00916893840fe0a29dfdc261efd3a26a&'
data = 'GET&http%3A%2F%2Fopen.tianya.cn%2Foauth%2Frequest_token.php&oauth_consumer_key%3Dfc69b18eb12bab1e9b35d1093c4de9290516cfdc4%26oauth_nonce%3Dc09e4bf167fbc7eb374b1abb02b5268d%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1366882036%26oauth_version%3D1.0'

digest = OpenSSL::HMAC.digest('sha1', appsecret, data)
Base64.encode64(digest)

PHP:

$appsecret = '00916893840fe0a29dfdc261efd3a26a&';
$data = 'GET&http%3A%2F%2Fopen.tianya.cn%2Foauth%2Frequest_token.php&oauth_consumer_key%3Dfc69b18eb12bab1e9b35d1093c4de9290516cfdc4%26oauth_nonce%3Dc09e4bf167fbc7eb374b1abb02b5268d%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1366882036%26oauth_version%3D1.0';

$digest = hash_hmac('sha1', $data, $appsecret, true);
echo base64_encode($digest);

Both produce hJT2I37mBCo9qISNshKEvhe/at4=. Note, however, that the ruby output also has a trailing new-line, so you will need to normalize this (either remove it in ruby or add one in PHP) if you want to compare them directly.

OpenSSL::HMAC.hexdigest PHP equivalent won't print the same result as ruby one

It seems Ruby is adding newlines to the base64 encoded string, while PHP is not.

Ruby:

Base64.encode64('bonjour')
=> "Ym9uam91cg==\n"

PHP:

base64_encode('bonjour')
=> "Ym9uam91cg=="

So now we know how to fix it in PHP:

hash_hmac('sha1', base64_encode('bonjour') . "\n", 'hello');
=> "62ac34e5d28563d6a50272d660805d1f8c791e41"

Or fixing it in Ruby:

OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), 
'hello', Base64.encode64('bonjour').chomp)
=> "89ebf8bd3d92bf3283aa4c5f24072820258367e4"

Part 2

In PHP, as well as in Ruby, '\n' is not the same as "\n". The first one produces two characters (\ followed by n), the second one produces a newline.

So to fix your code you need to use newlines, not slash+n, in your strings:

$base64 = chunk_split(base64_encode($json), 60, "\n");
^^^^

You could also strip the newlines from the Ruby base64 encoded string with gsub, which means you will not need to use any tricks in your PHP code:

encoded_body = Base64.encode64(json_body).gsub("\n", '')

Convert hash_hmac in PHP to rails equivalent

You can do like this

require 'openssl'
require 'json'

private_hash = 'e249c439ed7697df2a4b045d97d4b9b7e1854c3ff8dd668c779013653913572e'
content = { "test" => "content" }.to_json
digest = OpenSSL::Digest.new('sha256')

hash = OpenSSL::HMAC.hexdigest(digest, private_hash, content)

For more information, please see http://ruby-doc.org/stdlib-2.2.3/libdoc/openssl/rdoc/OpenSSL/HMAC.html

Ruby HMAC signing issue

You need to do this in Ruby:

hash = OpenSSL::HMAC.hexdigest(digest, [key].pack('H*'), message)

The real issue here is that your PHP code uses two variable names for the message. You set $message, then use $msg, which means you're computing the hash for an undefined variable.

Ruby hmac sha256 hash differs for variable versus literal

looks like Base64.encode64 appends a "\n" to the end of its output so

from docs

encode64(bin) Returns the Base64-encoded
version of bin. This method complies with RFC 2045. Line feeds are
added to every 60 encoded characters.

this

contentmd5 = Base64.encode64(OpenSSL::Digest::MD5.digest(content))

returns

"XUFAKrxLKna5cZ2REBfFkg==\n"

not

 "XUFAKrxLKna5cZ2REBfFkg=="

--

you can use strict_encode64 to not include line feeds so:

contentmd5 = Base64.strict_encode64(OpenSSL::Digest::MD5.digest(content))

returns

 => "XUFAKrxLKna5cZ2REBfFkg=="

Get Ruby's OpenSSL::HMAC.hexdigest() to output the same as PHP's hash_hmac()

Use OpenSSL::HMAC.digest to get the binary output.



Related Topics



Leave a reply



Submit