如何在PHP中复制此C#散列? (toByteArray(),ComputeHash())

时间:2013-06-21 11:44:45

标签: c# php sha1 hmac

我正在尝试复制PHP中的以下代码,它是我必须与之接口的API的示例代码(API和示例代码位于C#,我的应用位于{ {1}})。我不是C#开发人员,所以我很难做到这一点。

PHP 5.3

我使用pack()和我在网上找到的其他功能尝试了很多变化,但没有任何可比性,我不知道我是否做得对。

任何C#开发人员都可以运行上面的代码并发布生成的值,以便我可以使用它来检查/测试吗?

我已经尝试检查MSDN以查看这些方法的作用,但是卡住了(并且不确定它是否正确,因为我没有什么要比较它)。

PHP伪代码

// C# Code I am trying to replicate in PHP
var apiTokenId = 1887;
var apiToken = "E1024763-1234-5678-91E0-T32E4E7EB316";

// Used to authenticate our request by the API (which is in C#)
var stringToSign = string.Empty;
stringToSign += "POST"+"UserAgent"+"http://api.com/post";

// Here is the issue, How can I do the following 3 lines in PHP?
// No "secret key" provided?.. How do I do this in PHP?
var hmacsha1 = new HMACSHA1(new Guid(apiToken).toByteArray());

// Make a byte array with ASCII encoding.
byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(stringToSign);

// Finally, 'computeHash' of the above (what does this do exactly?!)
var calculatedSignature = Convert.ToBase64String(hmacsha1.ComputeHash(byteArray));

这听起来非常简单直接,但我不确定这些C#方法中的一些是做什么的。

这些// Set vars $apiToken = 'E1024763-1234-5678-91E0-T32E4E7EB316'; $apiTokenId = '1887'; $stringToSign = "POST"."UserAgent"."http://api.com/post"; // HowTo: Build a `byteArray` of our apiToken? (i think) // C#: var hmacsha1 = new HMACSHA1(new Guid(apiToken).toByteArray()); // HowTo: Convert our $stringToSign to a ASCII encoded `byteArray`? // C#: byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(stringToSign); // HowTo: Generate a base64 string of our (`hmacsha1`.ComputeHash(byteArray)) // C#: var calculatedSignature = Convert.ToBase64String(hmacsha1.ComputeHash(byteArray)); 方法做什么/返回什么?

  • C# - 计算什么?...返回什么内容?
  • ComputeHash(byteArray) - 这会带来什么回报?
  • System.Text.Encoding.ASCII.GetBytes(stringToSign);没有密钥?,使用的密钥是什么?

非常感谢任何资源或帮助。 我在SO上尝试了other个答案的变体,但没有快乐。

我可以在网上某处运行3行代码(例如new HMACSHA1(new Guid(apiToken).toByteArray());JSFiddle吗?)所以我可以看到每行的输出?

<小时/>

更新 - 赏金添加

仍然遇到问题,我已经设法在Visual Studio中测试C#代码,但在C#中生成相同的哈希时遇到了问题。

我想......

..上面的PHP代码(具体来说,创建C#哈希的3行)要转换为PHP(查看我上面发布的SHA1)。我应该能够使用PHP匹配Pseudo Code哈希。

如果您有任何其他问题,请询问。

3 个答案:

答案 0 :(得分:3)

问题是GUID的字符串形式反转了GUID的前3个段中的2个字符的十六进制数字的顺序。有关详细信息,请参阅示例中的注释:http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

以下代码应该有效:

$apiTokenId = 1887;
$apiToken = "E1024763-1234-5678-91E0-FF2E4E7EB316";
$stringToSign = '';
$hexStr = str_replace('-','',$apiToken);
$c = explode('-',chunk_split($hexStr,2,'-'));
$hexArr = array($c[3],$c[2],$c[1],$c[0],$c[5],$c[4],$c[7],$c[6],$c[8],$c[9],$c[10],$c[11],$c[12],$c[13],$c[14],$c[15]);
$keyStr = '';
for ($i = 0; $i < 16; ++$i) {
    $num = hexdec($hexArr[$i]);
    $keyStr .= chr($num);
}
$stringToSign .= "POST" . "UserAgent" . "http://api.com/post";
$hmacsha1 = base64_encode(hash_hmac('sha1',$stringToSign,$keyStr,true));

我已根据您上面提供的C#代码测试了此代码,输出结果相同。但是,原始代码中指定的GUID无效,因此我不得不稍微更改它。

答案 1 :(得分:0)

当我不必测试代码时,这很容易:P

http://php.net/manual/en/function.hash-hmac.php - 这相当于HMACSHA1 c#class。

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

所以$ algo =“sha1”

$ data是你的$ stringToSign - 因为那已经是一个ascii字符串(我希望) - C#只是取相同的字节。

new Guid(apiToken).toByteArray() - &gt;这是GUID的16字节(16 * 8 = 128)表示 - 这是32 * 4 = 128位。这是关键。

$ key是一个字符串,所以你需要你的$ apiToken等效的ASCII字符串(这是32个十六进制字符 - 首先剥离/忽略它们之间的破折号) - E10247631234567891E0T32E4E7EB316(更正密钥 - 它不能有“T”)

function hex2str($hex) {
    for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
    return $str;
}

$hexKey = hex2str($apiToken); //strip the dashes first

http://www.linux-support.com/cms/php-convert-hex-strings-to-ascii-strings/

所以方法调用现在有效:

$almostResult = hash_hmac ("sha1" , $stringToSign, $hexKey, true)

这将返回一个二进制字符串 - 您需要将其转换为base64编码。

$final = base64_encode ($almostResult)

应该这样做...享受:)

答案 2 :(得分:0)

我几乎遇到了同样的问题,经过一番谷歌搜索后,我发现了这篇文章: https://www.reddit.com/r/PHP/comments/2k9tol/string_to_byte_array_using_utf8_encoding/

在PHP中,字符串已经是字节数组。您遇到的具体问题是什么?

对我来说,解决方案只是base64_encode('apikey')