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:
- Your ruby output is returned as ascii hex, not raw, and you are not base64 encoding it
- 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
Create New Xml File and Write Data to It
How to Select All Column Name from a Table in Laravel
Sending Push Notifications to Multiple Android Devices Using Gcm
How to Render Zf2 View Within JSON Response
How to Check If Letter Is Upper or Lower in PHP
How to Paginate a Merged Collection in Laravel 5
How to Set an Arrays Internal Pointer to a Specific Position? PHP/Xml
How to Alias the Name of a Column in Eloquent
What Are the Valid Characters in PHP Variable, Method, Class, etc Names
How to Notify a User After an Access_Control Rule Redirects
How to Execute PHP Code Within JavaScript
Algorithm to Get All Possible String Combinations from Array Up to Certain Length
Use One Laravel Migrations Table Per Database
Php/Symfony/Doctrine Memory Leak