securitycakephpencryptionencodingrijndael

Encrypting/decrypting some file types with Rijndael 256 (CakePHP Security library) garbles contents


I am using CakePHP's Security::rijndael() function to encrypt and decrypt text and files. I previously wrote some code using mcrypt directly, which worked in the same way, but then I found Security::rijndael and realised I had reinvented the wheel. So the problem I have happens either way.

If I encrypt a string, or a text file, or a PDF document, the code below works perfectly and I get the correct decrypted string/file. However, if I try encrypting a .doc, .docx or an image file, the decrypted file is garbled.

Here's the code that does the encrypting/decrypting

public static function encrypt($plainText, $key) {
    $plainText = base64_encode($plainText);

    //Hash key to ensure it is long enough
    $hashedKey = Security::hash($key);
    $cipherText = Security::rijndael($plainText, $hashedKey, 'encrypt');
    return base64_encode($cipherText);
}

public static function decrypt($cipherText, $key) {
    $cipherText = base64_decode($cipherText);

    $hashedKey = Security::hash($key);
    $plainText = Security::rijndael($cipherText, $hashedKey, 'decrypt');
    return base64_decode($plainText);
}

...and this code actually presents the file to the user (I've edited the code to keep it simple):

public function download($id){
    App::uses('File', 'Utility');
    $key = $this->User->getDocumentKey($id);
    $file = new File('my_encrypted_file.docx');
    $encrypted = $file->read();
    $decrypted = Encrypt::decrypt($encrypted, $key);

    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Content-Disposition: attachment; filename="my_decrypted_file.docx"');
    echo $decrypted;
    die();
}

Update - it appears that the encryption is a red herring, as the file is garbled even without encrypting and decrypting it! The following produces exactly the same broken file:

        header('Content-Disposition: attachment; filename="test.docx"');
        $file = new File($this->data['Model']['file']['tmp_name']);
        echo $file->read();
        die();

Solution

  • Well, I was barking up the wrong tree.

    For whatever reason (whitespace at the start of some PHP file maybe?), adding ob_clean(); immediately after sending the headers, has fixed the problem.