Search code examples
c#encryptionopensslbouncycastlephp-openssl

Encoding problem in C# decrypting in bouncycastle from openssl


I'm trying to decrypt in c#, using bouncycastle, the result of the following php code:

<?php
    $plaintext = 'The quick brown fox jumps over the lazy dog';
    $cipher = "AES-128-CTR";
    $key = "F5UgsDQddWGdgjddJtNgg6xE3V9uwaCR";
    if (in_array($cipher, openssl_get_cipher_methods()))
    {
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = '2782614358578542';
        $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
        echo $ciphertext."\n";
    }
?>

My c# code is as follows:

public string Decrypt(string toDecrypt, string keyStr, string ivStr)
{
    byte[] inputBytes = Convert.FromBase64String(toDecrypt);
    byte[] keyBytes = Encoding.UTF8.GetBytes(keyStr);
    byte[] iv = Encoding.UTF8.GetBytes(ivStr);
    IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/PKCS7PADDING");
    cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytes), iv));
    byte[] decryptedBytes = cipher.DoFinal(inputBytes);
    return Encoding.UTF8.GetString(decryptedBytes);
}

The php code returns

7/q61uOzeC4iycFIMrjvh01zvjOuCtnX8eWob8MAA5kIfMOIx915ctBIyw==

But when I make in C# the following call

Decrypt("7/q61uOzeC4iycFIMrjvh01zvjOuCtnX8eWob8MAA5kIfMOIx915ctBIyw==", "F5UgsDQddWGdgjddJtNgg6xE3V9uwaCR", "2782614358578542");

I get the following gibberish:

���yF�l����c:�-��7K�(�,�X�.[�W"�ܜ��J�

Which makes me think that I'm missing or doing something wrong with the encoding but I can't seem to figure it out.


Solution

  • AES-128 uses a 16 bytes key. In the PHP code, however, a 32 bytes key is used, which PHP implicitly truncates by considering only the first 16 bytes.

    So the fix is to shorten the key in the C# code accordingly, i.e. use F5UgsDQddWGdgjdd.
    Alternatively, change the AES variant in the PHP code to AES-256 (aes-256-ctr), which results in the ciphertext Tw05j9QDfaBK7zbyt9jine8xWqnzNB2Pim7rtv7gDba2TsE7ejvvjP5YKA==.

    Additionally, in the C# code, apply AES/CTR/NoPadding, since CTR is a stream cipher mode that does not require padding, which is why padding is implicitly disabled in the PHP code.


    Note that for security reasons, key/IV pairs must not be reused, especially for CTR. Therefore, for a fixed key, a static IV must not be applied, but a random one (which is passed to the decrypting side together with the ciphertext, usually concatenated).