HMC SHA1哈希 - Java生成不同的散列输出比C# [英] HMC SHA1 hash - Java producing different hash output than C#

查看:183
本文介绍了HMC SHA1哈希 - Java生成不同的散列输出比C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这一点的跟进的问题,但我正在尝试将C#代码移植到Java而不是Ruby代码到C#,就像相关问题一样。我试图验证Recurly.js api返回的加密签名是有效的。不幸的是,Recurly没有一个Java库来帮助验证,所以我必须自己实现签名验证。



根据上面的相关问题(这个),以下C#代码可以产生哈希需要验证从Recurly返回的签名:

  var privateKey = Configuration.RecurlySection.Current.PrivateKey; 
var hashedKey = SHA1.Create()。ComputeHash(Encoding.UTF8.GetBytes(privateKey));
var hmac = new HMACSHA1(hashedKey);
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(dataToProtect));
return BitConverter.ToString(hash).Replace( - ,).ToLower();

Recurly在他们的签名文档页面:


未加密的验证消息
[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]



私钥
0123456789ABCDEF0123456789ABCDEF



结果签名
0f5630424b32402ec03800e977cd7a8b13dbd153-1312701386




这是我的Java实现:

  String unencryptedMessage =[1312701386,transactioncreate [ACCOUNT_CODE:ABC,amount_in_cents:5000,货币:USD]]; 
String privateKey =0123456789ABCDEF0123456789ABCDEF;
String encryptedMessage = getHMACSHA1(unencryptedMessage,getSHA1(privateKey));

private static byte [] getSHA1(String source)throws NoSuchAlgorithmException,UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance(SHA-1);
byte [] bytes = md.digest(source.getBytes(UTF-8));
返回字节;
}

private static String getHMACSHA1(String baseString,byte [] keyBytes)throws GeneralSecurityException,UnsupportedEncodingException {
SecretKey secretKey = new SecretKeySpec(keyBytes,HmacSHA1);
Mac mac = Mac.getInstance(HmacSHA1);
mac.init(secretKey);
byte [] bytes = baseString.getBytes(ASCII);
返回Hex.encodeHexString(mac.doFinal(bytes));
}

但是,当我打印出encryptedMessage变量时,它与消息不匹配示例签名的一部分。具体来说,我得到一个值c8a9188dcf85d1378976729e50f1de5093fabb78而不是0f5630424b32402ec03800e977cd7a8b13dbd153。



更新



@ p @ Per @ M.Babcock,我用示例数据重新编写C#代码,并返回与Java代码相同的输出。所以看来我的哈希方法是正确的,但是我传递错误的数据(unencryptedMessage)。叹。如果/当我可以确定正确的加密数据时,我将更新此帖子,因为Recurly文档中提供的未加密的验证消息似乎缺少某些内容。



更新2



错误原来是未加密的验证消息数据/格式。示例数据中的消息实际上并不对提供的示例签名进行加密,因此也许过时的文档?无论如何,我已经确认Java实现将适用于真实世界的数据。感谢所有。

解决方案

我认为问题在于你的.NET代码。 Configuration.RecurlySection.Current.PrivateKey 返回一个字符串?这个价值是你期望的关键吗?



使用以下代码,.NET和Java返回相同的结果。



.NET代码

  string message =[1312701386,transactioncreate,[account_code:ABC,amount_in_cents :5000,货币:USD]]; 
string privateKey =0123456789ABCDEF0123456789ABCDEF;

var hashedKey = SHA1.Create()。ComputeHash(Encoding.UTF8.GetBytes(privateKey));
var hmac = new HMACSHA1(hashedKey);
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(message));

Console.WriteLine(Message:{0},message);
Console.WriteLine(Key:{0} \\\
,privateKey);
Console.WriteLine(Key bytes:{0},BitConverter.ToString(hashedKey).Replace( - ,).ToLower());
Console.WriteLine(Result:{0},BitConverter.ToString(hash).Replace( - ,).ToLower());

