C# Encryption to PHP Decryption

C# Encryption to PHP Decryption

Since the string is partially OK, but there is gibberish at the end it would suggest a padding problem within the encryption which expects exact blocks of 256 bytes. I suggest setting the padding as PKCS7 (PaddingMode.PKCS7) instead of Zeros on the C# side which PHP will understand without issues (as it's the default mode on that parser).

Edit: Oops, I did not notice that you had the following in your PHP:

$enc = $_COOKIE["MyCookie"];

This is the caveat. PHP is likely not getting the encrypted data as-is and is running some urldecode sanitizing. You should print this variable to see that it really matches what is being sent from the C# code.

Edit2:

Convert the whitespaces to missing + characters from the cookie by adding this:

str_replace(' ', '+', $enc);

Decrypt C# Encryption with PHP

Well - after finding a sandbox that could take hash_hmac I seem to have sussed it out spurred on by you guys and your comments......

Using this site.

and the following code in it (I just hope it behaves the same in a real situation)

<?php

class Foo {

public function decrypt_full($key, $iv, $encrypted)
{
$dev = $this->pbkdf2("sha1", $key, $iv, 1000, 48, true);
$derived_key = substr($dev, 0, 32); //Keylength: 32
$derived_iv = substr($dev, 32, 16); // IV-length: 16
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $derived_key, base64_decode($encrypted), MCRYPT_MODE_CBC, $derived_iv);
}

private function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');

$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);

$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
return substr($output, 0, $key_length);
}

}
//###########################################################################################
$encrypted = "pLgIEjhNGDMfI0IynoAdbey3NKbOJzgUzYAlU14OWOpuZy7/lr7HRtFhiRKfjbZz";
$iv = "This_is_the_password_salt";
$key = "This_is_the_input_key";

$foo = new foo;
echo "<br/>";
echo "Encrypted String: ".$encrypted."<br/>";
echo "Decrypted string: ".$foo->decrypt_full($key, $iv, $encrypted )."<br/>";
?>

The output is...

Key: .g���13f^sI>M��j$\�+�od�mY# �!
IV: �2]��&y�q� WJ��
Decrypted: Co-operation is the key to success!

Can't wait to tell the PHP guys ;)

PHP to C# Encrypted message - trouble decrypting

Credit to Michael Fehr from the comments.

Apparently C# cannot decrypt using a public key, at least with the libraries I'm using. So the solution is to give the C# code the private key and decrypt all messages from the PHP server with the public key.

It's my understanding that this won't be a security issue, despite the fact that the "private" key is being sent into the wild, because both keys are designed for this exact purpose.

Symmetric encryption between C# and PHP

There are the following issues in the C# code:

  • In the PHP code a 32 bytes key is generated, but because of the specified AES-128 (aes-128-cbc), only the first 16 bytes are taken into account. Accordingly, in the C# code only the first 16 bytes of the key may be considered and not the full 32 bytes (see first comment).
  • In the PHP code openssl_encrypt returns the ciphertext Base64 encoded by default, so this part of the ciphertext must be Base64 decoded in the C# code and not UTF8 encoded (see second comment).
  • AesCryptoServiceProvider uses CBC mode and PKCS7 padding by default, so both do not need to be explicitly specified in the C# code.

The following C# code decrypts the ciphertext encrypted with the PHP code:


string content = "UeWeXUAnu98RKTkMiBGLWpMNy4CRKJErOqTTUfJWrtXziFTELGG+647lw/XT846dj8tlNMITLVBg2cKS3dFINeKot4zlb+gVpfq4oIb/M3a8n3a9XWaeIOrHpNedZmMrYiZoCQ==";

var keyString = content.Substring(0, 16);
var keyBytes = Encoding.UTF8.GetBytes(keyString);

var ivString = content.Substring(32, 16);
var ivBytes = Encoding.UTF8.GetBytes(ivString);

var encString = content.Substring(48);
var encBytes = Convert.FromBase64String(encString);

