Question

I have the following code in C#

string s = "hellowld";
byte[] bytes = new UnicodeEncoding().GetBytes(s);
FileStream stream = new FileStream(inputFile, FileMode.Open);
RijndaelManaged managed = new RijndaelManaged();
CryptoStream stream2 = new CryptoStream(stream, managed.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
FileStream stream3 = new FileStream(outputFile, FileMode.Create);
try
{
    int num;
    while ((num = stream2.ReadByte()) != -1)
    {
        stream3.WriteByte((byte) num);
    }
 [....]

This code snippet decrypts a certain file and outputs a decrypted version. In the CreateDecryptor method from RijndaelManaged im using the password as KEY and also as IV.

I found some code here on stackoverflow for PHP but if I try to give the key and iv the same Array of Bytes like in C# nothing happens.

$Pass = "hellowld";
$Clear = file_get_contents('./file.dat', FILE_USE_INCLUDE_PATH);

$bytePass=array();
$i = 0;
foreach (str_split($Pass) as $value) {
    $bytePass[$i]=ord($value);
    $i++;
}

echo decryptAES($Clear,$bytePass,$bytePass);

function decryptAES($content,$iv, $key,$aes) {

// Setzt den Algorithmus
switch ($aes) {
    case 128:
       $rijndael = 'rijndael-128';
       break;
    case 192:
       $rijndael = 'rijndael-192';
       break;
    default:
       $rijndael = 'rijndael-256';
}

// Setzt den Verschlüsselungsalgorithmus
// und setzt den Output Feedback (OFB) Modus
$cp = mcrypt_module_open($rijndael, '', 'ofb', '');

 // Ermittelt die Anzahl der Bits, welche die Schlüssellänge des Keys festlegen
$ks = mcrypt_enc_get_key_size($cp);

// Erstellt den Schlüssel, der für die Verschlüsselung genutzt wird
$key = substr(md5($key), 0, $ks);

// Initialisiert die Verschlüsselung
mcrypt_generic_init($cp, $key, $iv);

// Entschlüsselt die Daten
$decrypted = mdecrypt_generic($cp, $content);

// Beendet die Verschlüsselung
mcrypt_generic_deinit($cp);

// Schließt das Modul
mcrypt_module_close($cp);

return trim($decrypted);

}

I really need some help how to properly create the code in PHP. Its not necessary that I output a file in PHP, a string would be sufficient.

UPDATE: The default C# RijndaelManaged cipher method is AES-128-CBC. I changed my PHP code to that mcrypt module (default C# cipher method)

UPDATE 2: I did manage to create a Java Decryptor which lead me to another thing. PHP has to use the PKCS7 Padding.

Was it helpful?

Solution

Your C# code doesn't really look secure, so if you can change it, see below for some tips. Here is your given PHP code modified to look like it could be equivalent to the C# code given.

function decryptAES128CBC($content,$iv, $key) {

    // AES is Rijndael-128
    $rijndael = 'rijndael-128';

    // key size is 128 bit = 16 bytes
    $ks = 16;

    // CBC mode, not OFB
    $cp = mcrypt_module_open($rijndael, '', 'cbc', '');

    // pad key and IV by zeros (this is not a good idea)
    $key = str_pad($key, $ks, "\0");
    $iv = str_pad($key, $iv, "\0");

    // initialize the decryptor with key and IV
    mcrypt_generic_init($cp, $key, $iv);

    // the actual work
    $decrypted = mdecrypt_generic($cp, $content);

    // clean up
    mcrypt_generic_deinit($cp);
    mcrypt_module_close($cp);

    // remove padding, see below
    return unpad($decrypted);
}

The last unpad is there to remove the padding which was likely appended by the encryption function to enlarge the message size to a full number of blocks. The default padding used by RijndaelManaged is PKCS7-padding, which appends a number of bytes (between 1 to 16), each of which being equal to the number of bytes appended. In a real implementation, you would check after decryption that the padding is valid (i.e. that all these bytes have the same value), but for "quick and dirty" you can simply use something which checks the last byte and removes that many bytes. See the comments to mcrypt_decrypt for an example.

If you can change your C# code:

  • Note that it is usually not a good idea to use a fixed value (per key) as an initialization vector, and using the key itself as initialization vector is not good, either. Use a random initialization vector (sent together with the message), or see the next point.

  • Also, you normally don't want to use a (rather short) password directly as a key, but instead use a longer passphrase, and hash it with a salt (included with in the message) to derive the key. If you do this, you can also derive the initialization vector from the same two pieces of data (but in a way that they'll be different, using a key derivation function). To avoid brute-forcing your password from the encrypted file, use a slow hash function here (PBKDF-2 or bcrypt).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top