尝试复制PHP';s包(“H*”)函数


Trying to reproduce PHP's pack("H*") function in C#

这是我在C#中的代码:

    public static String MD5Encrypt(String str, Boolean raw_output=false)
    {
        // Use input string to calculate MD5 hash
        String output;
        MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(str); 
        byte[] hashBytes = md5.ComputeHash(inputBytes);
        // Convert the byte array to hexadecimal string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hashBytes.Length; i++)
        {
            sb.Append(hashBytes[i].ToString("x2"));
        }
        output = sb.ToString();
        if (raw_output)
        {
            output = pack(output);
        }
        return output;
    }
    public static String pack(String S)
    {
        string MultiByte = ""; 
        for (int i = 0; i <= S.Length - 1; i += 2)
        {
            MultiByte += Convert.ToChar(HexToDec(S.Substring(i, 2)));
        }
        return MultiByte;
    }
    private static int HexToDec(String hex)
    {
        //Int32.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
        return Convert.ToInt32(hex, 16);
    }

通过这种方式复制php中的操作:

md5($str, true);

pack('H*', md5( $str ));

我尝试了很多东西,但在某些情况下,双方都不一样。例如,在字符串"8tv7er5j"上尝试此测试

PHP端:

9c36ad446f83ca38619e12d9e1b3c39e <= md5("8tv7er5j");
œ6­DoƒÊ8ažÙá³Ãž <= md5("8tv7er5j", true) or pack("H*", md5("8tv7er5j"))

C#侧

9c36ad446f83ca38619e12d9e1b3c39e <= MD5Encrypt("8tv7er5j")
6­DoÊ8aÙá³Ã <= MD5Encrypt("8tv7er5j", true) or pack( MD5Encrypt("8tv7er5j") )

为什么?编码问题?

第1版:我有好的结果,但用这个函数编码坏了pack():

if ((hex.Length % 2) == 1) hex += '0';
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
    bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;

因此,System.Text.Encoding.UTF8.GetString(字节)给我:�6.�做��8a���Þ

和System.Text.Encoding.ASCII.GetString(字节)?6.做8a??????

我遇到了同样的场景,我需要php在C#中的pack-unpack-md5函数。最重要的是,我需要用php来匹配所有这3个函数。

我创建了自己的函数,然后用onlinephpfunctions.com上的函数验证了我的输出。当我用DefaultEncoding解析时,输出是一样的。仅供参考,我检查了应用程序的编码(encoding.Default.ToString()),结果是System.Text.SBCCodePageEncoding

包装

    private static string pack(string input)
{
    //only for H32 & H*
    return Encoding.Default.GetString(FromHex(input));
}
public static byte[] FromHex(string hex)
{
    hex = hex.Replace("-", "");
    byte[] raw = new byte[hex.Length / 2];
    for (int i = 0; i < raw.Length; i++)
    {
        raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
    }
    return raw;
}

MD5

    private static string md5(string input)
{
    byte[] asciiBytes = Encoding.Default.GetBytes(input);
    byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
    string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
    return hashedString;
}

开箱

私有静态字符串解包(字符串p1,字符串输入){StringBuilder输出=新StringBuilder();

    for (int i = 0; i < input.Length; i++)
    {
        string a = Convert.ToInt32(input[i]).ToString("X");
        output.Append(a);
    }
    return output.ToString();
}

PS:用户可以用其他格式增强这些功能

我猜PHP默认为Latin1,所以代码应该看起来像:

public static String PhpMd5Raw(string str)
{
    var md5 = System.Security.Cryptography.MD5.Create();
    var inputBytes = System.Text.Encoding.ASCII.GetBytes(str); 
    var hashBytes = md5.ComputeHash(inputBytes);
    var latin1Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
    return latin1Encoding.GetString(hashBytes);
}

如果您要将结果作为HMAC-SHA1哈希的密钥,请将其保留为字节[],并使用此函数的返回值初始化HMACSHA1:不要将其转换为字符串并返回为字节,因为这个错误,我已经花了几个小时。

public static byte[] PackH(string hex)
{
    if ((hex.Length % 2) == 1) hex += '0';
    byte[] bytes = new byte[hex.Length / 2];
    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }
    return bytes;
}

我知道这是个老问题。我发布我的答案,为任何可能到达这个页面搜索它的人。以下代码是pearl功能包("H*")到c#的完整转换。

public static String Pack(String input)
{
    input = input.Replace("-", " ");
    byte[] hashBytes = new byte[input.Length / 2];
    for (int i = 0; i < hashBytes.Length; i++)
    {
        hashBytes[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
    }
    return Encoding.UTF7.GetString(hashBytes); // for perl/php
}
对不起。我没有完全回答这些问题。但是如果php代码如下,
$testpack = pack("H*" , "you value");

如果无法读取$testpack值(由于某些不支持的格式),则首先执行下面的base64_encode并回显它。

echo base64_encode($testpack);

然后使用Risky Pathak答案。为了完成这个答案,我会发布他的答案,并进行一些小的修改,如base64编码等。

            var hex = "you value";
            hex = hex.Replace("-", "");
            byte[] raw = new byte[hex.Length / 2];
            for (int i = 0; i < raw.Length; i++)
            {
                raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
            }
            var res = Convert.ToBase64String(raw);
            Console.WriteLine(res);

现在,如果比较这两个值,它们应该是相似的。

所有的功劳都应该归于Risky Pathak的答案。

在c#中使用Hex.Decode()方法可以达到相同的效果。php中的bin2hex()是Hex.Encode().