using var alg = AesCryptoServiceProvider.Create();

alg.IV = ivBytes;
alg.Key = keyBytes;

var decryptor = alg.CreateDecryptor(keyBytes, ivBytes);
using var ms = new MemoryStream(encBytes);
using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
using var sr = new StreamReader(cs);

string decrypted = sr.ReadToEnd();
Console.WriteLine(decrypted);

Please consider with regard to the PHP-Code, that it is inconsistent when a 32 bytes key is generated for AES-128. Instead, a 16 bytes key should be generated. Alternatively, you can switch to AES-256 (aes-256-cbc). And also keep in mind the hint in the first comment: A key must generally not be sent with the ciphertext, because any attacker could easily decrypt the data.

Encrypt / Decrypt data with AES between c# and PHP - decrypted data starts with 255,254

Good news, your decryption seems to work OK.

What you are seeing in the decrypted ciphertext is the byte order mark for UTF-16 LE, which is (incorrectly) indicated by Microsoft as Encoding.Unicode. You need to do either one off two things:

  1. decode the text with a decoder that groks UTF-16 LE including byte order mark;
  2. encode using much more reasonable UTF-8 encoding (in the C# code).

Personally I would put a strong preference on (2).

PHP and C# AES256 encryption - decryption

php code:

define('AES_128_ECB', 'aes-128-ecb');
$encryption_key = "MY_16_CHAR_KEY:)";
$data = "MyOwnEncryptedSecretText";
$encryptedData = openssl_encrypt($data, AES_128_ECB, $encryption_key, 0);

C# code:

public String Decrypt(String text, String key)
{
//decode cipher text from base64
byte[] cipher = Convert.FromBase64String(text);
//get key bytes
byte[] btkey = Encoding.ASCII.GetBytes(key);

//init AES 128
RijndaelManaged aes128 = new RijndaelManaged();
aes128.Mode = CipherMode.ECB;
aes128.Padding = PaddingMode.PKCS7;

//decrypt
ICryptoTransform decryptor = aes128.CreateDecryptor(btkey, null);
MemoryStream ms = new MemoryStream(cipher);
CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);

byte[] plain = new byte[cipher.Length];
int decryptcount = cs.Read(plain, 0, plain.Length);

ms.Close();
cs.Close();

//return plaintext in String
return Encoding.UTF8.GetString(plain, 0, decryptcount);
}

and usage of it:

string DecryptedText = Decrypt("GENERATED_KEY", "MY_16_CHAR_KEY:)");

Now it works great :)
Thanks.

Decrypt string in C# encrypted in PHP (Blowfish)

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

Decrypt PHP encrypted string in C#

Hope this helps:

class Program
{
static void Main(string[] args)
{
Console.WriteLine(Decrypt("47794945c0230c3d"));
}

static string Decrypt(string input)
{
TripleDES tripleDes = TripleDES.Create();
tripleDes.IV = Encoding.ASCII.GetBytes("password");
tripleDes.Key = Encoding.ASCII.GetBytes("passwordDR0wSS@P6660juht");
tripleDes.Mode = CipherMode.CBC;
tripleDes.Padding = PaddingMode.Zeros;

ICryptoTransform crypto = tripleDes.CreateDecryptor();
byte[] decodedInput = Decoder(input);
byte[] decryptedBytes = crypto.TransformFinalBlock(decodedInput, 0, decodedInput.Length);
return Encoding.ASCII.GetString(decryptedBytes);
}

static byte[] Decoder(string input)
{
byte[] bytes = new byte[input.Length/2];
int targetPosition = 0;

for( int sourcePosition=0; sourcePosition<input.Length; sourcePosition+=2 )
{
string hexCode = input.Substring(sourcePosition, 2);
bytes[targetPosition++] = Byte.Parse(hexCode, NumberStyles.AllowHexSpecifier);
}

return bytes;
}
}


Related Topics



Leave a reply



Submit