PHP SHA-256 not the same as this c# code? - c#

Got a problem - maybe... It seems that this piece of PHP:
$mydigestb = hash("sha256",$digeststring);
does not generate the same result as this C# code:
private string GenerateDigest(long currentTime)
{
SHA256Managed hashString = new SHA256Managed();
StringBuilder hex = new StringBuilder();
byte[] hashValue = hashString.ComputeHash(Encoding.UTF8.GetBytes(String.Format("{0}{1}", currentTime, txtApiKey.Text)));
foreach (byte x in hashValue)
{
hex.AppendFormat("{0:x2}", x);
}
return hex.ToString();
}
The input values are the same, but it appears that what comes out is different.

It is the same for me:
PHP code: http://codepad.org/gcGC5Omp
<?php
$mydigestb = hash("sha256" , "abhinav" );
echo $mydigestb;
?>
C# code: https://ideone.com/jrz05O
using System;
public class Test
{
public static void Main()
{
System.Security.Cryptography.SHA256Managed hm = new System.Security.Cryptography.SHA256Managed();
byte[] hashValue = hm.ComputeHash(System.Text.Encoding.ASCII.GetBytes("abhinav"));
Console.WriteLine(System.BitConverter.ToString(hashValue).Replace("-", "").ToLower());
}
}
Are you using the same sample data?

Related

C# PHP SHA-256 hashing returns different value, but SHA-1 & base64 not

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.
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.

Base64 and SHA256 results of C# and Python are different

I'm a newcomer and beginner, because my English is not good, I will make a long story short, please help me.
A public key is Base64 decode and SHA256.
Use C# and Python (Python result is correct.)
Why do I get different results?
If you like, I hope to get the answer by C# code(my English is very poor.)
Thank you very much.
Same public key : MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0k9N59vMq/1BP6lwgyxVPeWj6EFTMW+wJqyl+vePi1vKzJBCXWPZ5Ls7PmNaTaAQ5TVC5WVoxveuvaYLGm514Y7EDTrL8BrPWcK73Gw7E/IQyfOC+/Mw6mBnANyWiVAu9qIi2/PWasA2J/XR97kfUfuM716NKUNzBmmju8pfyPu+ee9Zfh0fUclF0g48AJMZaw8g6SxiWnQ8XhABkMHXyqVio5cdt5omupDcZ17HHBXsP3KHNX5Tu8ZDrCbFH566p1WGjM6W2Wr2YffzC8WPyFTS/6eiAde5iVjS2VHqRkmgQvrH794kGUC7ZUitP7p6gYCvhdffqxLQslvga9cPNQIDAQAB
Base64 decode ==> SHA256
Python:
pubkey_der = base64.b64decode(pubKey)
sha = hashlib.sha256(pubkey_der).hexdigest()
for i in sha:
print(i),
print('\n'),
result:890e947269d4e6d9c73883157f65aa6f12e20ad0a05ff518b5f9cb43cea28b89
C#:
private void button_go2_Click(object sender, EventArgs e)
{
string b64 = DecodeBase64(pubKey);
string result = GetSHA256HashFromString(b64);
}
private static string DecodeBase64(string pubKey)
{
string decode = string.Empty;
byte[] bytes = Convert.FromBase64String(pubKey);
decode = Encoding.UTF8.GetString(bytes);
return decode;
}
public string GetSHA256HashFromString(string strData)
{
byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(strData);
try
{
SHA256 sha256 = new SHA256CryptoServiceProvider();
byte[] retVal = sha256.ComputeHash(bytValue);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("GetSHA256HashFromString() fail,error:" + ex.Message);
}
}
result:1eb61f3f380bccf54e61e05cdbe6e14c3871c6c827b33dc03b2cf47c1fc0df4c

Generate HMAC-SHA256 hash with BouncyCastle

