使用c#计算HMACSHA256以匹配付款提供商示例 [英] Calculating HMACSHA256 using c# to match payment provider example

查看:1948
本文介绍了使用c#计算HMACSHA256以匹配付款提供商示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于付款服务提供商,我需要使用HMAC-SHA256计算基于散列的邮件验证码。这导致了很多麻烦。



付款提供商给出了两个伪代码中正确计算的验证码的例子。所有按键都在十六进制。



方法1



 键= 57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66 
消息=金额= 100安培;货币= EUR
的MAC = HMAC-SHA256(hexDecode(密钥),消息)
结果= b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905



方法2



  message =amount = 100& ;货币= EUR
文= 61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950
柯= 0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a
的MAC = SHA256(hexDecode(KO)+ SHA256(hexDecode(KI)+消息))
结果= b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905

我试图写代码来做这个,做了一些研究,但我不断提出不同结果。

 私有静态无效的主要(字串[] args)
{
VAR键=57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66 ;
VARき=61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950;
无功阁=0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a;
var mm =amount = 100& currency = EUR;

var result1 = CalcHMACSHA256Hash(HexDecode(key),mm);

var result2 = CalcSha256Hash(string.Format({0} {1},HexDecode(ko),CalcSha256Hash(HexDecode(ki)+ mm)

Console.WriteLine(Expected:b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905);
Console.WriteLine(Actual 1:+ result1);
Console.WriteLine(Actual 2:+ result2);

Console.WriteLine(------------------------------);
Console.ReadKey();

}

私人静态字符串HexDecode(字符串十六进制)
{
var sb = new StringBuilder();
for(int i = 0; i <= hex.Length - 2; i + = 2)
{
sb.Append(Convert.ToChar(Int32.Parse (hex.Substring(i,2),System.Globalization.NumberStyles.HexNumber))));
}
return sb.ToString();
}

私人静态字符串CalcHMACSHA256Hash(string plaintext,string salt)
{
string result =;
var enc = Encoding.Default;
byte []
baText2BeHashed = enc.GetBytes(plaintext),
baSalt = enc.GetBytes(salt);
System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt);
byte [] baHashedText = hasher.ComputeHash(baText2BeHashed);
result = string.Join(,baHashedText.ToList()。Select(b => b.T​​oString(x2))。ToArray());
return result;
}


