-3

I am working on a data exchange integration with my client and the data they send me is encrypted using their C# encrypt method (below).

My app is running PHP 5.3 and I need an equivalent code to decrypt the data they send. I have the PHP code but it'd not decrypt the client data correctly for me.

Clearly I am making some mistake in my encryption/decryption methods, IV key or something. Can anyone spot the mistake?

Thanks.

C# Code (From my client):

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

public class Program
{
    public static void Main()
    {
        var text = "this is a plain string";
        var enc = Program.Encrypt(text);
        Console.WriteLine(enc);
        Console.WriteLine(Program.Decrypt(enc));
    }

    public static string Encrypt(string clearText)
    {
        var EncryptionKey = "1234567890123456";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            byte[] IV = new byte[15];
            var rand = new Random();
            rand.NextBytes(IV);
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }

                clearText = Convert.ToBase64String(IV) + Convert.ToBase64String(ms.ToArray());
            }
        }

        return clearText;
    }

    public static string Decrypt(string cipherText)
    {
        var EncryptionKey = "1234567890123456";
        byte[] IV = Convert.FromBase64String(cipherText.Substring(0, 20));
        cipherText = cipherText.Substring(20).Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }

                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }

        return cipherText;
    }
}

PHP Code I have:

public function encrypt($plainText)
{
    $secretKey = '1234567890123456';

    return rtrim(
        base64_encode(
            mcrypt_encrypt(
                MCRYPT_RIJNDAEL_256,
                $secretKey, $plainText,
                MCRYPT_MODE_ECB,
                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256,
                        MCRYPT_MODE_ECB
                    ),
                    MCRYPT_RAND)
            )
        ), "\0"
    );
}

public function decrypt($encodedData)
{
    $secretKey = '1234567890123456';

    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_256,
            $secretKey,
            base64_decode($encodedData),
            MCRYPT_MODE_ECB,
            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256,
                    MCRYPT_MODE_ECB
                ),
                MCRYPT_RAND
            )
        ), "\0"
    );
}

2 Answers 2

9

Can anyone spot the mistake?

Yes, and the big one isn't really your fault: mcrypt's confusing API strikes again.

That said, there are actually multiple mistakes here.

return rtrim( // unnecessary
    base64_encode(
        mcrypt_encrypt(
            MCRYPT_RIJNDAEL_256, // Not AES
            $secretKey, $plainText,
            MCRYPT_MODE_ECB, // BAD, use MCRYPT_MODE_CBC or 'ctr' instead
            mcrypt_create_iv(
                mcrypt_get_iv_size(      // unless you're going make this
                    MCRYPT_RIJNDAEL_256, // configurable, you should just
                    MCRYPT_MODE_ECB      // hard-code this as an integer
                ),
                MCRYPT_RAND) // BAD, use MCRYPT_DEV_URANDOM
        )
    ), "\0"
); 

If you're going to generate an IV, it should be communicated so your recipient can decrypt the same first block successfully. The C# code does this, the PHP does not.

From a cryptography engineering perspective, you should consider, both in C# land and in PHP, deploying an Encrypt then Authenticate protocol. See this blog post on encryption and authentication. Also, all the crypto code you've ever written is probably broken.

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

Comments

0

It seems like the PHP Script is Using the wrong Mode:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.mode%28v=vs.110%29.aspx
The C# Functions do not set any Mode so the default is CBC.
The PHP part uses ECB instead, which is not only wrong, but insecure.

3 Comments

That's not the only thing. OP uses Rijndael-128 in C# and Rijndael-256 in PHP. OP doesn't derive key and IV in PHP. OP also uses random IV in both encryption and decryption in the PHP code. (Feel free to add this to your answer.)
Just edited the post to make it more specific. Also made a few corrections in the code suggested by Artjom B and EaranMaleasi (thank a lot). The code still does not work. Any more suggestions? I'll keep on looking on my own meanwhile.
@AtherHashmi I rolled back your edit. Please don't change your question after receiving an answer. Your change invalidated the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.