【问题标题】:can't get the same hmac_sha1 results for java and c# (winrt)无法为 java 和 c# (winrt) 获得相同的 hmac_sha1 结果
【发布时间】:2012-11-24 12:52:14
【问题描述】:

我正在尝试将基于 java 的代码转换为 c#,如下所示;

原java代码;

String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*"

Mac localMac = Mac.getInstance("HmacSHA1");
localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve".getBytes(), localMac.getAlgorithm()));
String str3 = new BigInteger(1, localMac.doFinal(str2.getBytes())).toString(16);
Object[] arrayOfObject2 = new Object[2];
arrayOfObject2[0] = str3;
arrayOfObject2[1] = URLEncoder.encode(str2);
String str4 = String.format("%s:%s", arrayOfObject2);

这是我基于 WinRT 的 c# 代码

var token="5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";

var encoding = new System.Text.UTF8Encoding();
var key = encoding.GetBytes("Wd75Yj9sS26Lmhve");
//var key = Convert.FromBase64String("Wd75Yj9sS26Lmhve");

var tokenData = encoding.GetBytes(token);

var result = HmacSha1(key, tokenData);

var hexString = new BigInteger(result).ToString("x");
var urlEncoded = System.Net.WebUtility.UrlEncode(token);

var combined = String.Format("{0}:{1}", hexString, urlEncoded);

以及我在 WinRT 上运行时的 hmacsha1 函数;

    public static byte[] HmacSha1(byte[] key, byte[] data)
    {
        var crypt = Windows.Security.Cryptography.Core.MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
        var keyBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(key);
        var cryptKey = crypt.CreateKey(keyBuffer);

        var dataBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(data);
        var signBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.Sign(cryptKey, dataBuffer);

        byte[] result;
        Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(signBuffer, out result);

        return result;
    }

所以这是对应的输出;

(JAVA) 92e893efe72a2f7df6ed409ce35819faba191a63:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.*
  (C#) 63b10e1d8e9f99cd7fba2ed46fe8e4a4a40222f5:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.*

如上图,java和c#的HMAC_SHA1输出不相等。有任何想法吗?我在运行编码问题吗?

【问题讨论】:

  • 如果您对这个问题投反对票,我很乐意写评论。
  • 当很明显 C# 和 Java 输出可能不正确时,不修改您的问题。这是一个非常本地化的问题。调试此问题的最佳方法是在将所有密钥和数据传递到 HMAC 代码之前使用(更好的)十六进制编码打印出所有密钥和数据。

标签: c# java cryptography sha1 hmac


【解决方案1】:

保持简单,代码相同。

Java:

public static String toHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * 2);
    for (int i = 0; i < bytes.length; ++i) {
        sb.append(String.format("%02x", bytes[i]));
    }
    return sb.toString();
}

public static void main(String[] args) {
    String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";
    Mac localMac;
    try {
        localMac = Mac.getInstance("HmacSHA1");

        localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve"
                .getBytes("UTF-8"), localMac.getAlgorithm()));
        byte[] result = localMac.doFinal(str2.getBytes("UTF-8"));
        String hexString = toHexString(result);
        System.out.println(hexString);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

}

结果:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163

C#:

var token = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*";

var encoding = new System.Text.UTF8Encoding();
var privateKey = "Wd75Yj9sS26Lmhve";
HMACSHA1 hmac_sha1 = new HMACSHA1(encoding.GetBytes(privateKey));
hmac_sha1.Initialize();
byte[] result = hmac_sha1.ComputeHash(encoding.GetBytes(token));

string hexString = String.Join( "", result.Select( a => a.ToString("x2") ));

Console.WriteLine(hexString);

结果:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163

【讨论】:

    【解决方案2】:

    三个提示:

    1. 当我测试您的 Java 代码时,我收到了 str3 的这个值:f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163 这与您发布的 Java 和 C# 结果不同。 (This online tool 也会计算我的结果。)

    2. Wikipedia 包含一个example,根据 Java 代码和在线计算器,它似乎是正确的。第一步,使用 "The quick brown fox jumps over the lazy dog", "key", "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" 三元组测试您的 Java 和 C# 代码。

    3. 使用 BigInterger.toString(16) 将字节数组转换为十六进制字符串不是一个好主意,因为当字节数组以一个或多个零位(或十六进制?)开头时,转换后的十六进制字符串将不包含前 0 个字符。

    【讨论】:

    • 你是对的,the code 计算 f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163 作为输出。现在将尝试先修复我的 c# 代码。
    • 现在我得到了一个完全不同的哈希 70F4E22B2600225A3151727323B0CAB40B325045 和 c# code,它使用 .net 4.0 的 System.Security.Cryptography 东西。我现在完全糊涂了..
    【解决方案3】:

    您将字节与字符串混淆了。 getBytes() 的结果取决于默认的,可能因系统而异。

    【讨论】:

    • 那么关于 java 在基于 Windows 的主机上的默认编码有什么想法吗?
    • @HuseyinUslu 这取决于它看起来的语言设置。通常,它不是 UTF-8,而是 Windows 专有方案之一,它又基于 ISO 8859 8 位字符编码标准。对于任何 ASCII 它们 - 和 UTF-8 - 应该是兼容的。对于其他任何东西(包括非常常见的基于 UTF-16 的方案)来说都不算什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-29
    • 2021-02-17
    • 1970-01-01
    • 2020-12-16
    • 2013-12-16
    相关资源
    最近更新 更多