public static string CalcSha256Hash(string input)
{
SHA256 sha256 = new SHA256Managed();
byte [] sha256Bytes = Encoding.Default.GetBytes(input);
byte [] cryString = sha256.ComputeHash(sha256Bytes);
string sha256Str = string.Empty;
for(int i = 0; i {
sha256Str + = cryString [i] .ToString(x2);
}
return sha256Str;
}

这是我得到的结果:


b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
实际值1:421ce16f2036bb9f2a3770c16f01e9220f0232d45580584ca41768fd16c15fe6
实际2:290f14398bf8c0959dfc963e2fd9c377534c6fec1983025d2ab192382f132b92

 预期$ p> 

所以没有两个方法,我可以得到提供者示例想要的结果。



我在这里缺少什么?是编码吗?我的hexDecode是否已损坏?



通过付款服务提供商测试工具: http://tech.dibs.dk/dibs_api/other_features/hmac_tool/



PHP示例代码:http://tech.dibspayment.com/dibs_api/other_features/mac_calculation/

解决方案

我已经完全解决了您的问题(因为这可能是您要找的)。



概述



程序可以组织为到三个部分:


  1. 哈希函数 - 这些实际函数将使用 byte [] 用于输入

  2. 编码助手 - 这些用于哈希十六进制函数帮助转换以下内容:


    • string - > byte []

    • byte [] - > hex string

    • hex string - > byte [] (感谢@bobince!


  3. Hash十六进制函数 - 这些是帮助函数,使用十六进制字符串作为输入。



代码



< h2> 0。使用语句

在开始之前,请确保您具有以下使用语句,这样就不会因为包含错误而产生大量错误。 p>

 使用System; 
using System.Globalization;
using System.Security.Cryptography;
using System.Text;



1。哈希函数



HMAC-SHA256(方法1)



这将计算HMAC-SHA256 )。正如你所看到的,它比方法2要简单得多,但结果相同。

  private静态字节[] HashHMAC(byte [] key,byte [] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}



SHA256(方法2)


$ b b

现在,使用一吨SHA哈希计算哈希(你的方法2),它是一个更多的参与。这基本上与没有十六进制解码的伪代码相同,而是使用 byte [] 代替。这将如下所示:

  MAC = SHA256(outerKey + SHA256(innerKey + message))

而不是您的:

  MAC = SHA256(hexDecode(outerKey)+ SHA256(hexDecode(innerKey)+ message))

c $ c> outerKey innerKey 信息都是 byte [] s。当然,在这种情况下,所有的键已经从十六进制字符串解码,但也可以 byte []



所以代码可以分解到这些步骤:


  1. 创建内部数据和存储它在 byte [] innerData

  2. 复制 innerKey 现在计算散列 c $ c> innerData 并将其存储在 byte [] innerHash

  3. byte [] data
  4. 创建一个缓冲区
  5. 复制 outerKey innerHash ,先前计算的散列(从#3)到数据

  6. 计算数据的最后一个散列,并将其存储在 result 中并返回。

要进行字节复制,我使用 Buffer.BlockCopy() 函数,因为它显然比一些其他方式href =http://stackoverflow.com/questions/895120/append-2-byte-arrays-in-c-sharp>来源)。
那些步骤可以写成这样的代码:

  private static byte [] HashSHA(byte [] innerKey ,byte [] outerKey,byte [] message)
{
var hash = new SHA256Managed();

//计算内部数据的哈希值
byte [] innerData = new byte [innerKey.Length + message.Length];
Buffer.BlockCopy(innerKey,0,innerData,0,innerKey.Length);
Buffer.BlockCopy(message,0,innerData,innerKey.Length,message.Length);
byte [] innerHash = hash.ComputeHash(innerData);

//计算整个散列
byte [] data = new byte [outerKey.Length + innerHash.Length];
Buffer.BlockCopy(outerKey,0,data,0,outerKey.Length);
Buffer.BlockCopy(innerHash,0,data,outerKey.Length,innerHash.Length);
byte [] result = hash.ComputeHash(data);

返回结果;
}



2。辅助函数



在我们得到哈希十六进制函数之前,需要一些函数来帮助在概述中描述的事情之间进行转换。



string - > byte []



字符串编码假设文本是纯ASCII,似乎工作(现在)。虽然,如果你需要使用花哨的符号编码,你可能需要使用UTF8。如果是这种情况,请关闭 ASCIIEncoding UTF8Encoding 或对您的使用进行编码。

  private static byte [] StringEncode(string text)
{
var encoding = new ASCIIEncoding();
return encoding.GetBytes(text);
}



byte [] - > hex string



这是一个字节数组,串。很简单。

 私人静态字串HashEncode(byte [] hash)
{
return BitConverter.ToString (hash).Replace( - ,).ToLower();
}



hex string > byte []



最后是将十六进制字符串转换为字节数组。这来自@ bobince的答案,所以它不是我的。

 私人静态字节[] HexDecode(字符串十六进制)
{
var bytes = new byte [hex.Length / 2];
for(int i = 0; i {
bytes [i] = byte.Parse(hex.Substring(i * 2,2),NumberStyles .HexNumber);
}
return bytes;
}



3。 Hash十六进制函数



如前所述,这些是帮助函数,它们使用十六进制数据和字符串来处理散列函数。它们是不言自明的:



HMAC的六边形哈希



 私有静态字符串HashHMACHex(string keyHex,string message)
{
byte [] hash = HashHMAC(HexDecode(keyHex),StringEncode(message));
return HashEncode(hash);
}



SHA的六边形散列



 私人静态字串HashSHAHex(string innerKeyHex,string outerKeyHex,string message)
{
byte [] hash = HashSHA(HexDecode(innerKeyHex),HexDecode(outerKeyHex ),StringEncode(message));
return HashEncode(hash);
}



4。控制台测试



这里是一个控制台程序,它会调用函数来显示它们实际上正常工作。

  static void Main(string [] args)
{
string message =amount = 100& currency = EUR
string expectedHex =b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905;
Console.WriteLine(Ref:+ expectedHex);

//测试HMAC哈希方法
string key =57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66;
string hashHMACHex = HashHMACHex(key,message);
Console.WriteLine(HMAC:+ hashHMACHex);

//测试SHA哈希方法
string innerKey =61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950;
string outerKey =0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a;
string hashSHAHex = HashSHAHex(innerKey,outerKey,message);
Console.WriteLine(SHA:+ hashSHAHex);

Console.ReadLine();
}

如果一切顺利,运行没有错误,您应该得到以下输出显示所有散列是正确的( ref 是预期的散列):

 编号:b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905 
HMAC:b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
SHA:b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905



结论



最后,为了确保一切正常,可以在以下位置找到代码:

http://pastebin.com/xAAuZrJX


For a payment provider, I need to calculate a hash-based message authentication code, using HMAC-SHA256. That is causing me quite a bit of trouble.

The payment provider gives two examples of orrectly calculated authentication code in pseudo-code. All keys are in hex.

Method 1

key = 57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66
message = "amount=100&currency=EUR"
MAC = HMAC-SHA256( hexDecode(key), message )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905

Method 2

message = "amount=100&currency=EUR"
Ki = 61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950
Ko = 0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a
MAC = SHA256( hexDecode(Ko) + SHA256( hexDecode(Ki) + message ) )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905

I tried to write the code to do this, after doing some research, but I keep coming up with different results.

private static void Main(string[] args)
    {
        var key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
        var ki = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
        var ko = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
        var mm = "amount=100&currency=EUR";

        var result1 = CalcHMACSHA256Hash(HexDecode(key), mm);

        var result2 = CalcSha256Hash(string.Format("{0}{1}", HexDecode(ko), CalcSha256Hash(HexDecode(ki) + mm)));

        Console.WriteLine("Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905");
        Console.WriteLine("Actual 1: " + result1);
        Console.WriteLine("Actual 2: " + result2);

        Console.WriteLine("------------------------------");
        Console.ReadKey();

    }

    private static string HexDecode(string hex)
    {
        var sb = new StringBuilder();
        for (int i = 0; i <= hex.Length - 2; i += 2)
        {
            sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber))));
        }
        return sb.ToString();
    }

    private static string CalcHMACSHA256Hash(string plaintext, string salt)
    {
        string result = "";
        var enc = Encoding.Default;
        byte[]
        baText2BeHashed = enc.GetBytes(plaintext),
        baSalt = enc.GetBytes(salt);
        System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt);
        byte[] baHashedText = hasher.ComputeHash(baText2BeHashed);
        result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray());
        return result;
    }


    public static string CalcSha256Hash(string input)
    {
        SHA256 sha256 = new SHA256Managed();
        byte[] sha256Bytes = Encoding.Default.GetBytes(input);
        byte[] cryString = sha256.ComputeHash(sha256Bytes);
        string sha256Str = string.Empty;
        for (int i = 0; i < cryString.Length; i++)
        {
            sha256Str += cryString[i].ToString("x2");
        }
        return sha256Str;
    }

