Search code examples
c#phpbouncycastlephp-openssl

Unable to exchange AES-256-CBC/PKCS7 between C# bouncycastle and PHP openssl


so I have the following code in C# and PHP, and so far the results are not consistent between both side. For C#, I am using bouncy castle API, and for PHP I am using openSSL. Just to be sure, I also encrypted the same thing in C# using Microsoft Crypto Library, and I got the the same cipher text, but not when they are exchanged with PHP.

C#

    public const string AES_ALGORITHM = "AES/CBC/PKCS7";
    public const string CRYPTO_ALGORITHM = "AES";
    public AESController(string key) {
        encryptionKey = Convert.FromBase64String(key);
    }
    public string encrypt(string plainText, byte[] iv) {
        string cipherText = "";
        //setting up AES Key
        KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);

        // Setting up the Initialization Vector. IV is used for encrypting the first block of input message
        ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);

        // Create the cipher object for AES algorithm using GCM mode and NO padding
        IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
        cipher.Init(true, aesIVKeyParam);

        byte[] output = cipher.DoFinal(Encoding.UTF8.GetBytes(plainText));

        cipherText = Convert.ToBase64String(output);
        return cipherText;
    }

    public string decrypt(string cipherText, byte[] iv) {
        string plainText = "";
        //setting up AES Key
        KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);

        // Setting up the Initialization Vector. IV is used for encrypting the first block of input message
        ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);

        // Create the cipher object for AES algorithm using GCM mode and NO padding
        IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
        cipher.Init(false, aesIVKeyParam);


        byte[] output = cipher.DoFinal(Convert.FromBase64String(cipherText));

        plainText = Encoding.UTF8.GetString(output);
        return plainText;
    }

     static void Main(string[] args) {
        AESController aes = new AESController("OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=");
        byte[] iv = Base64.Decode("fdL8sKmhC8YIrYHMzoJJvQ==");
        string encryptedText = "TESTING123";

        string cipherText = aes.encrypt(encryptedText, iv);
        Console.Out.WriteLine("IV: " + Encoding.UTF8.GetString(Base64.Encode(iv)));
        Console.Out.WriteLine("Plain Text:"+aes.decrypt(cipherText, iv));
        Console.Out.WriteLine("Cipher Text:" + cipherText);

        Console.In.ReadLine();
    }

and then PHP:

    $key = "OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=";
    $iv = base64_decode("fdL8sKmhC8YIrYHMzoJJvQ==");
    //$iv = openssl_random_pseudo_bytes(16);
    //$cipherText = "YMdJ0mdWZ+p50krLzhyI0Q==";
    $plainText = "TESTING123";
    $decrypted = openssl_encrypt($plainText, "aes-256-cbc", $key, 0, $iv);

    var_dump($decrypted);

So, the cipher text that come from C# bouncycastle is :

EnOtpv4fOGiAKMzXXJMYBA==

and cipher text that come from PHP is :

Cs+f7a/DBEGma7iQ/PQVLw==

and if I take that c# cipher text to PHP, the decrypted result is : bool(False) (encryption failed)

Lastly, if in PHP, I change the padding to OPENSSL_ZERO_PADDING, and decrypt cipher text from C#, the result is :

���_�X�GmNSlZx�

For what I can gather, the key and IV is the same on both (both are BASE64 string), the encrypted results have the same length(which explains the two == at the end of the cipher text. Is there anything that I miss, or I need to do something special for openssl library? Thanks.


Solution

  • Unlike the OpenSSL command-line tools, PHP's openssl functions expect raw inputs and not Base64-encoded ones.

    In your PHP code, you haven't Base64-decoded the key.