在PHP中从C#复制相同的AES加密

在PHP中从C#复制相同的AES加密

问题描述:

I am working on a project where I have a C# application which has an encryption class which can perform encryption and decryption of a string value. I now want to make a web interface to work alongside my C# application using PHP.

I am trying to do the same sort of encryption that my C# project is doing in my PHP web site but I can't work out what I need to do.

Below is the code for my C# application.

public static string encrypt(string encryptionString)
        {
            byte[] clearTextBytes = Encoding.UTF8.GetBytes(encryptionString);

            SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();

            MemoryStream ms = new MemoryStream();
            byte[] rgbIV = Encoding.ASCII.GetBytes("PRIVATE");

            byte[] key = Encoding.ASCII.GetBytes("PRIVATE");
            CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write);

            cs.Write(clearTextBytes, 0, clearTextBytes.Length);

            cs.Close();

            return Convert.ToBase64String(ms.ToArray());
        }

I am trying the following code in my PHP web interface

define("CIPHERKEY", "PRIVATE");
function encrypt($data) 
    { 
        //$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_ECB, '');
        $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
        //$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($cipher), MCRYPT_RAND);
        $iv = 'PRIVATE';
        //$key = substr(CIPHERKEY, 0, mcrypt_enc_get_key_size($cipher));
        $key =CIPHERKEY;
        if (mcrypt_generic_init($cipher, $key, $iv) != 1) 
        {
            $cipherData = mcrypt_generic($cipher, $data);

            mcrypt_generic_deinit($cipher);
            mcrypt_module_close($cipher);

            $sanitizedCipherData = trim(base64_encode($cipherData)); 

            return $sanitizedCipherData;
        } 
    }

I've tried various variations but can't find the correct way to do it.

The iv variable is using the same key as in the rgbIV variable within the C# app and the CIPHERKEY in the PHP web interface is using the same key as in the key variable within my c# app.

Thanks for any help you can provide

UPDATE At the moment I keep on getting different results. I am testing it by passing in the string password.

In the current code above in PHP I get NHHloywxlybbANIH5dS7SQ== as the encrypted string.

However, with the same string I get the result of n86Mwc5MRXzhT3v3A/uxEA==

The reason you're getting different results is that by default the Cipher Mode in C# is CBC whereas in PHP you are using ECB Mode See Wikipedia for information on the two different modes.

CBC is more secure than ECB so I recommend sticking with the default .NET implementation and changing your PHP code to use CBC however you do have two options.

Option 1 - Change .NET to use ECB mode (if you have some legacy code and you need to use it) But please read about it, ECB mode will leave artifacts behind in your cipher text and will enable attackers to have some knowledge of what you've encrypted (see the Penguin image on the Wikipedia article).

To change the .NET code to use ECB just add a line for the mode:

// Start of your code ...
SymmetricAlgorithm rijn = SymmetricAlgorithm.Create();
rijn.Mode = CipherMode.ECB;

MemoryStream ms = new MemoryStream();
byte[] rgbIV = Encoding.ASCII.GetBytes("PRIVATE");
// Rest of your code ...

Option 2 - Change the PHP script to use CBC mode

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

Update I checked this out in more detail and found that you also need to add padding to your plaintext as well. The following code will give you a match:

PHP Code:

function encrypt($data) 
{ 
    $iv = "AAAAAAAAAAAAAAAA";
    $key = CIPHERKEY;

    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, addpadding($data), MCRYPT_MODE_CBC, $iv));
}

function addpadding($string, $blocksize = 16)
{
    $len = strlen($string);
    $pad = $blocksize - ($len % $blocksize);
    $string .= str_repeat(chr($pad), $pad);
    return $string;
}

The C# code will automatically add padding based on PKCS7.

Update 2 Strip Padding: As stated in the comments, the padding would need to be stripped after decryption.

function strippadding($string)
{
    $slast = ord(substr($string, -1));
    $slastc = chr($slast);
    $pcheck = substr($string, -$slast);
    if(preg_match("/$slastc{".$slast."}/", $string)){
        $string = substr($string, 0, strlen($string)-$slast);
        return $string;
    } else {
        return false;
    }
}

try this:

   function encrypt_str($str) 
    {
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM);
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, "PRIVATE", $str, MCRYPT_MODE_ECB, $iv);
    return rtrim($encrypted);
    }

And Add This to your C#

rijn.Mode = CipherMode.ECB;