And this is the result I get:

Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
Actual 1: 421ce16f2036bb9f2a3770c16f01e9220f0232d45580584ca41768fd16c15fe6
Actual 2: 290f14398bf8c0959dfc963e2fd9c377534c6fec1983025d2ab192382f132b92

So with none of the two methods, I can get the result the provider example wants.

What am I missing here? Is it encoding? Is my hexDecode screwed up?

Test tool from payment provider: http://tech.dibs.dk/dibs_api/other_features/hmac_tool/

PHP sample code: http://tech.dibspayment.com/dibs_api/other_features/mac_calculation/

解决方案

I've made a complete solution to your issue (since that is probably what you were looking for). It calculates the correct hash using both your method 1 and 2.

Overview

The program can be organized in to three sections:

  1. Hash functions - these are the actual functions that will calculate the hashes using byte[] for input
  2. Encoding helpers - these are used with the the hash hex functions (#3) and help with converting the following:
    • string -> byte[]
    • byte[] -> hex string
    • hex string -> byte[] (thanks @bobince!)
  3. Hash hex functions - these are helper functions so that you can use the hash functions (#1) using hex string as input instead. These use the encoding helpers (#2) to do that.

Code

0. Using Statements

Before you get started, make sure to that you have the following using statements so that you don't get a ton of errors from not including them.

using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;

1. Hash functions

HMAC-SHA256 (Method 1)

This will calculate the HMAC-SHA256 (your method 1). As you can see, it is much simpler than method 2 but gives the same result.

private static byte[] HashHMAC(byte[] key, byte[] message)
{
    var hash = new HMACSHA256(key);
    return hash.ComputeHash(message);
}

SHA256 (Method 2)

Now to calculate the hash using a ton of SHA hashing (your method 2), it is a little bit more involved. This is basically the same as your pseudo-code without the hex decoding and uses byte[] for input instead. This would look like:

MAC = SHA256( outerKey + SHA256( innerKey + message ) )

Instead of your:

MAC = SHA256( hexDecode(outerKey) + SHA256( hexDecode(innerKey) + message ) )

Where outerKey, innerKey, and message are all byte[]s. Of course, in this case, all the keys have already been decoded from hexadecimal strings but it may as well been byte[]s too.

So the code can be broken down in to these steps:

  1. Create the buffer for the inner data and store it in byte[] innerData
  2. Copy the innerKey and the message to the byte[] innerData
  3. Now compute the SHA256 hash of innerData and store it in byte[] innerHash
  4. For the final and entire hash, create a buffer for it in byte[] data
  5. Copy the outerKey and innerHash, the previously computed hash (from #3), to the data
  6. Compute the final hash of data and store it in result and return it.

To do the byte copying I'm using the Buffer.BlockCopy() function since it apparently faster than some other ways (source). Those steps then can be written in code like this:

private static byte[] HashSHA(byte[] innerKey, byte[] outerKey, byte[] message)
{
    var hash = new SHA256Managed();

    // Compute the hash for the inner data first
    byte[] innerData = new byte[innerKey.Length + message.Length];
    Buffer.BlockCopy(innerKey, 0, innerData, 0, innerKey.Length);
    Buffer.BlockCopy(message, 0, innerData, innerKey.Length, message.Length);
    byte[] innerHash = hash.ComputeHash(innerData);

    // Compute the entire hash
    byte[] data = new byte[outerKey.Length + innerHash.Length];
    Buffer.BlockCopy(outerKey, 0, data, 0, outerKey.Length);
    Buffer.BlockCopy(innerHash, 0, data, outerKey.Length, innerHash.Length);
    byte[] result = hash.ComputeHash(data);

    return result;
}

2. Helper functions

Before we get to the hash hex function, you need a few functions to help with converting between things as said in the overview.

string -> byte[]

The string encoding assumes the text is plain ASCII and seems to work (for now). Though, if you need to encode with fancy symbols, you are probably going to need to use UTF8 instead. If that is the case, then switch out ASCIIEncoding with UTF8Encoding or what ever encoding your using.

private static byte[] StringEncode(string text)
{
    var encoding = new ASCIIEncoding();
    return encoding.GetBytes(text);
}

byte[] -> hex string

All this does is take an array of bytes and turn it to a lower-case hex string. Pretty simple.

private static string HashEncode(byte[] hash)
{
    return BitConverter.ToString(hash).Replace("-", "").ToLower();
}

hex string -> byte[]

Lastly is the conversion of a hex string to a byte array. This came from @bobince's answer so its not mine. Give credit where credit is due.

private static byte[] HexDecode(string hex)
{
    var bytes = new byte[hex.Length / 2];
    for (int i = 0; i < bytes.Length; i++)
    {
        bytes[i] = byte.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber);
    }
    return bytes;
}

3. Hash hex functions

As said before, these are the helper functions that work with the hash functions with hex data and strings instead. They are pretty self-explanatory:

Hex hashing for HMAC

private static string HashHMACHex(string keyHex, string message)
{
    byte[] hash = HashHMAC(HexDecode(keyHex), StringEncode(message));
    return HashEncode(hash);
}

Hex hashing for SHA

private static string HashSHAHex(string innerKeyHex, string outerKeyHex, string message)
{
    byte[] hash = HashSHA(HexDecode(innerKeyHex), HexDecode(outerKeyHex), StringEncode(message));
    return HashEncode(hash);
}

4. Console Test

Well to wrap all the functions together, here is a console program that will call the functions to show that they are actually working properly.

static void Main(string[] args)
{
    string message = "amount=100&currency=EUR";
    string expectedHex = "b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905";
    Console.WriteLine("Ref : " + expectedHex);

    // Test out the HMAC hash method
    string key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
    string hashHMACHex = HashHMACHex(key, message);
    Console.WriteLine("HMAC: " + hashHMACHex);

    // Test out the SHA hash method
    string innerKey = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
    string outerKey = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
    string hashSHAHex = HashSHAHex(innerKey, outerKey, message);
    Console.WriteLine("SHA : " + hashSHAHex);

    Console.ReadLine();
}

If everything went correctly and it ran without errors, you should get the following output showing that all the hashes are correct (ref is the expected hash):

Ref : b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
HMAC: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
SHA : b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905

Conclusion

Lastly, just to make sure everything worked, the code altogether can be found at:
http://pastebin.com/xAAuZrJX

这篇关于使用c#计算HMACSHA256以匹配付款提供商示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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