2016-07-29 101 views
0

我正在开发一个使用API​​的项目,并且需要为Web服务调用头生成一个签名。 API文档提供了一些带有“已知良好”结果的PHP示例代码,因此您可以将其转换为您选择的编程语言,并且我遇到了一堵墙,我需要一些帮助。将HMAC-SHA1 PHP脚本转换为C#脚本

我从来没有与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]"; 
    ?> 

输出: 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 =

回答

1

这里的问题是因为你(或API)正在编码错误的散列值。

从PHP文档hash_hmac

string hash_hmac (string $algo , string $data , string $key [, bool $raw_output = false ])

参数

...

raw_output

           当设置为TRUE时,输出原始二进制数据。 FALSE输出小写hexits。

因此该行:

$signature = utf8_encode(base64_encode(hash_hmac('sha1', $string_to_sign, $secret_key, false))); 

,而不是生成的base64编码的HMAC哈希值,它实际上会产生...的HMAC哈希的小写,十六进制值的base64编码字符串本身......在UTF-8 ...¯\ _(ツ)_ /¯

您应该注意到,从false更换的hash_mac的第三个参数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

+0

IronGeek,我根本就不会没有你想通了这一点r帮助先生!非常感谢您的解释和快速协助!马上接受你的回答! – Josh