I need to generate a HMAC-SHA256 hash in a PCL (developing for Xamarin Forms) which doesn't support the .NET built-in HMAC/cryptography classes, so I'm working with BouncyCastle to implement my cryptography classes.
I need to generate a HMAC-SHA256 hash, but I haven't been able to find any example on Google, nor does BouncyCastle seem to have any documentation for this. Can anyone help me out?
Thanks to the solution here I came up with this code:
public class HmacSha256
{
public byte[] Hash(string text, string key)
{
var hmac = new HMac(new Sha256Digest());
hmac.Init(new KeyParameter(Encoding.UTF8.GetBytes(key)));
byte[] result = new byte[hmac.GetMacSize()];
byte[] bytes = Encoding.UTF8.GetBytes(text);
hmac.BlockUpdate(bytes, 0, bytes.Length);
hmac.DoFinal(result, 0);
return result;
}
}
Corresponding unit test (uses FluentAssertions):
[TestClass]
public class HmacSha256Tests
{
private readonly HmacSha256 _hmac = new HmacSha256();
[TestMethod]
public void Hash_GeneratesValidHash_ForInput()
{
// Arrange
string input = "hello";
string key = "test";
string expected = "F151EA24BDA91A18E89B8BB5793EF324B2A02133CCE15A28A719ACBD2E58A986";
// Act
byte[] output = _hmac.Hash(input, key);
string outputHex = BitConverter.ToString(output).Replace("-", "").ToUpper();
// Assert
expected.Should().Be(outputHex);
}
}
Using this PCL offshoot of BouncyCastle https://www.nuget.org/packages/BouncyCastle-PCL/1.0.0.6 it's really easy, in fact identical to the windows api.
public string ComputeHMAC(string message)
{
var keyBytes = Encoding.UTF8.GetBytes(Constants.API_KEY);
var messageBytes = Encoding.UTF8.GetBytes(message);
var hmac = new HMACSHA256(keyBytes);
byte[] result = hmac.ComputeHash(messageBytes);
return Convert.ToBase64String(result);
}
And a unit test using the actual .Net version:
[Test, AutoMoqData]
public void Hash_Algorithm_Correct (
[NoAutoProperties] HashMacService sut,
string message)
{
string expected;
var key = Encoding.UTF8.GetBytes(Constants.API_KEY);
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
expected = Convert.ToBase64String(hash);
}
var result = sut.ComputeHMAC(message);
Assert.That(result, Is.EqualTo(expected));
}
I was using PCLCrypto but it kept crashing on Xamarin iOS, this was much cleaner and could be unit tested, wheras PCLCrypto required the platform apis so had to be deployed to a device.
private static void CreateToken(string message, string key)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[]keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha = new HMACSHA256(keyByte);
byte[]messageBytes = encoding.GetBytes(message);
byte[]hashmessage = hmacsha.ComputeHash(messageBytes);
Console.WriteLine(ByteToString(hashmessage));
}
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);
}
Above code saved my time while working for HMAC-SHA256, I hope this may help someone and here is the reference in detail http://billatnapier.com/security01.aspx

Convert C# HMAC SHA256 to PHP

I've a C# method which I have to convert to PHP. I tried several things, but I still get different results. Unfortunately I cannot change anything on the C# application. It has to be as it is. Maybe one of you could help?
C#:
static public void Main ()
{
string StringToSign = "test";
string Key = "123456";
//Calculate Signature
string Signature = CalculateSignature(StringToSign, Key);
Console.WriteLine ("StringToSign: " + StringToSign);
Console.WriteLine ("Key: " + Key);
Console.WriteLine ("Signature Caculated: " + Signature + "\r\n");
}
static private string CalculateSignature(String StringToSign, String Key)
{
Encoding enc = Encoding.GetEncoding(65001);
byte[] KeyHex = StringHexValuesToByteArray(Key);
byte[] StringToSign_byte = enc.GetBytes(StringToSign);
//Check Signature
HMACSHA256 hmac = new HMACSHA256(KeyHex);
byte[] hashValue = hmac.ComputeHash(StringToSign_byte);
return BitConverter.ToString(hashValue).Replace("-", "");
}
static public byte[] StringHexValuesToByteArray(string str)
{
if (str.Length % 2 != 0)
return null;
string s = string.Empty;
byte[] ret = new byte[str.Length / 2];
for (int run = 0; run < str.Length / 2; run++)
{
s = str.Substring(run * 2, 2);
ret[run] = Convert.ToByte(s, 16);
}
return ret;
}
PHP:
public function send() {
$stringToSign = 'test';
$key = '123456';
//Calculate Signature
$signature = $this->calculateSignature($stringToSign, $key);
print_r("StringToSign: " . $stringToSign . PHP_EOL);
print_r("Key: " . $key . PHP_EOL);
print_r("Signature Caculated: " . $signature . PHP_EOL);
}
private function calculateSignature($stringToSign, $key) {
// check signature
$hash = strtoupper(hash_hmac('sha256', $stringToSign, $key, false));
return $hash;
}
For better understanding, here is the output of the code blocks above:
C#
StringToSign: test
Key: 123456
Signature Caculated:
DA3617974490FB780F04F06287BF93B0F24A7F15970471146428B943FFDC7850
PHP
StringToSign: test
GroupKey: 123456
Signature Caculated: 9D2BB116E1DF997FFE8A5139FC1D187F976C19579A138414A112BC2E39020EBA
If you want to modify the PHP to make it equivalent to C#
Change
$hash = strtoupper(hash_hmac('sha256', $stringToSign, $key, false));
to
$hash = strtoupper(hash_hmac('sha256', $stringToSign, hex2bin($key), false));
Be sure to check the code will work for non-ASCII characters like àèéìòù.
ideone here.
If you want to modify the C# code to make it equivalent to PHP
You are complicating everything:
static private string CalculateSignature(String stringToSign, String key)
{
byte[] key_byte = Encoding.UTF8.GetBytes(key);
byte[] stringToSign_byte = Encoding.UTF8.GetBytes(stringToSign);
//Check Signature
HMACSHA256 hmac = new HMACSHA256(key_byte);
byte[] hashValue = hmac.ComputeHash(stringToSign_byte);
return BitConverter.ToString(hashValue).Replace("-", "");
}
There is nothing hex. And instead of using Encoding.GetEncoding(65001) it is normally better to use Encoding.UTF8, because it is clearer for everyone.
Note that there could be problems with the encoding. Try calculating the hmac of something like àèéìòù to see which encoding the PHP is using.

