用Convert.ToChar(0)生成的字符串在使用hash_hmac函数进行哈希时与PHP中使用chr(0)生成的字符串哈希结果不同。

6

我有一个PHP字符串,它被转换为字节数组并进行了哈希。

被转换为字节数组的字符串如下:

"g". chr(0) . "poo";

我需要在C#中找到相应的字节数组,以便获得相同的哈希值。

编辑:以下是完整的问题,生成的哈希值不一样。

PHP

$api_secret = '5432919427bd18884fc2a6e48b65dfba48fd9a1a46e3468b52fadbc6d6b463425';
$data = 'payment_currency=USD&group_orders=0&count=100&nonce=1385689989977529';
$endpoint = '/info/orderbook';

$signature = hash_hmac('sha512', $endpoint . chr(0) . $data, $api_secret);

$result =  base64_encode($signature);

C#

var apiSecret = "5432919427bd18884fc2a6e48b65dfba48fd9a1a46e3468b52fadbc6d6b463425";
var data = "payment_currency=USD&group_orders=0&count=100&nonce=1385689989977529";
var endPoint = "/info/orderbook";

System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

String message = endpPoint + Convert.ToChar(0) + data;

var hmacsha512 = new HMACSHA512(encoding.GetBytes(message));
var result = Convert.ToBase64String(hmacsha512.Hash);

我尝试了不同的Base64编码,例如:

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;
    }   

但是最终问题似乎出现在被哈希的 byteArray 上,因为 PHP 使用 chr(0)。

我觉得你想要的是这样的: "g" + (char)0 + "poo"。这个 php 字符串是指你想把 "g" 和 null 进行拼接,然后再和 "poo" 进行拼接吗? - Alexandre Machado
是的,那个对的。然后我需要把它转换成字节数组。但是我不明白如何在C#中创建相同类型的字符串。我从中生成的字节数组和随后的哈希值是不同的。 - billy jean
我回答了如何将此转换为字节数组。 - Wagner Leonardi
3个回答

4

我会再次回答您的问题,因为您已经更改了整个问题,所以针对您的新问题有一个新的解决方案。

首先,HMACSHA512不会给出与您的php代码相同的结果。顺便说一下,您的PHP生成的哈希值是:

41028bb90af31dc6e7fa100a8ceb1e220bfedf67ea723292db9a4e1c14f69c73adf30eeba61ab054cdc91c82f6be2f76dd602392be630b5e99b1f86da1460cbe

为了在C#中达到相同的结果,我创建了 BillieJeansSHA512 类来使哈希值与PHP相等。另外,我创建了 ByteToString 方法来正确地将 byte[] 转换为 String,而不是使用 encoding.GetBytes 进行转换。
哦,下面的代码并不像PHP那么简单,但我向你或任何人挑战,在保持相同的PHP哈希情况下,让它更简单!我敢你,我双倍敢你!让我们看看这段代码:
//These are not default imports, so you need to use it
using System.Text;
using System.Security.Cryptography;

//Before your actual class, you need to make your custom 512
public class BillieJeansSHA512 : HMAC
{
    public BillieJeansSHA512(byte[] key)
    {
        HashName = "System.Security.Cryptography.SHA512CryptoServiceProvider";
        HashSizeValue = 512;
        BlockSizeValue = 128;
        Key = (byte[])key.Clone();
    }
}

//Now, there's your actual class
public class HelloWorld{


    //First, use this method to convert byte to String like a boss
    static string ByteToString(byte[] buff)
    {
        string sbinary = "";
        for (int i = 0; i < buff.Length; i++)
            sbinary += buff[i].ToString("x2"); /* hex format */
        return sbinary;
    }    

    //Now let's get it started!
    public static void Main(String []args){
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

        //Your data
        var apiSecret = "5432919427bd18884fc2a6e48b65dfba48fd9a1a46e3468b52fadbc6d6b463425";
        var data = "payment_currency=USD&group_orders=0&count=100&nonce=1385689989977529";
        var endPoint = "/info/orderbook";

        String message = endPoint + Convert.ToChar(0) + data;

        //Hash will be stored here
        String hash = "";

        //put your key at your custom 512
        BillieJeansSHA512 hmacsha512 = new BillieJeansSHA512(encoding.GetBytes(apiSecret));
        //hash'em all
        byte[] result = hmacsha512.ComputeHash(encoding.GetBytes(message));

        //convert bytes to string
        hash = ByteToString(result);

        //See it :)
        Console.WriteLine(hash);

        //Or if you using it at a web-page, this is it.
        //Response.Write(hash)

        //Now the easy part, convert it to base64
        var bytesTo64 = System.Text.Encoding.UTF8.GetBytes(hash);
        String hash64 = System.Convert.ToBase64String(bytesTo64);
    }
}

......好的,这就是它。 String hash 具有与 PHP 相同的哈希值:

41028bb90af31dc6e7fa100a8ceb1e220bfedf67ea723292db9a4e1c14f69c73adf30eeba61ab054cdc91c82f6be2f76dd602392be630b5e99b1f86da1460cbe

String hash64 具有与 PHP 相同的编码 base64 值:

NDEwMjhiYjkwYWYzMWRjNmU3ZmExMDBhOGNlYjFlMjIwYmZlZGY2N2VhNzIzMjkyZGI5YTRlMWMxNGY2OWM3M2FkZjMwZWViYTYxYWIwNTRjZGM5MWM4MmY2YmUyZjc2ZGQ2MDIzOTJiZTYzMGI1ZTk5YjFmODZkYTE0NjBjYmU=

1
我真诚地想感谢你!为什么你必须制作定制的512呢?PHP中的块大小不同吗??天啊..我一直在抓狂。谢谢! - billy jean
2
是的!那真的很难,我至少花了3个小时在上面!!现在好好享受吧 :) - Wagner Leonardi
1
@WagnerLeonardi 你刚刚救了我的命。非常感谢你发布这个。 - Sealer_05
@WagnerLeonardi 尝试使用自定义的 HMAC 实现时,我遇到了错误,提示 System.PlatformNotSupportedException: '在此平台上不支持通过操作 HashName 属性来访问哈希算法。相反,您必须实例化提供的子类型之一(例如 HMACSHA1)。' 非常感谢任何帮助。 - Raghav

1
他还要求将其作为byte数组传递,这是最重要的,因为必须使用char到byte的转换:
//Conversion object
System.Text.UTF8Encoding  encoding = new System.Text.UTF8Encoding();

//Your any String text
String stringText = "g" + Convert.ToChar(0) + "poo";

//Convert to the wanted byte array
byte[] byteArray = encoding.GetBytes(stringText);

如果您愿意,您也可以在一行中完成同样的操作 :)
byte[] byteArray = new System.Text.UTF8Encoding().GetBytes("g" + Convert.ToChar(0) + "poo");

当我对其进行哈希时,结果与在php中哈希“g”+ Convert.ToChar(0) +“poo”的结果不同。 - billy jean
好的,这不是同一个问题。我为此做了一个新答案,所以请查看一下。 - Wagner Leonardi

0
你可以使用Convert.ToChar(Int32)方法将Unicode值表示为字符。
用法:"g" + Convert.ToChar(0) + "poo"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接