无法获得相同的hmac_sha1结果为java和c#(winrt)
我想转换一个基于java的代码为c#,如下所示;无法获得相同的hmac_sha1结果为java和c#(winrt)
原始的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;
}
所以这里是相应的outpus;
(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的输出不相等。有任何想法吗?我运行编码问题?
只是保持简单,代码相同。
的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
的三大秘诀:
当我测试你的Java代码,我收到了STR3这个值:
f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163
这不同于Java和C#的结果发表你。 (This online tool也计算我的结果。)Wikipedia包含一个example,它似乎是正确的基于Java代码和在线计算器。在第一步中,使用
"The quick brown fox jumps over the lazy dog", "key", "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
三元组测试Java和C#代码。使用BigInterger.toString(16)将字节数组转换为十六进制字符串不是一个好主意,因为当字节数组以一个或多个零位(或hexit?)开头时,转换后的十六进制字符串将不会包含前导0个字符。
你是对的,[代码](https://compilr.com/raistlinthewiz/hmac-sha1-test)计算f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163作为输出。现在尝试修复我的C#代码。 – HuseyinUslu
现在我得到一个完全不同的哈希70F4E22B2600225A3151727323B0CAB40B325045与[c#代码](https://compilr.com/raistlinthewiz/hmac-sha1-csharp-test)使用.net 4.0的System.Security.Cryptography的东西。我现在完全困惑.. – HuseyinUslu
你正在混淆字节与字符串。 getBytes()
的结果取决于默认character-encoding,这可能因系统而异。
所以任何想法在基于Windows的主机上的Java的默认编码? – HuseyinUslu
@HuseyinUslu它依赖于它似乎的语言设置。一般而言,它不是* UTF-8,而是基于ISO 8859标准的Windows专有方案之一,用于8位字符编码。对于任何ASCII码,它们和UTF-8应该是兼容的。没有其他的东西(包含相当常见的基于UTF-16的方案)。 –
我会是怎样写评论我如果你对这个问题投了反对票。 – HuseyinUslu
对于不清楚C#和Java输出可能不正确的情况,不要修改您的问题。这是一个相当本地化的问题。调试的最佳方法是在将其传递到HMAC代码之前,使用(更好的)十六进制编码打印出所有密钥和数据。 –