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
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 a code to generate hash in C#:
string hash = GetHash("Ю-41241624.05.1991");
public static string GetHash(string str)
{
Encoding eu = Encoding.UTF8;
byte[] data = eu.GetBytes(str);
SHA1 sha = new SHA1CryptoServiceProvider();
return Convert.ToBase64String(sha.ComputeHash(data));
}
The result is:
G7xY+gb35Lw4HlDnTZP89FU3Khk=
And I try to get the same result in PHP:
$str = mb_convert_encoding("Ю-41241624.05.1991","UTF-8");
$hash = sha1($str,true);
$base64 = base64_encode($hash);
echo $base64;
But the result is:
Dg+x7F8lsC/r9O8PNskgJ/MwNgU=
Just get rid of mb_convert_encoding(), if the string is already UTF-8 it will mess things up.
When I run the code without that function I get the correct result: https://eval.in/620412
Hi your problem is in "YU" character. Your c# code looks fine. When you debug the code only with this character, you will get byte array with values 208 174 which is really Ю character in UTF8. So c# code should works fine and sha1 from c# should be good.
Can you get byte numbers from php only for char Ю? It should be also 208 and 174.
If you remove this character your hash string should be equal.
I'm trying to get the HMAC SHA256 value(str_signature), I followed the Ruby code from this post, although his example was converting code from Java(with a Hex key).
C#
string strRawSignature = "200123123891:12|11231231|GET|just%20test%20value"
// Convert signature to byte array in order to compute the hash
byte[] bSignature = Encoding.UTF8.GetBytes(strRawSignature);
// Convert ApiKey to byte array - for initializing HMACSHA256
byte[] bSecretKey = Convert.FromBase64String(strApiKey);
string strSignature = "";
using (HMACSHA256 hmac = new HMACSHA256(bSecretKey))
{
// Compute signature hash
byte[] bSignatureHash = hmac.ComputeHash(bSignature);
// Convert signature hash to Base64String for transmission
str_signature = Convert.ToBase64String(bSignatureHash);
}
Ruby
require "openssl"
require "base64"
digest = OpenSSL::Digest.new('sha256')
key = [ 'xiIm9FuYhetyijXA2QL58TRlvhuSJ73FtdxiSNU2uHE=' ]
#this is just a dummy signature to show what the possible values are
signature = "200123123891:12|11231231|GET|just%20test%20value"
hmac = OpenSSL::HMAC.digest(digest, key.pack("m*"), signature)
str_signature = Base64.urlsafe_encode64(hmac)
example result: "B0NgX1hhW-rsnadD2_FF-grcw9pWghwMWgG47mU4J94="
Update:
Changed the pack method to output base64 strings.
Edited variable names for concistency
References:
Used hexdigest, has a different ouput string length.
This example uses the digest method, although I'm not sure what value the key parameter has, hopefully it's a base 64 encoded string.
This uses hexdigest again. I am pretty sure that digest is the method to go vs hexdigest, since hexdigest ouput has a longer string compared to the sample HMAC value I have from C# script.
Finally got the monkey of my back!
I don't really need to create a sha256 digest object after all, I just had to put the 'sha256' parameter.
require 'openssl'
require "base64"
#API_KEY = base64 encoded string
key = Base64.decode64(API_KEY)
hash = OpenSSL::HMAC.digest('sha256', key, "Message")
puts Base64.encode64(hash)
thanks to this link
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.
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))), “-”, “”);
}