对于支付提供商,我需要使用HMAC-SHA256计算基于哈希的消息身份验证码。这给我带来了不少麻烦。
支付提供商给出了两个在伪码中正确计算身份验证码的示例。所有键均为十六进制。
key = 57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66
message = "amount=100¤cy=EUR"
MAC = HMAC-SHA256( hexDecode(key), message )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
message = "amount=100¤cy=EUR"
Ki = 61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950
Ko = 0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a
MAC = SHA256( hexDecode(Ko) + SHA256( hexDecode(Ki) + message ) )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
在做了一些研究之后,我试图编写代码来实现这一点,但我不断得出不同的结果。
private static void Main(string[] args)
{
var key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
var ki = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
var ko = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
var mm = "amount=100¤cy=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;
}
这是我得到的结果:
Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
Actual 1: 421ce16f2036bb9f2a3770c16f01e9220f0232d45580584ca41768fd16c15fe6
Actual 2: 290f14398bf8c0959dfc963e2fd9c377534c6fec1983025d2ab192382f132b92
因此,使用这两种方法中的任何一种,我都可以得到提供者示例想要的结果。
我错过了什么?它是编码吗?我的hexDecode坏了吗?
支付提供商提供的测试工具:http://tech.dibs.dk/dibs_api/other_features/hmac_tool/
PHP示例代码:http://tech.dibspayment.com/dibs_api/other_features/mac_calculation/
您可以将此方法用于HMACSHA256。
string key = "your key";
string message = "your message";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return ByteToString(hashmessage);
以下是ByteToString方法:
public static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
以下是一种字符串扩展方法,用于为给定字符串获取相当标准的HMAC SHA 256标记:
用法:
myMessageString.HmacSha256Digest(mySecret)
字符串扩展方法:
public static string HmacSha256Digest(this string message, string secret)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
编辑:您可能正在寻找一种快速而简单的方法来执行HMAC-SHA256,而不是深入到更精细的细节中。最初的问题询问了下面将进一步解释的更详细的细节。
using System.Security.Cryptography;
...
private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
在里面NET 5及以上版本,请使用系统。转换FromHexString(谢谢@proximab)就是这样。如果你在预科班。NET 5中,滚动到“Helper functions”,其中有其他解决方案。
using System;
using System.Security.Cryptography;
...
private static byte[] HashHMACHex(string keyHex, string messageHex)
{
var key = Convert.FromHexString(hexKey);
var message = Convert.FromHexString(messageHex);
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
继续阅读。您可能希望使用下面的“方法2”作为参考点,并将其调整为您的服务希望您实现HMAC以防消息篡改。
在这里,我们将手动计算HMAC-SHA256(这回答了原始问题中的“方法2”)。
假设outerKey
、innerKey
和消息
已经是字节数组,我们执行以下操作:
表示法:假设A B连接字节数组A和B。您也可以在更多学术设置中看到A B表示法。
HMAC = SHA256( outerKey + SHA256( innerKey + message ) )
. . `------------------´ . .
\ \ `innerData` / /
\ `------------------------´ /
\ `innerHash` /
`----------------------------------´
`data`
因此,可以将代码分解为以下步骤(以上述步骤为指导):
为了进行字节复制,我使用了Buffer。BlockCopy()
函数,因为它显然比其他一些方式(源)更快。
n、 b.使用新的ReadOnlySpan,可能有更好的方法(请阅读:最肯定的方法)来实现这一点
我们可以将这些步骤转化为以下内容:
using System;
using System.Security.Cryptography;
...
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;
}
您有纯ASCII或UTF8文本,但需要它是字节[]
使用ASciencoding或UTF8Encoding,或您正在使用的任何外来编码。
private static byte[] StringEncode(string text)
{
var encoding = new System.Text.ASCIIEncoding();
return encoding.GetBytes(text);
}
您有一个字节[],但必须是十六进制字符串。
private static string HashEncode(byte[] hash)
{
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
您有一个十六进制字符串,但必须是字节[]`。
.净值5及以上
private static byte[] HexDecode(string hex) =>
System.Convert.FromHexString(hex);
之前净5(感谢@bobince)
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;
}
n、 如果你需要一个性能优化的版本。NET Framework 4。x、 您也可以对进行后端口。NET 5版本(通过替换ReadOnlySpan
为了完整起见,以下是使用“方法1”和“方法2”回答问题的最终方法
“方法1”(使用.NET库)
private static string HashHMACHex(string keyHex, string message)
{
byte[] hash = HashHMAC(HexDecode(keyHex), StringEncode(message));
return HashEncode(hash);
}
“方法2”(手动计算)
private static string HashSHAHex(string innerKeyHex, string outerKeyHex, string message)
{
byte[] hash = HashSHA(HexDecode(innerKeyHex), HexDecode(outerKeyHex), StringEncode(message));
return HashEncode(hash);
}
我们可以使用控制台应用程序快速执行健全性检查:
static void Main(string[] args)
{
string message = "amount=100¤cy=EUR";
string expectedHex = "b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905";
Console.WriteLine("Expected: " + expectedHex);
// Test out the HMAC hash method
string key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
string hashHMACHex = HashHMACHex(key, message);
Console.WriteLine("Method 1: " + hashHMACHex);
// Test out the SHA hash method
string innerKey = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
string outerKey = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
string hashSHAHex = HashSHAHex(innerKey, outerKey, message);
Console.WriteLine("Method 2: " + hashSHAHex);
}
您应该正确排列所有哈希:
Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
Method 1: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
Method 2: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
此答案的原始代码可访问:http://pastebin.com/xAAuZrJX
我在运行测试脚本后收到一个错误。我已经在其他测试脚本中运行了相同的方法,但我使用的这个脚本几乎与其他测试脚本相同。你能帮助我为什么会出现这个错误吗? 这是获取excel数据的方法。 这是我的数据提供程序方法
我有一个包含2列测试数据的xls文件。对于每一列,我都希望有一个测试方法。 现在我知道了如何使用dataprovider读取xls文件并将测试数据提供给一个测试方法。但如何使用同一个dataprovider进行多个测试呢? 我有下面的代码,一旦我运行这个代码得到错误,我的代码是: =========================================================默认
本文向大家介绍IIS7.5 提示未在本地计算机上注册“Microsoft.Jet.OleDb.4.0”提供程序,包括了IIS7.5 提示未在本地计算机上注册“Microsoft.Jet.OleDb.4.0”提供程序的使用技巧和注意事项,需要的朋友参考一下 在WIN7 X64平台IIS7.5,使用Asp.net连接access数据库时候,提示:未在本地计算机上注册“Microsoft.Jet.Ole
商家支付回调接口 url POST http://callback_url 回调参数说明 参数 类型 描述 uid string 百度用户ID order_id string 百度网盘订单号 third_order_id string 业务方订单号 pay_no string 支付流水号 pay_time int 支付时间 ts int 当前时间戳 sign string 签名参数(对以上参数按照
同公众号支付
说明 支付宝小程序支付交易SDK。 官方文档:https://opendocs.alipay.com/open/204/105465/ 类 请求参数类 APP支付参数 类名:\Yurun\PaySDK\AlipayApp\MiniApp\Params\Pay\Request 属性 名称 类型 说明 $method string 接口名称 $notify_url string 支付宝服务器主动通知商