4

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==

5
  • What is the problem - are you getting an error or a different result? Can you provide examples demonstrating the differences you are seeing? Commented Jan 27, 2013 at 19:37
  • @PinnyM I've added some more information to the question, in answer to your question, I am getting different results between PHP and C# Commented Jan 27, 2013 at 19:39
  • Do you really need to replicate this C# code? It has quite some flaws. For example it doesn't use an IV. An IV isn't a kind of key. It's a value that should be different for each encryption, and in the case of CBC it should be unpredictably random. Commented Jan 27, 2013 at 19:42
  • .NET defaults to CBC block mode, your PHP is specifying ECB. Commented Jan 27, 2013 at 19:43
  • Tangentially related: your C# code is using 4 classes (that I can see) which implement IDisposable. These should optimally be wrapped in using statements. Commented Jan 27, 2013 at 19:49

2 Answers 2

3

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;
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, I've tried changing the mode CBC in PHP and I get a different result which is now 5XuJaW+G27lcJaAG1D0uZw== but still doesn't match with C#. I really can't change the C# code as this would effect an already working and being used piece of software and the same encryption technique is also being used on an Android app so it is only the PHP I can change
@Boardy I have updated with one more change you need to put in place.
Thanks for your help, would the padding need to be stripped off when decrypting as at the moment when I try decrypting it again I get funny characters printed such as Té_ªÅ instead of password
Yes you'd have to strip the padding, just pass it through the strippadding I added in my edit (but only after you do the decryption).
thanks very much again, much appreciated. working perfectly now
1

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;

3 Comments

The second argument to mcrypt_create_iv is invalid. The second argument is a randomness source, and should always be MCRYPT_DEV_URANDOM.
Thanks, I really can't change the C# code, this is already being used on released software and is working with the same encryption technique which is being used on an Android app. The Android App, C# app and web site all need to work together.
So change the PHP from MCRYPT_MODE_ECB to MCRYPT_MODE_CBC

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.