I have the following code in Java:
byte[] secretKey = secretAccessKey.getBytes("UTF-8");
SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] bytes = data.getBytes("UTF-8");
byte[] rawHmac = mac.doFinal(bytes);
String result = javax.xml.bind.DatatypeConverter.printBase64Binary(rawHmac);
and the following code in C#:
UTF8Encoding enc = new UTF8Encoding();
byte[] secretKey = enc.GetBytes(secretAccessKey);
HMACSHA256 hmac = new HMACSHA256(secretKey);
hmac.Initialize();
byte[] bytes = enc.GetBytes(data);
byte[] rawHmac = hmac.ComputeHash(bytes);
string result = Convert.ToBase64String(rawHmac);
The byte arrays “secretKey” and “bytes” are equivalent but the byte array “rawHmac” is different, and the string “result” is different. Can anyone see why?
Don’t do this:
That will use the platform default encoding to convert a string to a byte array. That can vary between platform, whereas you want something repeatable. I would suggest UTF-8:
(Do the same for the key, of course.)
You should then use the same encoding in your C# – not ASCII, unless you really want to not handle non-ASCII characters.
It’s also not clear how you’re comparing the results afterwards – don’t forget that
byteis signed in Java, but unsigned in C#. It’s probably simplest to convert the hash to hex or base64 for comparison purposes.EDIT: I strongly suspect the last part was the problem – comparing the results.
Here are two short but complete programs (using the iharder.net base64 converter in Java) which produce the same base64 output:
Java:
C#:
Output from both: