我正在处理一个使用API的项目,我需要为web服务调用头生成签名。API文档提供了一些具有"已知良好"结果的PHP示例代码,因此您可以将其转换为您选择的编程语言,我遇到了困难,需要一些帮助。
我以前从未与HMAC合作过,所以这对我来说是全新的,我非常感谢提供任何反馈。
基本上API提供了一个示例PHP脚本及其结果,这样您就可以编写它的版本并对其进行测试。
以下是PHP示例及其结果。我将在下面的相同代码中发布我当前的C#尝试。再次,提前感谢您所能提供的任何帮助。
Use the following code example to compare your signature generation with a
known signature. The PHP code example that follows provides a reference to
the generation of a signature for a GET call into the CDRN API. Use your
code with the parameter values listed to validate the same signature is
generated.
<?php
$cdrn_domain = "api.testing.cdrn.com";
$secret_key = "cdrnpassword";
$api_version = "1.1";
$method_type = "GET";
$case_id = "12345";
$string_date = "2014-06-20T12:06:31Z";
$string_to_sign = $method_type . "n" . $cdrn_domain . "n" . "/partners/cases/$case_id" . "n" . "" . "n" . $api_version . "n" . $string_date . "n";
$signature = utf8_encode(base64_encode(hash_hmac('sha1', $string_to_sign, $secret_key, false)));
echo "SIGNATURE[$signature]";
?>
输出:签名[NWY3N2Q0NTdmZDQxZjA4YWI0Njg3YTEwODljODdiNTEwMTdmMzNlZg===]
这是我需要帮助的C#代码:
using System.Security.Cryptography;
string cdrn_domain = "api.testing.cdrn.com";
string secret_key = "cdrnpassword";
string api_version = "1.1";
string method_type = "GET";
string case_id = "12345";
string string_date = "2014-06-20T12:06:31Z";
string string_to_sign = method_type + "n" + cdrn_domain + "n" + "/partners/cases/" + case_id + "n" + "" + "n" + api_version + "n" + string_date + "n";
var result = CreateSignature(string_to_sign, secret_key);
public string CreateSignature(string message, string key)
{
var encoding = new System.Text.UTF8Encoding();
byte[] keyByte = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha1 = new HMACSHA1(keyByte, false))
{
byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage);
}
}
MY C#代码生成的签名为:X3fUV/1B8Iq0aHoQich7UQF/M+8=
这里的问题是因为您(或API)对错误的哈希值进行了编码。
来自hash_hmac
:的PHP文档
string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] )
参数
原始输出
nbsp nbsp 当设置为TRUE时,输出原始二进制数据FALSE输出小写十六进制。
所以这条线:
$signature = utf8_encode(base64_encode(hash_hmac('sha1', $string_to_sign, $secret_key, false)));
它不是生成base64编码的HMAC哈希值,而是实际生成HMAC哈希本身的一个…base64编码字符串的小写十六进制值。。。UTF-8\_(ツ)_/
您应该注意到,通过将hash_mac
的第三个参数从false
替换为true
,它实际上会产生与C#函数相同的值。
$signature = utf8_encode(base64_encode(hash_hmac('sha1', $string_to_sign, $secret_key, true)));
演示:ideone.com/lyrgKV
显然,为了从您的方面(C#)修复与API输出匹配的问题,我们需要在将哈希编码为base64:之前降低哈希的大小
public static string CreateSignature(string message, string key)
{
var encoding = new System.Text.UTF8Encoding();
byte[] keyByte = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha1 = new HMACSHA1(keyByte, false))
{
byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
string hashstring = BitConverter.ToString(hmacsha1.ComputeHash(messageBytes)).Replace("-","").ToLower();
return Convert.ToBase64String(encoding.GetBytes(hashstring));
}
}
演示:dotnetfiddle.net/FT4OQ4