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

时间:2012-11-05 17:42:39

标签: c# java encryption hmac sha256

我在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”是不同的。谁能明白为什么?

2 个答案:

答案 0 :(得分:12)

不要这样做:

byte[] bytes = data.getBytes();

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

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

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

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

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

之后还不清楚你是如何比较结果的 - 不要忘记byte是用Java签名的,但是在C#中没有签名。为了进行比较,将哈希转换为十六进制或base64可能是最简单的。

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

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

爪哇:

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=

答案 1 :(得分:1)

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

我的案例中的问题是无关的,事实上Java在UrlEncoder上编码百分比编码,但.NET不编码。

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