I have to replicate C# hash from the code below into PHP. I have been searching but didn't find a solution so far.
From this article on creating an md5 hash string:
using System;
using System.Text;
using System.Security.Cryptography;
// Create an md5 sum string of this string
static public string GetMd5Sum(string str)
{
// First we need to convert the string into bytes, which
// means using a text encoder.
Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
// Create a buffer large enough to hold the string
byte[] unicodeText = new byte[str.Length * 2];
enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
// Now that we have a byte array we can ask the CSP to hash it
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(unicodeText);
// Build the final string by converting each byte
// into hex and appending it to a StringBuilder
StringBuilder sb = new StringBuilder();
for (int i=0;i<result.Length;i++)
{
sb.Append(result[i].ToString("X2"));
}
// And return it
return sb.ToString();
}
For input = "123", the above code gives me "5FA285E1BEBE0A6623E33AFC04A1FBD5"
I have tried the following PHP code but it does not give the same output.
From the SO question PHP MD5 not matching C# MD5:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-32LE");
echo md5($strUtf32);
This code has the result = "a0d5c8a4d386f15284ec25fe1eeeb426". By the way, changing UTF-32LE to utf-8 or utf-16 still does not give me the same result.
Can anyone help?
Yep, as CodesInChaos suggests, you got the encodings wrong.
On php side try this:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16LE");
echo md5($strUtf32);
This will give you 5FA285E1BEBE0A6623E33AFC04A1FBD5. This will match System.Text.Encoding.Unicode on the c# side.
Otherwise change System.Text.Encoding.Unicode to System.Text.Encoding.UTF32 on the c# side. This will give you A0D5C8A4D386F15284EC25FE1EEEB426.
Uhh, the C# code creates a MD5 hash and the PHP mb_convert_encoding function just encodes the string...
Plus, this is NOT THE FULL CODE from the link you gave. You are missing the important MD5 function:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16");
echo md5($strUtf32); <=====
If that code matches there should be NO REASON why that shouldn't work, as the MD5 algorithm is still the same and does not vary from language to language.
Related
I'm struggling badly trying to decrypt some values in C# that are encrypted in PHP. The encryption in PHP is done using the following:
function encrypt($pure_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = 'fÔdñá1f¦';
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
$encrypted_string = base64_encode($encrypted_string);
return $encrypted_string;
}
Since ECB mode is used IV probably it's not used, but still that doesn't help. The biggest issue is that PHP documentation is so poor and it doesn't specify what encoding the functions are using! The string passed around have different byte values depending on the encoding and in the end encryption (Blowfish in this case) deals with bytes.
Without knowing the encoding, I'm just trying different encodings in my C# code, but without success. Somewhere I read that PHP is using internally "iso-8859-1" encoding, but even with that it's not working.
Has anyone been successful in decrypting in C# some value that was encrypted in PHP using the stupid function mcrypt_encrypt()?
Update
I did an example in PHP. Code:
define("ENCRYPTION_KEY", "1234asdf");
define("IV", "1#^ÊÁñÔ0");
$clearText = "abc";
function encrypt($pure_string, $encryption_key, $iv) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
$encrypted_string = base64_encode($encrypted_string);
return $encrypted_string;
}
$encrypted_string = encrypt($clearText, ENCRYPTION_KEY, IV);
echo "Key:" . ENCRYPTION_KEY . "<br />";
echo "IV:" . IV . "<br />";
echo "Clear Text:" . $clearText . "<br />";
echo "Encrypted Text:" . $encrypted_string . "<br />";
and the result is:
Key:1234asdf
IV:1#^ÊÁñÔ0
Clear Text:abc
Encrypted Text:OiZ6QIdhXYk=
Also I confirmed that IV is not used, any value I pass the result is the same.
Well, the problem in you case is not the blowfish decryption part in c#, it is the encryption part in php. And no, this is not about using mcrypt_encrypt, it is the mistake to call utf8_encode on an already utf8 encoded string...
The decryption function i've created uses BouncyCastle. There are two encrypted strings, the first has been created with the php function you've posted, for the second one i've removed the utf8_encode call inside mbcrypt_encrypt.
The first sample uses the (bad) php_utf8_encoded string, we need to convert the decrypted byte array back and forth to get the correct result.
Debug the second call of the c# decryption function and have a look at the result of the first str1 produced by Encoding.UTF8.GetBytes. Its correct, without the back-and-forth conversion of the charset.
public static string BlowfishDecrypt(string encrypted, string key)
{
var cipher = new BufferedBlockCipher(new BlowfishEngine());
var k = new KeyParameter(Encoding.UTF8.GetBytes(key));
cipher.Init(false, k);
var input = Convert.FromBase64String(encrypted);
var length = cipher.GetOutputSize(input.Length);
var block = new byte[length];
var len = cipher.ProcessBytes(input, 0, input.Length, block, 0);
var output = cipher.DoFinal(block, len);
// dont know how we get the real length of the content here... but this will do it. But I am sure there is a better way...
var idx = Array.IndexOf(block, (byte)0);
var str1 = Encoding.UTF8.GetString(block, 0, idx);
var raw1 = Encoding.GetEncoding("iso-8859-1").GetBytes(str1);
var str2 = Encoding.UTF8.GetString(raw1);
return str2;
}
static string original = "#€~>|";
static string encrypted_with_utf8_encode = "7+XyF+QGcA8lz5AQlLf1FA==";
static string encrypted_without = "3oWsAOEF+Kc=";
static string key = "t0ps3cr3t";
public static void Main()
{
var decrypted1 = BlowfishDecrypt(encrypted_with_utf8_encode, key);
var decrypted2 = BlowfishDecrypt(encrypted_without, key);
var same = original.Equals(decrypted1);
Debugger.Break();
}
In the end was able to do it. A few pointers:
Some Blowfish libraries in C# seems to have bad implementation. The one that worked correctly was https://github.com/b1thunt3r/blowfish-csharp
Never use methods that deal with strings directly. That's stupid in the first place to offer in any library (even the one above has overloads that work with string and it "supposes" that strings are in Unicode!)
When dealing with different platforms, try to convince the other party to use base64 encoding.
In the end, I am amazed that why so many developers (even the ones developing crypto libraries) don't get it that working with strings without specifying an encoding is stupid and does not make any sense!
I have something like that written in PHP:
$signature = md5($tosigndata);
Now, I am trying to replicate this in C#:
MD5.Create().ComputeHash(Tools.GetBytes(tosigndata))
But that gives me totally different result. How do I need to change my C# code in order to match PHP hash?
PS. Yeah, I know that .ComputeHash() returns byte[], but that doesn't change anything, i tried decoding it and it's still a different string.
Edit: Tools.GetBytes() returns Encoding.UTF8.GetBytes(tosigndata);
try this in C#:
byte[] asciiBytes = ASCIIEncoding.ASCII.GetBytes(tosigndata); // tosigndata is your string variable
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
// hashString contains your hash data similar to php md5
I have looked and found code to take a PHP sha512 hash and match it inside C#. I am currently looking for a way to go from a hash that was made in C# and get the same result in PHP. We are slowly moving away from asp.net to PHP and need a way to check our passwords in the database. Here is the C# code used to make the hash.
// Create a hash from a pwd and salt using sha512
public static string CreatePasswordHash(string _password, string _salt)
{
string saltAndPwd = String.Concat(_password, _salt);
SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
byte[] sha512Bytes = System.Text.Encoding.Default.GetBytes(saltAndPwd);
byte[] cryString = sha512.ComputeHash(sha512Bytes);
string hashedPwd = string.Empty;
for (int i = 0; i < cryString.Length; i++)
{
hashedPwd += cryString[i].ToString("X");
}
return hashedPwd;
}
In PHP I have tried to get it to match but it is off by just a few bytes it seems.
function CreatePasswordHash($_password, $_salt)
{
$saltAndPwd = $_password . $_salt;
$hashedPwd = hash('sha512', $saltAndPwd);
return strtoupper($hashedPwd);
}
When using the above with the same salt and password here is the results I get.
The first result is from C#, and the second result is from PHP:
60BB73FDA3FF7A444870C6D0DBC7C6966F8D5AD632B0A02762E0283051D7C54A5F4B01571D1A5BC8C689DBC411FEB92158383A56AFC6AE6074696AF36E16
60BB73FDA3FF7A444870C6D0DBC7C609066F8D5AD632B0A02762E0283051D7C54A5F4B001571D1A5BC8C689DBC411FEB092158383A56AFC6AE6074696AF36E16
Any ideas on why these are not matching up? Does it have to do with endian byte order?
try
hashedPwd += cryString[i].ToString("X2");
Editing PHP:
function CreatePasswordHash($_password, $_salt)
{
$saltAndPwd = $_password . $_salt;
$hashedPwd = hash('sha512', $saltAndPwd);
$hex_strs = str_split($hashedPwd,2);
foreach($hex_strs as &$hex) {
$hex = preg_replace('/^0/', '', $hex);
}
$hashedPwd = implode('', $hex_strs);
return strtoupper($hashedPwd);
}
The C# print out is not including leading zeros.
Replace
hashedPwd += cryString[i].ToString("X");
with
hashedPwd += cryString[i].ToString("X2");
Double check that you use the same character encoding in C# and PHP. GetBytes returns different results, depending on the encoding. System.Text.Encoding.Default depends on the localization of the OS.
You can try open_ssl_digest
echo openssl_digest($saltAndPwd, 'sha512');
if you have PHP >= 5.3
You could also use the hash_algos function to see which algorithms are supported in your system.
HTH
I am converting my Java code to C#. I am not able to convert the following function from Java to C#. The fumction is calling the Update method twice. I have tried the C# code in following manner
SHA256 sh = SHA256.Create();
Encoding shEncoding = Encoding.UTF7;
byte[] data = shEncoding.GetBytes(sn);
byte hash = sh.ComputeHash(data);
But I don't know how to convert two consecutive update function call in C#.
String getSHA(byte[] sf,String sn,byte[] mac) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(sf);
md.update(sn.getBytes());
byte[] hash = md.digest(mac);
StringBuilder sb = new StringBuilder();
for(byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
Thanks in Advance.
Your help/guidance will help me lot.
You can use TransformBlock and TransformFinalBlock on SHA256 (~update and digest in Java) and retrieve the hash using the Hash property.
i have a hashing algorithm in C#, in a nutshell, it is:
string input = "asd";
System.Security.Cryptography.MD5 alg = System.Security.Cryptography.MD5.Create();
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
byte[] hash = alg.ComputeHash(enc.GetBytes(input));
string output = Convert.ToBase64String(hash);
// outputs: eBVpbsvxyW5olLd5RW0zDg==
Console.WriteLine(output);
Now I need to replicate this behaviour in php,
$input = "asd";
$output = HashSomething($input);
echo $output;
How can I achieve it?
I checked
md5
utf8_decode
utf8_encode
base64_encode
base64_decode
url_decode
but i noted the php md5 doesn't get the == on the end... what am I missing?
NOTE: I cannot change C# behaviour because it's already implemented and passwords saved in my db with this algorithm.
The issue is PHP's md5() function by default returns the hex variation of the hash where C# is returning the raw byte output that must then be made text safe with base64 encoding. If you are running PHP5 you can use base64_encode(md5('asd', true)). Notice the second parameter to md5() is true which makes md5() return the raw bytes instead of the hex.
Did you remember to base64 encode the md5 hash in php?
$result = base64_encode(md5($password, true));
The second parameter makes md5 return raw output, which is the same as the functions you're using in C#
Your C# code takes the UTF8 bytes from the string; calculates md5 and stores as base64 encoded. So you should do the same in php, which should be:
$hashValue = base64_encode(md5(utf8_decode($inputString)))
it should be like as below for php
php -r "echo base64_encode(md5(utf8_encode('asd'),true));"
I had the same issue...using just md5($myvar) it worked. I am getting the same result C# and PHP.
Gavin Kendall posted helped me. I hope this helps others.
http://jachman.wordpress.com/2006/06/06/md5-hash-keys-with-c/
public static string MD5Hash(string text)
{
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
return System.Text.RegularExpressions.Regex.Replace(BitConverter.ToString(md5.ComputeHash(ASCIIEncoding.Default.GetBytes(text))), “-”, “”);
}