c#和java - hmacsha256 hash之间的区别

Posted

技术标签:

【中文标题】c#和java - hmacsha256 hash之间的区别【英文标题】:c# and java - difference between hmacsha256 hash 【发布时间】:2022-01-10 14:29:29 【问题描述】:

我在 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”不同。有谁知道为什么?

【问题讨论】:

还应该说“data”和“secretKey”是等价的字符串 【参考方案1】:

这是一个非问题,正如所证明的那样,哈希值始终相同。

在我的情况下,问题是无关的,Java 大写百分比编码在 UrlEncoder 上但 .NET 没有。

说明独立测试的重要性!

【讨论】:

【参考方案2】:

不要这样做:

byte[] bytes = data.getBytes();

这将使用平台默认编码将字符串转换为字节数组。这可能因平台而异,而您想要可重复的东西。我建议使用 UTF-8:

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

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

然后你应该在你的 C# 中使用相同的编码 - not ASCII,除非你真的不想处理非 ASCII 字符。

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

也不清楚您之后如何比较结果 - 不要忘记byte 是用 Java 签名的,但在 C# 中是未签名的。将哈希转换为十六进制或 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=

【讨论】:

谢谢,但正如我所说,bytes[] 在两种语言中都包含相同的数字。因此,尽管您的 cmets 很有帮助,但它们并不能解决问题 @GregT:他们至少解决了一个问题。也请参阅我的最后一段 - 你没有给我们任何关于你如何比较这些的迹象。如果您可以编辑您的问题以提供两个简短但完整的程序来演示该问题,那将使生活更轻松。 谢谢,现在完成了。我不知道字节之间的区别。 @GregT:我已经编辑了我的答案以显示简短但完整的程序 do 给出相同的答案。您能否以显示不同答案的方式编辑您的问题? (你给出的代码还不完整。) @GregT:嗯,此时您应该可以使用我创建的两个独立程序,并提供一个显示差异的密钥/数据对。

以上是关于c#和java - hmacsha256 hash之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 等效于 C# HMACSHA256

hmac-sha256 2021-11-02

C#实现HMACSHA256加密算法

Java - 使用 HMACSHA256 作为 PRF 的 PBKDF2

JWT Web 令牌加密 - SecurityAlgoritms.HmacSha256 与 SecurityAlgoritms.HmacSha256Signature

HmacSHA256 算法