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=
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!(/=+$/, "")