在尝试将HMACSHA256(哈希)集成到不同的编程语言时,我遇到了一个问题。我尝试使用Java和C#中的标准预定义方法来实现标准算法,并且使用不同的语言会得到不同的结果。请在下面查看我在Java和C#中的实现:
Java:
public static String convertSHAWithSalt(String value, String salt)
throws NoSuchAlgorithmException, InvalidKeyException {
String data = "";
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt.getBytes(StandardCharsets.UTF_8));
byte[] bytes = md.digest(value.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
data = sb.toString();
System.out.println(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
字符串值'abcd'和空盐值的结果:88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589
C#:
public static string createHash(string message, string secret)
{
byte[] keyByte = System.Text.Encoding.UTF8.GetBytes(secret);
byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return BitConverter.ToString(hashmessage).Replace("-", "").ToLower();
}
字符串值'abcd'和空盐值的结果:527ff4c28c22a090fe39908139363e81b8fb10d0695a135518006abfa21cf5a2
请说明为什么两个结果都不同。我也在Java中尝试了以下实现,但不适用于空盐值:
public static String convertSHAWithSalt(String value, String salt)
throws NoSuchAlgorithmException, InvalidKeyException {
String data = "";
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretkey = new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256Hmac.init(secretkey);
data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
System.out.println(data);
}
答案 0 :(得分:1)
SHA-256
和HMAC-SHA-256
之间有一个difference。
HMAC-SHA-256
(另请参见HMAC
)是一种使用MAC
-哈希算法生成SHA-256
的算法。
第一个Java代码和C#代码的结果不同,因为Java代码使用SHA-256
和C#代码HMAC-SHA-256
。
由于您要使用HMAC-SHA-256
,因此我专注于此,而忽略了第一个Java代码。
文本的C#代码结果
This is an arbitrary text!
使用键
1234567890
是
25583e6e0b6c2c3a5c50ebd9ea48138a960a7ca2a215fae2b4b82ee99734deb4
第二个Java代码也使用HMAC-SHA-256
。如果您替换行
data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
System.out.println(data);
使用
data = bytesToHex(sha256Hmac.doFinal(value.getBytes(StandardCharsets.UTF_8)));
return data;
然后,输出是相同的(前提是您的(未发布)bytesToHex
方法以正确的方式工作,请参见How to convert a byte array to a hex string in Java?)。
顺便说一句,在第二个Java代码中,您应该将标签salt
更改为key
之类的,因为这是MAC
上下文中的常用措词。 salt通常与第一个Java代码中的密码哈希结合使用。
注意:在Java代码中,不允许将空字节数组用作SecretKeySpec
-输入。这将引发IllegalArgumentException (Empty key)
。但是,C#代码中的HMACSHA256
-ctor接受一个空字节数组,并在内部用0值填充。因此,对于您的测试用例(文本:abcd
,空键),您可以在Java代码中通过包含单个0值的字节数组来模拟空字节数组。然后,Java代码的输出等于C#代码的输出。当然,空键只能用于该测试用例。