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();
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.