0

I have to implement a system where we send an encrypted message to another application which we do not control. We use C# whereas the other application uses PHP.

The first thing I wanted to make sure was that, for the same input, I would get the same encrypted output in both C# and PHP.

To be clear, I can not change the PHP code used by the receiving application.

I have used a PHP example using openssl_encrypt (CBC) and a C# example using system.security.cryptography.RijndaelManaged.

PHP test code

$opts=OPENSSL_RAW_DATA;
$plain_text = "wetestendit";
$key = "12345678911234567892123456789312";
$iv = "1234567890123456";
$opts=OPENSSL_RAW_DATA;
$plaintext = "wetestendit";
$key = "12345678911234567892123456789312";
$iv = "1234567890123456";

$saltDing = "Salted__12345678";

$encrypt = openssl_encrypt($plain_text, "AES-256-CBC", $key, $opts, $iv);
$encrypt2 = openssl_encrypt($plain_text, "AES-256-CBC", $key, 0, $iv);

echo $encrypt . "\n";
echo $encrypt2 . "\n";

When using the RAW_Data output format my test gives: ?Y09?¬???}?)?v? as output. When using 0 the output is base64 encoded: x1kwOeUf3fmUfdQpknbjkw==

If I use the following C# function with the same key, iv and input

private string EncryptString(string message, string KeyString, string IVString)
{
    byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
    byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);

    string encrypted = null;
    RijndaelManaged rj = new RijndaelManaged();
    rj.Key = Key;
    rj.IV = IV;
    rj.Mode = CipherMode.CBC;

    MemoryStream ms = new MemoryStream();

    using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
    {
        using (StreamWriter sw = new StreamWriter(cs))
        {
            sw.Write(message);
            sw.Close();
        }
        cs.Close();
    }
    byte[] encoded = ms.ToArray();
    
    ms.Close();

    return Encoding.ASCII.GetString(encoded);
}

I get ?Y09?\u001f???}?)?v?? as the result. If I base64 the byte array first, the output is x1kwOeUf3fmUfdQpknbjkw==, the same as PHP. Unfortunately the PHP code uses raw output, so I need make sure those are the same.

Interestingly enough the individual bytes, using PHP ord and inspecting the c# byte array, are the same. The output however, even though it looks similar, isn't.

I've tried all the paddingmodes in C# but none of them gave the exact same rsult as PHP.

Is there a way to make sure that both C# and PHP give the same output?

uvr
  • 515
  • 4
  • 12
  • You use different crypto algorithms. In PHP you use AES and in C# you use Rijndael. – TheTanic May 17 '21 at 08:08
  • 1
    @TheTanic AES is a subset of the Rijndael, and OP is getting the same binary result. – ProgrammingLlama May 17 '21 at 08:09
  • 1
    If the base64 encoded strings of the byte arrays are the same, then I can't see how the un-encoded byte arrays can be different. – Hans Kilian May 17 '21 at 08:10
  • @Llama My bad. You are right – TheTanic May 17 '21 at 08:11
  • 4
    Your flag is OPENSSL_RAW_DATA, which suggests it's just returning the data as binary and that's being interpreted as text using whatever encoding is default in PHP. In C# you're explicitly using ASCII. Note that using ASCII is not good option for encoding arbitrary binary data as it isn't round-trippable (i.e. the result of string -> binary likely won't be the same as the initial binary that created the string). [Example](https://rextester.com/KAJ75707) – ProgrammingLlama May 17 '21 at 08:13
  • Any suggestions as to how I should get the string from the bytes in C# then? I can use UTF8 encoding, but that gives �Y09�\u001f���}�)�v�. – user6588597 May 17 '21 at 08:30
  • 2
    If you want to store a ciphertext in a string, you should use a binary-to-text encoding like Base64, charset encodings like UTF-8 generally corrupt the data, s. [this post](https://stackoverflow.com/a/9098905/9014097) – Topaco May 17 '21 at 08:47
  • The php application does use a base64 string eventually, but first it adds a salt string to the result from the encryption $endresult = base64_encode("Salt123" . $encrypt); In C# I need the same result from the encryption. If I use the base64 result from the encryption and then concatenate the base64 salt the result will not be a valid base64 string. – user6588597 May 17 '21 at 12:16

0 Answers0