How to create MD5 hash with HMAC module in Ruby?
The following gem should be installed: 'ruby-hmac'
$ irb
>> require 'hmac-md5'
=> true
>> HMAC::MD5.new("abc").digest
=> "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~"
>> HMAC::MD5.new("abc").hexdigest
=> "d41d8cd98f00b204e9800998ecf8427e"
>>
How does this PHP function should look in Ruby? HMAC MD5
There is no reason to write your own implementation of HMAC and many, many reasons not to. Just use the secure and well-tested implementation supplied by the OpenSSL module:
require "openssl"
key = "key"
data = "Hello"
digest = OpenSSL::Digest.new('md5')
hmac = OpenSSL::HMAC.hexdigest(digest, key, data)
That's literally all you need.
HMAC vs simple MD5 Hash
The Wikipedia article on HMAC gives a good explanation of this.
In the Security section of the same article it goes on to say:
HMACs are substantially less affected by collisions than their underlying hashing algorithms alone.
So adding an HMAC to an MD5 hash would make it substantially more difficult to break via a rainbow table.
Difference between OpenSSL::HMAC#hexdigest vs Digest::MD5#hexdigest in ruby?
The HMAC-MD5 of DATA and KEY is define as
MD5( (K xor pad1) + H ((K xor pad2) + DATA )
where pad1 and pad2 are two fixed constants. Some of the more obvious things you might do are cryptographically weak.
Digest::MD5.hexdigest(KEY + DATA)
is fatally flawed. Consider how MD5 works. It splits the input up into blocks of a certain size (512 bits for md5) and sets up some initial state h0, h1, h2, h3. It then does a bunch of transformations to mix the first block of data with that initial state to produce new values of h0, h1, h2, h3. The second block of data is then combined with those to produce a new set of h0,h1,h2,h3 and so on. The final value of the hash function is just the concatenation of h0,h1,h2,h3.
This means that if you give me Digest::MD5#hexdigest(KEY + DATA)
then I can calculate what Digest::MD5#hexdigest(KEY + DATA + OTHER_DATA)
is without knowing KEY at all. You can do the same thing with SHA1
If instead you did
Digest::MD5.hexdigest(DATA+KEY)
then any known collisions in MD5 are easily used to make messages with the same HMAC value.
Apparently
Digest::MD5.hexdigest(KEY+DATA+KEY)
may be flawed too, even if two different keys were used. HMAC was designed to mitigate all of these attacks.
Equivalent ruby code for PHP MD5 Key
You need to concatenate your post_data
and secretkey
values in the same way that you're doing using the .
operator in PHP, so that you're only passing a single string to the MD5 digest function.
Digest::MD5.hexdigest(post_data + secretkey)
is the simplest method, though you could also use
Digest::MD5.hexdigest(post_data << secretkey)
or
Digest::MD5.hexdigest("#{post_data}#{secretkey}")
HMAC (hash-based message authentication code, aka data signing) in Mathematica
Here's my implementation:
First some utility functions:
(* Pad the string s with x on the right/left so it has length n. *)
strpadr[s_, n_, x_] := StringJoin@PadRight[Characters[s], n, x]
strpadl[s_, n_, x_] := StringJoin@PadLeft[Characters[s], n, x]
(* hex representation; optionally pad to length n with zeros *)
hex[x_, n_:Null]:= If[n===Null, Identity, strpadl[#,n,"0"]&]@IntegerString[x,16]
(* parse hex representation (return an integer) *)
unhex[x_] := FromDigits[x, 16]
(* Concatenate all the arguments as strings (if they're not already). *)
cat = StringJoin @@ (ToString /@ {##}) &;
(* Takes a string like "xy" and returns the hex representation (also a string,
twice as long) of the bytes (ascii codes). *)
tobytes[s_] := cat @@ (hex[#, 2] & /@ ToCharacterCode[s])
(* Takes a length n string like "0a10" and returns a length n/2 string where in
this example the first character is whatever has ascii code 10 ("a" in hex)
and the second is whatever has ascii code 16 ("10" in hex). *)
frombytes[hs_] := FromCharacterCode[unhex /@ cat@@@Partition[Characters[hs], 2]]
(* Bitwise-xor of two integers given in hex. *)
hexbitxor[a_String, b_String] := hex@BitXor[unhex@a, unhex@b]
(* Repeat the string s, n times. *)
strrpt[s_, n_] := cat @@ ConstantArray[s, n]
(* Byte length of a hex string is half the string length. *)
bytelen[s_] := Ceiling[StringLength[s]/2]
Implementing the basic hash functions in Mathematica is not quite trivial. See this question:
Cryptographic hash (sha1 or md5) of data given as a string in Mathematica.
(* FileHash is the only way to hash data given as a string in Mma. *)
hash[s_String, h_:"SHA"] := Module[{stream = StringToStream[s], result},
result = FileHash[stream, h];
Close[stream];
hex@result];
sha1[s_] := hash[s]
md5[s_] := hash[s, "MD5"]
Finally, here's the hmac function:
(* Return the hmac digest using hash function h for string s with key k. *)
hmac[s_, k_, h_:sha1] := Module[{b, key, ipad, opad},
b = 64; (* block size for both md5 and sha1 *)
key = tobytes[k];
key = If[bytelen[key] > b, h[frombytes@key], key];
key = strpadr[key, 2 b, "0"];
ipad = hexbitxor[strrpt["36", b], key];
opad = hexbitxor[strrpt["5c", b], key];
h[frombytes[opad <> h[frombytes[ipad <> tobytes@s]]]]]
I confirmed that this matches all the examples provided in RFC 2104. For example:
hmac["what do ya want for nothing?", "Jefe", md5]
returns
"750c783e6ab0b503eaa86e310a5db738"
C++ - HMAC MD5 is not equals with online generator
You are incorrectly assuming that the web site is converting the data from a hex string to bytes when it's not.
This simple example results in the same output as the web site:
bool test_gen_md5_hmac()
{
std::string k = "320E6FADB2738DA273A41E14F85027E1";
std::string d = "35413B1DD9AB9FA0F1395759BD72451C";
unsigned char hash[16];
unsigned int len = 16;
HMAC(EVP_md5(), k.c_str(), k.size(), (unsigned char*)d.c_str(), d.size(), hash, &len);
char* rv = OPENSSL_buf2hexstr(hash, 16);
std::string rv_str(rv);
OPENSSL_free(rv);
return rv_str == "BB:4C:6D:FF:8A:4F:70:6B:0A:52:06:92:2D:38:A1:91";
}
Getting Ruby code to work, creating SHA1 hash from given string and key
You need to install the ruby-hmac module. See this blog post for a gentle introduction.
Related Topics
Ruby Class Instance Variables and Inheritance
Is Time.Zone.Now.To_Date Equivalent to Date.Today
How to Expire a View Cached Fragment from Console
Creating a Hash with Values as Arrays and Default Value as Empty Array
Vi Input Mode in Command Line Matlab
How to Update Gems in Ruby for Windows
Sudo Gem Install Pg Won't Work
How to Get a HTML Table Row with Capybara
Define_Method: How to Dynamically Create Methods with Arguments
Rails - Displaying Foreign Key References in a Form
Differencebetween "Rails S" and "Bundle Exec Rails S"
Passenger Installation with Nginx Fails
Should I Check in '.Ruby-Gemset' And/Or '.Ruby-Version'
What Is the Community-Preferred Ruby Unit Testing Framework
Can't Convert Symbol into String