How can I SHA512 a string in C#?

I am trying to write a function to take a string and sha512 it like so?
public string SHA512(string input)
{
string hash;
~magic~
return hash;
}
What should the magic be?
Your code is correct, but you should dispose of the SHA512Managed instance:
using (SHA512 shaM = new SHA512Managed())
{
hash = shaM.ComputeHash(data);
}
512 bits are 64 bytes.
To convert a string to a byte array, you need to specify an encoding. UTF8 is okay if you want to create a hash code:
var data = Encoding.UTF8.GetBytes("text");
using (...
This is from one of my projects:
public static string SHA512(string input)
{
var bytes = System.Text.Encoding.UTF8.GetBytes(input);
using (var hash = System.Security.Cryptography.SHA512.Create())
{
var hashedInputBytes = hash.ComputeHash(bytes);
// Convert to text
// StringBuilder Capacity is 128, because 512 bits / 8 bits in byte * 2 symbols for byte
var hashedInputStringBuilder = new System.Text.StringBuilder(128);
foreach (var b in hashedInputBytes)
hashedInputStringBuilder.Append(b.ToString("X2"));
return hashedInputStringBuilder.ToString();
}
}
Please, note:
SHA512 object is disposed ('using' section), so we do not have any resource leaks.
StringBuilder is used for efficient hex string building.
512/8 = 64, so 64 is indeed the correct size. Perhaps you want to convert it to hexadecimal after the SHA512 algorithm.
See also: How do you convert Byte Array to Hexadecimal String, and vice versa?
You might try these lines:
public static string GenSHA512(string s, bool l = false)
{
string r = "";
try
{
byte[] d = Encoding.UTF8.GetBytes(s);
using (SHA512 a = new SHA512Managed())
{
byte[] h = a.ComputeHash(d);
r = BitConverter.ToString(h).Replace("-", "");
}
r = (l ? r.ToLowerInvariant() : r);
}
catch
{
}
return r;
}
It is disposed at the end
It's safe
Supports lower case
Instead of WinCrypt-API using System.Security.Cryptography, you can also use BouncyCastle:
public static byte[] SHA512(string text)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);
Org.BouncyCastle.Crypto.Digests.Sha512Digest digester = new Org.BouncyCastle.Crypto.Digests.Sha512Digest();
byte[] retValue = new byte[digester.GetDigestSize()];
digester.BlockUpdate(bytes, 0, bytes.Length);
digester.DoFinal(retValue, 0);
return retValue;
}
If you need the HMAC-version (to add authentication to the hash)
public static byte[] HmacSha512(string text, string key)
{
byte[] bytes = Encoding.UTF8.GetBytes(text);
var hmac = new Org.BouncyCastle.Crypto.Macs.HMac(new Org.BouncyCastle.Crypto.Digests.Sha512Digest());
hmac.Init(new Org.BouncyCastle.Crypto.Parameters.KeyParameter(System.Text.Encoding.UTF8.GetBytes(key)));
byte[] result = new byte[hmac.GetMacSize()];
hmac.BlockUpdate(bytes, 0, bytes.Length);
hmac.DoFinal(result, 0);
return result;
}
Keeping it simple:
using (SHA512 sha512 = new SHA512Managed())
{
password = Encoding.UTF8.GetString(sha512.ComputeHash(Encoding.UTF8.GetBytes(password)));
}
I'm not sure why you are expecting 128.
8 bits in a byte. 64 bytes. 8 * 64 = 512 bit hash.
From the MSDN Documentation:
The hash size for the SHA512Managed algorithm is 512 bits.
You could use the System.Security.Cryptography.SHA512 class
MSDN on SHA512
Here is an example, straigt from the MSDN
byte[] data = new byte[DATA_SIZE];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(data);
UnicodeEncoding UE = new UnicodeEncoding();
byte[] message = UE.GetBytes(password);
SHA512Managed hashString = new SHA512Managed();
string hexNumber = "";
byte[] hashValue = hashString.ComputeHash(message);
foreach (byte x in hashValue)
{
hexNumber += String.Format("{0:x2}", x);
}
string hashData = hexNumber;
I used the following
public static string ToSha512(this string inputString)
{
if (string.IsNullOrWhiteSpace(inputString)) return string.Empty;
using (SHA512 shaM = new SHA512Managed())
{
return Convert.ToBase64String(shaM.ComputeHash(Encoding.UTF8.GetBytes(inputString)));
}
}
Made it into an extension method in my ExtensionUtility.cs class
public static string SHA512(this string plainText)
{
using (SHA512 shaM = new SHA512Managed())
{
var buffer = Encoding.UTF8.GetBytes(plainText);
var hashedInputBytes = shaM.ComputeHash(buffer);
return BitConverter.ToString(hashedInputBytes).Replace("-", "");
}
}

Categories

Resources