c# and java - difference between hmacsha256 hash

早过忘川 提交于 2019-11-27 15:06:28

问题


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?


回答1:


Don't do this:

byte[] bytes = data.getBytes();

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:

byte[] bytes = data.getBytes("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.

byte[] bytes = Encoding.UTF8.GetBytes(data);

It's also not clear how you're comparing the results afterwards - don't forget that byte is 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:

import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class Test {
    public static void main (String[] args) throws Exception {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = secretAccessKey.getBytes();
        SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        byte[] bytes = data.getBytes();
        byte[] rawHmac = mac.doFinal(bytes);
        System.out.println(Base64.encodeBytes(rawHmac));
    }
}

C#:

using System;
using System.Security.Cryptography;
using System.Text;

class Test
{
    static void Main()
    {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = Encoding.UTF8.GetBytes(secretAccessKey);
        HMACSHA256 hmac = new HMACSHA256(secretKey);
        hmac.Initialize();
        byte[] bytes = Encoding.UTF8.GetBytes(data);
        byte[] rawHmac = hmac.ComputeHash(bytes);
        Console.WriteLine(Convert.ToBase64String(rawHmac));
    }
}

Output from both:

ivEyFpkagEoghGnTw/LmfhDOsiNbcnEON50mFGzW9/w=



回答2:


This was a non-question, as demonstrated, the hashes are always the same.

The problem in my case was unrelated, the fact that Java uppercases percent encoding on UrlEncoder but .NET doesn't.

Goes to show how important it is to test in isolation!



来源:https://stackoverflow.com/questions/13237456/c-sharp-and-java-difference-between-hmacsha256-hash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!