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();
}