I am running this code:
var timeStamp = DateTime.UtcNow;
var sharedSecret = "xx";
var saltedString = timeStamp.ToString("2021-01-07T16:42:33.619667Z") + sharedSecret;
//Encoding saltedString using Unicode little-endian byte order
byte[] encodedSaltedString = Encoding.Unicode.GetBytes(saltedString);
//Hashing Algorithm used is SHA512
HashAlgorithm hash = new SHA512Managed();
//Compute Hash of encodedSaltedString
byte[] hashedEncodedString = hash.ComputeHash(encodedSaltedString);
//Convert hashed array to base64-encoded string
string signature = Convert.ToBase64String(hashedEncodedString);
I am then getting this result in C#:
"gQhjrLnY6fo44EeaaWaUBE1PY/8oEIRsUcK3AMSCVUCYMM4vRfxvQEEggXaHTF0GQbw4w2HbWArX1k6NnkzJFg=="
I converted to this code as below, but I am getting an issue. Can I get some help on this?
$timestamp = "2021-01-07T16:42:33.619667Z";
$sharedSecret = 'xx';
$saltedString = $timestamp.$sharedSecret;
$utf=mb_convert_encoding($saltedString, "UTF-16LE");
$signature = base64_encode(hash('sha512', $utf));
IN PHP I am getting this result:
ODEwODYzYWNiOWQ4ZTlmYTM4ZTA0NzlhNjk2Njk0MDQ0ZDRmNjNmZjI4MTA4NDZjNTFjMmI3MDBjNDgyNTU0MDk4MzBjZTJmNDVmYzZmNDA0MTIwODE3Njg3NGM1ZDA2NDFiYzM4YzM2MWRiNTgwYWQ3ZDY0ZThkOWU0Y2M5MTY=
But both should be same. The c# one is correct, I want the same in the php code as well.
From the PHP docs for hash:
hash ( string $algo , string $data , bool $binary = false ) : string|false
binary
When set to true, outputs raw binary data. false outputs lowercase hexits.
You're not passing a value for $binary, so it's returning a string of hexadecimal characters.
The C# HashAlgorithm.ComputeHash method on the other hand binary data.
Since you're base64-encoding the result, you're presumably expecting the hash function to return binary data. You therefore need to pass true as the value for $binary:
$signature = base64_encode(hash('sha512', $utf, true));
Related
Below is the code of both C# and PHP, I need some help regarding it. I am trying to generate the authenticationKey which is in C# but want the convert in PHP. All is done but I don't know how to implement [System.Text] in PHP as there is hash_hmac() in PHP but what might be the $string in the same function.
C# Version
var hmac = new System.Security.Cryptography.HMACSHA256();
var buffer = userName + accessKey + timeStamp + originUrl;
var hash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(buffer));
var authenticationKey = Convert.ToBase64String(hash);
PHP version
$hmac = hash_hmac('sha256', $string, $buffer);
$encoded = base64_encode($hmac);
Can anyone help me with that. It will be very helpful. Thanks.
I was also searching for this and atlast it was just a mistake of 1 small varibale, in the hash_hmac function pass the last value as true, this is will return raw output and when you convert it to base64 it will give the same output as the c# code.
$buffer = $userName.$accessKey.$timeStamp.$originUrl;
$hmac = hash_hmac('sha256', $buffer, $tokenSecret, true);
$authenticationKey = base64_encode($hmac);
Just in your c# function use the key, as shown in the code below
var hmac = new System.Security.Cryptography.HMACSHA256();
hmac.Key = System.Text.Encoding.UTF8.GetBytes(tokenSecret);
In my code I have tokenSecret variable in bas64 form.
You may get the hex value, using unpack method:
$value = unpack('H*', buffer);
echo $value[1];
In your c# code, you used a randomly generated key. Check the documentation:
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hmacsha256?view=netframework-4.8#constructors
HMACSHA256()
Initializes a new instance of the HMACSHA256 class with a randomly generated key.
HMACSHA256(Byte[])
Initializes a new instance of the HMACSHA256 class with the specified key data
Now the php documentation in comparison: https://www.php.net/manual/en/function.hash-hmac.php
hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = FALSE ] ) : string
You see, what you call buffer in php, is actually the key and what you call buffer in c# is the data you hash.
So the$string should contain the data to be hashed.
As per the conversion, you don't need to get bytes in php: What is the PHP equivalent of this C# encoding code?
I have tried rather unsuccessfully , to convert the following php code to C#
and require help please.
php code is
$string="012014Te$ting#501834502014060007400";
$salt = "Cli3ntH#sah";
$utfString=mb_convert_encoding($string.$salt,ÄSCII");
$hashTag=sha1($utfString,true);
$Hash = base64_encode($hashTag);
with C# code
byte[] ascii = Encoding.ASCII.GetBytes(objtohash);
byte[] utf8 = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, ascii);
byte[] hashBytes2 = sha1.ComputeHash(utf8);
var Hash = Convert.ToBase64String(hashBytes2);
also tried this, where objtohash = $string.$salt (i.e. concatenated)
var sha1 = new System.Security.Cryptography.SHA1Managed();
//convert to ascii byte array
byte[] AScii = EncodeAscii(objtohash);
//Hash it
byte[] hashBytes = sha1.ComputeHash(AScii);
//convert it to base 64
var Hash = Convert.ToBase64String(hashBytes);
I have tried several other ways as per SO, but I cannot get the same hashed value as the php sample.Hopefully someone can do it and hopefully give explanation as to why.
Thanks
The syntax error was finger trouble.
The answer it turns out, ..basically by trying any and all combinations of what i could find by googling is:
var objtohashArry = Encoding.ASCII.GetBytes(objtohash);
var HashSharresult = SHA1.Create().ComputeHash(objtohashArry);
var requestHash = Convert.ToBase64String(HashSharresult);
RequestHash = requestHash;
I'm working on rewriting a piece of PHP code to C#. This code is used for password hashing. In the first step it produces a string like "password{salt}", than hashes it via sha512 hash algorithm. After that a loop is hashing the combination of the first hash and the salt again for 5000 iterations.
The PHP Code looks like this:
<?php
$password = 'abc';
$salt = 'def';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
for ($i=1; $i<5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encodedPassword = base64_encode($digest);
//$encodedPassword contains the final hash code
I was able to get it working without the loop (with just the first hash() call). So the main hashing and base64 encoding is done correctly. I found out that this part is what I cannot manage to rewrite in C#:
$digest.$salted
$digest seems to be a binary representation since PHP's hash() function was used with "true" as the last parameter (see PHP hash - manual). $salted is a string. Both get somehow magically combined by PHP's dot / concat operator. I guess there will be some sort of standard conversion from binary to string under the hood when using the dot operator with a non-string operand.
This is my code so far:
void Main()
{
string password = "abc";
string salt = "def";
string salted = String.Format("{0}{{{1}}}", password, salt);
byte[] digest = hash(salted);
for(int i = 1; i < 1; i++)
{
digest = hash(String.Format("{0}{1}", System.Text.Encoding.UTF8.GetString(digest), salted));
}
var encodedPassword = System.Convert.ToBase64String(digest);
//$encodedPassword should contain the final hash code
}
static byte[] hash(string toHash)
{
System.Security.Cryptography.SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
return sha512.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toHash));
}
As you see I tried to convert the hash bytes back to a string with System.Text.Encoding.UTF8.GetString() and then append the salt but that doesn't produce the same output as the PHP code.
I would be very happy if someone could help me on this. Thank you very much.
In the PHP version you loop 4999 times, while in the C# version 0. The second problem is that the returned bytes from hash() have no encoding at all.
This should give you the same result as the PHP version:
System.Security.Cryptography.SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
var saltedUtf8Bytes = System.Text.Encoding.UTF8.GetBytes(salted);
for(int i = 1; i < 5000; i++)
{
digest = sha512.ComputeHash(digest.Concat(saltedUtf8Bytes).ToArray());
}
This is my PHP code:
<?php
$sig_string = "GET&https%3A%2F%2Fapi.pinterest.com%2Fv3%2Fusers%2Farchimede%2Fboards%2F&client_id=987654×tamp=1391761866";
$secret = "123456";
$sig = hash_hmac("sha256", $sig_string, $secret);
echo $sig;
?>
which returns (correctly) a7918aec50919915f3cefed8622ddbe35448c8f71a54ad115828f07a05930f4c
Now, I want to translate this function inside C#. Code:
signature_base_string = "GET&https%3A%2F%2Fapi.pinterest.com%2Fv3%2Fusers%2Farchimede%2Fboards%2F&client_id=987654×tamp=1391761866";
signing_key = "123456";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(signing_key);
byte[] messageBytes = encoding.GetBytes(signature_base_string);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
Response.Write(Convert.ToBase64String(hashmessage));
}
but it retuns p5GK7FCRmRXzzv7YYi3b41RIyPcaVK0RWCjwegWTD0w=
Why two different results? Whats wrong in the C# code?
PHP encodes the result in hexadecimal and c# encodes that in base64. But the are same.
Change this line:
Response.Write(Convert.ToBase64String(hashmessage));
To this:
Response.Write(BitConverter.ToString(hashmessage).Replace("-", "").ToLower());
to have the result in hexadecimal encoding.
They are the same:
The result from .NET C# is p5GK7FCRmRXzzv7YYi3b41RIyPcaVK0RWCjwegWTD0w=. This is a base64 string.
You can convert it to hexadecimal using this tool for example. And you'll get the same as PHP after converting:
A7918AEC50919915F3CEFED8622DDBE35448C8F71A54AD115828F07A05930F4C
I have a hashing method in C# that looks like:
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] raw_input = Encoding.UTF32.GetBytes("hello");
byte[] raw_output = md5.ComputeHash(raw_input);
string output = "";
foreach (byte myByte in raw_output)
output += myByte.ToString("X2");
return output;
How can I implement this in PHP? Doing the following produces a different hash digest...
$output = hash('md5', 'hello');
PHP
This PHP code will do:
<?php
$str = "admin";
$strUtf32 = mb_convert_encoding($str, "UTF-32LE");
echo md5($strUtf32);
?>
This code outputs "1e3fcd02b1547f847cb7fc3add4484a5"
You need to find out which encoding PHP is using to convert your string to text. It's very unlikely that it's using UTF-32. It may well be using the platform default encoding, or possibly UTF-8.
using (MD5 md5 = MD5.Create())
{
byte[] input = Encoding.UTF8.GetBytes("hello");
byte[] hash = md5.ComputeHash(input);
return BitConverter.ToString(hash).Replace("-", "");
}
(This is the problem with languages/platforms which treat strings as binary data all over the place - it doesn't make it clear what's going on. There has to be a conversion to bytes here, as MD5 is defined for bytes, not Unicode characters. In the C# code you're doing it explicitly... in the PHP it's implicit and poorly documented.)
EDIT: If you've got to change the PHP, you could try this:
$text = mb_convert_encoding($text, "UTF-32LE");
$output = md5($text)
It depends whether PHP supports UTF-32 though...
When you apply md5 to Encoding.UTF32.GetBytes("admin");, that's same as
echo hash( "md5","a\0\0\0d\0\0\0m\0\0\0i\0\0\0n\0\0\0");
//1e3fcd02b1547f847cb7fc3add4484a5
In php.
You need to convert your string to UTF32-LE in PHP:
echo md5( mb_convert_encoding( "admin", "UTF-32LE" ) );
//1e3fcd02b1547f847cb7fc3add4484a5