将HMAC-SHA1 PHP脚本转换为C#脚本

时间:2016-07-29 06:58:57

标签: c# php hmacsha1

我正在开发一个使用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]";
    ?>

输出:         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 个答案:

答案 0 :(得分:1)

这里的问题是因为您(或API )正在编码错误的哈希值。

来自hash_hmac的PHP文档:

  

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

     

<强>参数

     

...

     

<强> raw_output

     

设置为 TRUE 时,输出原始二进制数据。 FALSE 输出小写的十六进制。

所以这一行:

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

而不是产生base64编码的HMAC哈希值,它实际上产生了一个...... base64编码的HMAC哈希值的小写 - 十六进制值的字符串本身...在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