C# equivalent to hash_hmac in PHP
Asked Answered
E

3

37

using .NET and C# i need to provide an integrity string using HMAC SHA512 to a PHP server . Using in C# :

Encoding encoding = Encoding.UTF8;
byte[] keyByte = encoding.GetBytes(key);
HMACSHA512 hmacsha512 = new HMACSHA512(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[]  hashmessage = hmacsha512.ComputeHash(messageBytes);
return(ByteToString(hashmessage).toUpper());

But it doesn't match with PHP hash_hmac() PHP code :

$hmac = strtoupper(hash_hmac($pbx_hash, $msg, $binKey));

I try to change encoding in C# (utf8, ASCII,Unicode) Without success.

I've tried many solution found on the net but nothing give the same string :(

I can't change the PHP code, and doesn't see what's wrong in C#

Edit This is ByteToString (copied from the comment):

static string ByteToString(byte[] buff)
{
    string sbinary = "";
    for (int i = 0; i < buff.Length; i++)
    {
        sbinary += buff[i].ToString("X2"); /* hex format */
    }
    return (sbinary);
}    

After many tets, in found that i get the same results if PHP hash_hmac key is a string, not a byte Array . Seems that the problem is with the PHP convert function $binKey = pack("H*", $keyTest);

Eddieeddina answered 9/10, 2012 at 16:17 Comment(3)
See stackoverflow.com/questions/tagged/hmac+c%23Relieve
chech this msdn.microsoft.com/en-us/library/…Casey
What is` ByteToString` ?Valles
C
44

The problem must be the actual representation of the key/message data.

See the following tests:

PHP

#!/usr/bin/php
<?php
print strtoupper(hash_hmac("sha256", "message", "key"));
?>

Output (live via http://writecodeonline.com/php/):

6E9EF29B75FFFC5B7ABAE527D58FDADB2FE42E7219011976917343065F58ED4A

C#

using System;
using System.Text;
using System.Security.Cryptography;

public class Program
{
    private const string key = "key";
    private const string message = "message";
    private static readonly Encoding encoding = Encoding.UTF8; 

    static void Main(string[] args)
    {
        var keyByte = encoding.GetBytes(key);
        using (var hmacsha256 = new HMACSHA256(keyByte))
        {
            hmacsha256.ComputeHash(encoding.GetBytes(message));

            Console.WriteLine("Result: {0}", ByteToString(hmacsha256.Hash));
        }
    }
    static string ByteToString(byte[] buff)
    {
        string sbinary = "";
        for (int i = 0; i < buff.Length; i++)
            sbinary += buff[i].ToString("X2"); /* hex format */
        return sbinary;
    }    
}

Output (live via http://ideone.com/JdpeL):

Result: 6E9EF29B75FFFC5B7ABAE527D58FDADB2FE42E7219011976917343065F58ED4A

So, check the character set/encoding of the PHP input data. Also check the actual algorithm (in $pbx_hash).

Catarina answered 9/10, 2012 at 16:26 Comment(7)
Thank you, here's the code for ByteToString : static string ByteToString(byte[] buff) { string sbinary = ""; for (int i = 0; i < buff.Length; i++) { sbinary += buff[i].ToString("X2"); // hex format } return (sbinary); } I supposeit will give the same return.Eddieeddina
sehe, There are already built-in classes for this BitConverter.ToString , System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinaryBarahona
Thank you, Bitconverter is shorter but it doesn't solve te problem of the difference between PHP and C# :(Eddieeddina
@Eddieeddina I have redone my analysis given your ByteToString function. See my answer rewritten from scratchCatarina
Hi, thanks for your reply, after many tests the problems comes from PHP Pack(H* function ! when the key provided is a string it's ok but using Pack(H* to provide key give different result from C# GetBytes (probably because of internal PHP encoding). Found the solution here : nuronconsulting.com/c-pack-h.aspxEddieeddina
Sooo, indeed, I was right. The error was in the key or message input.Catarina
Is there any reason you didn't use encoding.GetString(hmacsha256.Hash) ?Eveevection
S
20
    private static string HashHmac(string message, string secret)
    {
        Encoding encoding = Encoding.UTF8;
        using (HMACSHA512 hmac = new HMACSHA512(encoding.GetBytes(secret)))
        {
            var msg = encoding.GetBytes(message);
            var hash = hmac.ComputeHash(msg);
            return BitConverter.ToString(hash).ToLower().Replace("-", string.Empty);
        }
    }
Selfhypnosis answered 23/8, 2017 at 0:35 Comment(3)
i was working in c# from a PHP 'hash_hmac()' example, and was able to get desired results using above answer.Widow
Many APIs want a base64 version of the hash, you can simply get this by replacing the existing 'return...' line with return Convert.ToBase64String(hash);Byplay
Could you please explain why you need the .Replace("-", string.Empty) ?Nitrosyl
E
4

As said upper, the problem was with PHP Pack(H* function used to convert key to byte array. C# Getbytes doesn't give the same result (utf8, asci, unicode...). The solution found here : http://www.nuronconsulting.com/c-pack-h.aspx was ok for me. now HMAC from C# match with PHP !

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

Manu thanks to all for your help.

Eddieeddina answered 10/10, 2012 at 12:0 Comment(1)
I am having the exact same issue. I've tried using your approach but still having issues. I asked a similar question here #20277409 . Can you give me info WHERE in your solution you actually used this PackH function? thanks!Geibel

© 2022 - 2024 — McMap. All rights reserved.