结果:

 
消息:[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
密钥:0123456789ABCDEF0123456789ABCDEF

密钥字节:4d857d2408b00c3dd17f0c4ffcf15b97f1049867
结果:c8a9188dcf85d1378976729e50f1de5093fabb78

Java

  String message =[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]; 
String privateKey =0123456789ABCDEF0123456789ABCDEF;

MessageDigest md = MessageDigest.getInstance(SHA-1);
byte [] keyBytes = md.digest(privateKey.getBytes(UTF-8));

SecretKey sk = new SecretKeySpec(keyBytes,HmacSHA1);
Mac mac = Mac.getInstance(HmacSHA1);
mac.init(sk);
byte [] result = mac.doFinal(message.getBytes(ASCII));

System.out.println(Message:+ message);
System.out.println(Key:+ privateKey +\\\
);
System.out.println(Key Bytes:+ toHex(keyBytes));
System.out.println(Results:+ toHex(result));

结果:

 
消息:[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
密钥:0123456789ABCDEF0123456789ABCDEF

密钥字节:4d857d2408b00c3dd17f0c4ffcf15b97f1049867
结果:c8a9188dcf85d1378976729e50f1de5093fabb78


This is a follow up to this question, but I'm trying to port C# code to Java instead of Ruby code to C#, as was the case in the related question. I am trying to verify the encrypted signature returned from the Recurly.js api is valid. Unfortunately, Recurly does not have a Java library to assist with the validation, so I must implement the signature validation myself.

Per the related question above (this), the following C# code can produce the hash needed to validate the signature returned from Recurly:

var privateKey = Configuration.RecurlySection.Current.PrivateKey;
var hashedKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(privateKey));
var hmac = new HMACSHA1(hashedKey);
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(dataToProtect));
return BitConverter.ToString(hash).Replace("-", "").ToLower();

Recurly provides the following example data on their signature documentation page:

unencrypted verification message: [1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]

private key: 0123456789ABCDEF0123456789ABCDEF

resulting signature: 0f5630424b32402ec03800e977cd7a8b13dbd153-1312701386

Here is my Java implementation:

String unencryptedMessage = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
String privateKey = "0123456789ABCDEF0123456789ABCDEF";
String encryptedMessage = getHMACSHA1(unencryptedMessage, getSHA1(privateKey));

private static byte[] getSHA1(String source) throws NoSuchAlgorithmException, UnsupportedEncodingException{
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] bytes = md.digest(source.getBytes("UTF-8"));
    return bytes;
}

private static String getHMACSHA1(String baseString, byte[] keyBytes) throws GeneralSecurityException, UnsupportedEncodingException {
    SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA1");
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(secretKey);
    byte[] bytes = baseString.getBytes("ASCII");
    return Hex.encodeHexString(mac.doFinal(bytes));
}

However, when I print out the encryptedMessage variable, it does not match the message portion of the example signature. Specifically, I get a value of "c8a9188dcf85d1378976729e50f1de5093fabb78" instead of "0f5630424b32402ec03800e977cd7a8b13dbd153".

Update

Per @M.Babcock, I reran the C# code with the example data, and it returned the same output as the Java code. So it appears my hashing approach is correct, but I am passing in the wrong data (unencryptedMessage). Sigh. I will update this post if/when I can determine what the correct data to encrypt is- as the "unencrypted verification message" provided in the Recurly documentation appears to be missing something.

Update 2

The error turned out to be the "unencrypted verification message" data/format. The message in the example data does not actually encrypt to the example signature provided- so perhaps outdated documentation? At any rate, I have confirmed the Java implementation will work for real-world data. Thanks to all.

解决方案

I think the problem is in your .NET code. Does Configuration.RecurlySection.Current.PrivateKey return a string? Is that value the key you expect?

Using the following code, .NET and Java return identical results.

.NET Code

string message = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
string privateKey = "0123456789ABCDEF0123456789ABCDEF";

var hashedKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(privateKey));
var hmac = new HMACSHA1(hashedKey);
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(message));

Console.WriteLine("  Message: {0}", message);
Console.WriteLine("      Key: {0}\n", privateKey);
Console.WriteLine("Key bytes: {0}", BitConverter.ToString(hashedKey).Replace("-", "").ToLower());
Console.WriteLine("   Result: {0}", BitConverter.ToString(hash).Replace("-", "").ToLower());

Result:

  Message: [1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
      Key: 0123456789ABCDEF0123456789ABCDEF

Key bytes: 4d857d2408b00c3dd17f0c4ffcf15b97f1049867
   Result: c8a9188dcf85d1378976729e50f1de5093fabb78

Java

String message = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
String privateKey = "0123456789ABCDEF0123456789ABCDEF";

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] keyBytes = md.digest(privateKey.getBytes("UTF-8"));

SecretKey sk = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(sk);
byte[] result = mac.doFinal(message.getBytes("ASCII"));

System.out.println("  Message: " + message);
System.out.println("      Key: " + privateKey + "\n");
System.out.println("Key Bytes: " + toHex(keyBytes));
System.out.println("  Results: " + toHex(result));

Result:

  Message: [1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
      Key: 0123456789ABCDEF0123456789ABCDEF

Key Bytes: 4d857d2408b00c3dd17f0c4ffcf15b97f1049867
  Results: c8a9188dcf85d1378976729e50f1de5093fabb78

这篇关于HMC SHA1哈希 - Java生成不同的散列输出比C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