Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Ruby generated HMAC for SHA256 that is url safe to match Java?

I have a tomcat server running some Java code that lets users authenticate using an API key. The request uses an HMAC created with SHA256. I have a Ruby client that I am using to make the request and since I'm new to encryption I am having a difficult time getting it to generate a matching HMAC. I have tried not making it URL safe, and that matches. So I'm really wondering is how I can get the Ruby client to match with the URL safe version (since I can't change the Java code). It's just got an extra = character at the end. Thanks in advance for any help.

For Ruby I am using 1.9.3 and for Java I am using 6u31 along with the commons-codec-1.6.jar library from apache.

Code

Ruby:

require "openssl"
require "base64"

json_str = "{'community':'LG7B734A', 'login_id':'user1', 'time':'1331928899'}"
digest = OpenSSL::Digest::Digest.new("sha256")
key = [ "4cc45e4258121c3fec84147673e1bd88e51b1c177aafcfa2da72bd4655c9f933" ]
hmac = OpenSSL::HMAC.digest(digest, key.pack("H*"), json_str)

encoded_url_safe = Base64.urlsafe_encode64(hmac)
encoded = Base64.encode64(hmac)

puts("Encoded (Url Safe): " + encoded_url_safe)
puts("Encoded           : " + encoded)

Java:

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Mac;

public class ExampleHMAC
{
    public static void main(String[] args) throws Exception
    {
        String key = "4cc45e4258121c3fec84147673e1bd88e51b1c177aafcfa2da72bd4655c9f933";
        byte[] keyBytes = Hex.decodeHex(key.toCharArray());

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(keySpec);

        String jsonStr = "{'community':'LG7B734A', 'login_id':'user1', 'time':'1331928899'}";
        byte[] hmacBytes = mac.doFinal(jsonStr.getBytes());

        String encodedUrlSafe = Base64.encodeBase64URLSafeString(hmacBytes);
        String encoded = Base64.encodeBase64String(hmacBytes);

        System.out.println("Encoded (Url Safe): " + encodedUrlSafe);
        System.out.println("Encoded           : " + encoded);
    }
}

Output

Ruby:

Encoded (Url Safe): QgYLqGm1M4qozdEjGC_CnJ8CdBm2jQpsU85kSWFcjKM=
Encoded           : QgYLqGm1M4qozdEjGC/CnJ8CdBm2jQpsU85kSWFcjKM=

Java:

Encoded (Url Safe): QgYLqGm1M4qozdEjGC_CnJ8CdBm2jQpsU85kSWFcjKM
Encoded           : QgYLqGm1M4qozdEjGC/CnJ8CdBm2jQpsU85kSWFcjKM=
like image 786
mvalley Avatar asked Mar 16 '12 20:03

mvalley


1 Answers

Ruby does not remove the trailing '=' - it is not an absolute requirement, as you can read in RFC 4648 it just states that removing them might be desirable in certain applications. But other than that it is guaranteed that Ruby's URL-safe encoding will be exactly the same as Java's.

So the only thing for you to do is strip off the trailing '==', you could for example use a regex:

encoded_url_safe_.gsub!(/=+$/, "")
like image 87
emboss Avatar answered Sep 30 '22 05:09

emboss