Search code examples
c#phpencryptionbouncycastlesubstr

Converting php array substr to c#


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 = "F5UgsDQddWGdgjdd";
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt(
        $plaintext, 
        $cipher,   
        $key,
        0, 
        $iv
    );
    $ciphertext = base64_encode($iv.$ciphertext);
    echo $ciphertext."\n";
?>

in php, the following code works:

<?php
    $cipher = "AES-128-CTR";
    $key = "F5UgsDQddWGdgjdd";    
    $ciphertext = base64_decode( $_POST['ciphertext'] );
    $iv = substr($ciphertext, 0, 16);
    $content = substr($ciphertext, 16);
    $text = openssl_decrypt(
        $content, 
        $cipher,
        $key,  
        0, 
        $iv
      );
    
    echo $text."\n";
?>

However, when I do the following in C# the result is just gibberish.

public string Test(string cipherTextStr)
{
    var cipherText = Convert.FromBase64String(cipherTextStr);
    var iv = cipherText.Take(16).ToArray();
    var content = cipherText.Skip(16).ToArray();

    byte[] keyBytes = Encoding.UTF8.GetBytes("F5UgsDQddWGdgjdd");

    IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");

    cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytes), iv));

    byte[] decryptedBytes = cipher.DoFinal(content);

    return Encoding.UTF8.GetString(decryptedBytes);

}

The same C# code works if I don't have to separate iv and content which makes me think that I'm either doing the initial FromBase64String wrong or the take and skip from the byte array.


Solution

  • When you pass $option = 0 to openssl_encrypt, the input data is PKCS#7 padded and the output data is base64 encoded. If you don't want any padding and base64 encoded output, use this option value:

    $ciphertext = openssl_encrypt(
        $plaintext, 
        $cipher,   
        $key,
        OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, 
        $iv
    );
    

    Update: modify C#, manually decode the encrypted data.

    content = Convert.FromBase64String(Encoding.UTF8.GetString(content));