0

I want to encrypt a text in PHP and to decrypt in in C#, but i can't.

This is my PHP code:

define('AES_256_ECB', 'aes-256-ecb');
$encryption_key = "SomeSimpleTest";
$data = "Test123";
$encryptedData = openssl_encrypt($data, AES_256_ECB, $encryption_key, 0);

..and this is my C# code:

(AESEncryption.cs class)

   using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Security.Cryptography;

    namespace AESCrypto
    {
        class AESEncryption
        {
            public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
            {
                byte[] decryptedBytes = null;
                // Set your salt here to meet your flavor:
                byte[] saltBytes = passwordBytes;
                // Example:
                //saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

                using (MemoryStream ms = new MemoryStream())
                {
                    using (RijndaelManaged AES = new RijndaelManaged())
                    {
                        AES.KeySize = 256;
                        AES.BlockSize = 256;

                        var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                        AES.Key = key.GetBytes(AES.KeySize / 8);
                        AES.IV = key.GetBytes(AES.BlockSize / 8);

                        AES.Mode = CipherMode.ECB;
                        //AES.Padding = PaddingMode.PKCS7;

                        using (CryptoStream cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                            cs.Close();
                        }
                        decryptedBytes = ms.ToArray();
                    }
                }

                return decryptedBytes;
            }

            public static string Decrypt(string decryptedText, byte[] passwordBytes)
            {
                byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);

                // Hash the password with SHA256
                passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

                byte[] decryptedBytes = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

                // Getting the size of salt
                int saltSize = GetSaltSize(passwordBytes);

                // Removing salt bytes, retrieving original bytes
                byte[] originalBytes = new byte[decryptedBytes.Length - saltSize];
                for (int i = saltSize; i < decryptedBytes.Length; i++)
                {
                    originalBytes[i - saltSize] = decryptedBytes[i];
                }

                return Encoding.UTF8.GetString(originalBytes);
            }

            public static int GetSaltSize(byte[] passwordBytes)
            {
                var key = new Rfc2898DeriveBytes(passwordBytes, passwordBytes, 1000);
                byte[] ba = key.GetBytes(2);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < ba.Length; i++)
                {
                    sb.Append(Convert.ToInt32(ba[i]).ToString());
                }
                int saltSize = 0;
                string s = sb.ToString();
                foreach (char c in s)
                {
                    int intc = Convert.ToInt32(c.ToString());
                    saltSize = saltSize + intc;
                }

                return saltSize;
            }

            public static byte[] GetRandomBytes(int length)
            {
                byte[] ba = new byte[length];
                RNGCryptoServiceProvider.Create().GetBytes(ba);
                return ba;
            }
        }

    }

Usage of it:

    using AESCrypto;

    ...
 public string DecryptText(string input, string password)
            {
                // Get the bytes of the string
                byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
                byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
                passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

                byte[] bytesDecrypted = AESEncryption.AES_Decrypt(bytesToBeDecrypted, passwordBytes);

                string result = Encoding.UTF8.GetString(bytesDecrypted);

                return result;
            }

     private void btn1_Click(object sender, EventArgs e)
            {
                textBox1.Text = DecryptText("KEY_ENCRYPTED_WITH_PHP", "SomeSimpleTest");
            }

I even tried with CBC but does not work...The mode of encryption is not important. I only want to make it work as it should. Thanks.

9
  • You define your constant as AES_256_ECB but reference it as AES_256_ecb (This is why it's good to pay attention to notice-level messages). Commented Apr 19, 2017 at 19:47
  • 2
    1. The encryption mode is only important if the encryption needs to be secure. 2.The encryption mode must be the same for both and if CBC mode the IV must be the same. 3. The encryption key should be an exact supported length and also the same. 4. You should explicitly specify the padding for both, PKCS#7 (née PKCS#5) is a good choice 5. Verify the encodings, if any, of all inputs/outputs. Commented Apr 19, 2017 at 20:50
  • 1
    As zaph said. Your key stuff is completely different. AES-256 expects a 256 bit key. Your "SomeSimpleTest" key is only 112 bits long. This is not a valid key. Additionally, your PHP code isn't doing any key derivation, so you don't need SHA256 or Rfc2898DeriveBytes in C#. Then setting AES.BlockSize = 256; doesn't mean that it is AES. This is Rijndael and not AES anymore. Commented Apr 19, 2017 at 21:48
  • 1
    Never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme. Commented Apr 19, 2017 at 21:49
  • 1
    Yes, AES.BlockSize = 128 is the default and necessary in order to do actual AES. You don't need to change the padding. OpenSSL and C# are doing PKCS#7 padding by default. Commented Apr 20, 2017 at 17:22

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.