0

I am making backend system for mine game (server & client). I use following code to generate first part of signature (this one is corrupted one):

    #example data
    string Url = "https://example.com/api/test/example.php";
    Dictionary<string, string> RequestBody = new Dictionary<string, string>() { { "example_value", "test" } };

    string CreateFirstHash()
    {
        string Combined = "";
        foreach(KeyValuePair<string, string> BodyPart in RequestBody)
        {
            Combined += BodyPart.Key + "-" + BodyPart.Value + ".";
        }

        string HashedCombined = Encryption.SHA1(Combined);
        string EncodedUrl = Encryption.Base64Encode(this.Url);
        string PlainText = HashedCombined + ":" + EncodedUrl + ":" + 'ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE';

        return Encryption.SHA256(PlainText);
    }

Here is Encryption class:

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

public class Encryption
{
    private static readonly Encoding enc = Encoding.UTF8;

    public static string MD5(string input)
    {
        byte[] inputBytes = enc.GetBytes(input);
        using(System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
        {
            byte[] hashBytes = md5.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();

            foreach(byte hashByte in hashBytes)
            {
                sb.Append(hashByte.ToString("x2"));
            }

            return sb.ToString();
        }
    }

    public static string SHA1(string input)
    {
        byte[] inputBytes = enc.GetBytes(input);
        using(SHA1Managed sha = new SHA1Managed())
        {
            byte[] hashBytes = sha.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();

            foreach(byte hashByte in hashBytes)
            {
                sb.Append(hashByte.ToString("x2"));
            }

            return sb.ToString();
        }
    }

    public static string SHA256(string input)
    {
        byte[] inputBytes = enc.GetBytes(input);
        using (SHA256Managed sha = new SHA256Managed())
        {
            byte[] hashBytes = sha.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();

            foreach (byte hashByte in hashBytes)
            {
                sb.Append(hashByte.ToString("x2"));
            }

            return sb.ToString();
        }
    }

    public static string SHA512(string input)
    {
        byte[] inputBytes = enc.GetBytes(input);
        using (SHA512Managed sha = new SHA512Managed())
        {
            byte[] hashBytes = sha.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();

            foreach (byte hashByte in hashBytes)
            {
                sb.Append(hashByte.ToString("x2"));
            }

            return sb.ToString();
        }
    }

    public static string HMAC512(string input, string secret)
    {
        byte[] inputBytes = enc.GetBytes(input);
        byte[] secretBytes = enc.GetBytes(secret);

        using(HMACSHA512 hmac = new HMACSHA512(secretBytes))
        {
            byte[] hashBytes = hmac.ComputeHash(inputBytes);
            return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
        }
    }

    public static string Base64Encode(string input)
    {
        byte[] inputBytes = Encoding.ASCII.GetBytes(input);
        return Convert.ToBase64String(inputBytes);
    }
}

Server validates data by making same hash, with the same data and finally checks if generated signature is equal to input one. This is server implementation for CreateFirstHash() function:

    #example data
    public $requestBody = array('example_value' => 'test');
    public $url = 'https://example.com/api/test/example.php';
    public $scope = 'game'; #this is not important, you can disregard it

    private static function generateFirstHash($requestBody, $url, $scope)
    {
        $combined = "";
        foreach ($requestBody as $key => $value)
        {
            $combined .= $key . '-' . $value . ".";
        }

        $combined = sha1($combined);
        $encodedUrl = base64_encode($url);

        $plainString = $combined . ':' . $encodedUrl . ':' . 'ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE';
        return hash('sha256', $plainString);
    }

All data from input were the same (checked manually). This is list what was the same in debug (step by step):

  • Combined string: same
  • SHA-1 hash of combined string: same
  • Encoded URL: same
  • Plain text: same
  • Final SHA-256 hash: invalid

Can anyone knows what is wrong and how can I make this valid?

Edit 1 Added example input data.

  • Welcome to Stackoverflow. Kindly edit your post and add a set of example data as we cannot run your code in a minimal program (Plaintext, SHA256-hash on C# and PHP-side). As I asked you to provide this in your (in the meantime deleted question) I'm downvoting your question, sorry. – Michael Fehr Aug 16 '20 at 20:08
  • @MichaelFehr Updated. – ExampleEngineering Aug 16 '20 at 20:17

1 Answers1

0

Thanks for adding some sample data but your C#-code is not running directly as some functions are missing.

I run your PHP-code and could extract the input to the SHA256-function:

plainString: d4a1466c15dc46dd6f7533b172313660eab1aba5:aHR0cHM6Ly9leGFtcGxlLmNvbS9hcGkvdGVzdC9leGFtcGxlLnBocA==:ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE

With this input the PHP-SHA256 is:

hash: dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15

Test the plainString-value with an online-tool (https://emn178.github.io/online-tools/sha256.html) gives the same result:

dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15

Last but not least I tested your C#-implementation of SHA256 after fixing the missing

byte[] inputBytes = **enc.GetBytes**(input);

and got the result:

dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15

So in the end - there is no difference in SHA256-results between C# and PHP.

Michael Fehr
  • 5,827
  • 2
  • 19
  • 40