c#和java – hmacsha256哈希之间的区别

我在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); 

以及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); 

字节数组“secretKey”和“bytes”是等价的,但字节数组“rawHmac”是不同的,字符串“result”是不同的。 谁能明白为什么?

不要这样做:

 byte[] bytes = data.getBytes(); 

这将使用平台默认编码将字符串转换为字节数组。 这可以在平台之间变化,而你想要可重复的东西。 我建议使用UTF-8:

 byte[] bytes = data.getBytes("UTF-8"); 

(当然,为密钥做同样的事。)

然后,您应该在C#中使用相同的编码 – 而不是 ASCII,除非您真的不想处理非ASCII字符。

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

还不清楚你之后如何比较结果 – 不要忘记该byte是用Java签名的,但是在C#中是无符号的。 为了进行比较,将哈希转换为hex或base64可能是最简单的。

编辑:我强烈怀疑最后一部分是问题 – 比较结果。

这里有两个简短但完整的程序(使用Java中的iharder.net base64转换器),它产生相同的base64输出:

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)); } } 

两者的输出:

 ivEyFpkagEoghGnTw/LmfhDOsiNbcnEON50mFGzW9/w= 

这是一个非问题,如所示,哈希总是相同的。

我的案例中的问题是无关紧要的,Java在UrlEncoder上编码百分比编码但.NET没有。

去表明孤立地测试是多么重要!