CSecurityManager not decrypting properly on docx

Hi!

I am using CSecurityManager to encrypt-decrypt files that i store in a MySQL database. It works fine on most files EXCEPT for docx files. For docx files, the encryption and database storage works, However, when i retrieve the file and decrypt, the file turns out corrupted. Any ideas on this?

Here’s a snippet of my code:

encryption:




        public function beforeSave(){

		//set the encryption key

		$securityManager =  new CSecurityManager;

		$securityManager->setEncryptionKey(Yii::app()->params['fileEncryptKey']);		

		

		if($file=CUploadedFile::getInstance($this,'uploadedFile')){

			$this->fileName = $file->name;

			$this->fileType = $file->type;

			$this->fileSize = $file->size;

						

			$this->fileContent = $securityManager->encrypt(file_get_contents($file->tempName));			

		}

		return parent::beforeSave();

	}



decryption (used in download.php file):




$securityManager =  new CSecurityManager;

$securityManager->setEncryptionKey(Yii::app()->params['fileEncryptKey']);		


$fileContent = $securityManager->decrypt($model->fileContent);


return Yii::app()->getRequest()->sendFile($model->fileName, $fileContent);



Thanks in advance!

-Benjie

Try to set the correct header too, i think this is causing problems.

Also, take a look here: http://www.yiiframework.com/forum/index.php/topic/28973-file-download-issue/ it will help you.

Maybe its because the sendFile() method (used without mime type parameter) uses the mime type defined in the mimeTypes.php (in sendFile the CFileHelper::getMimeTypeByExtension() method). In the mimeTypes.php file there is no entry defined for docx so it sets the mime type to text/plain in sendFile().

I don’t be sure but one possible solution in my opinion could be setting the correct mime type as third parameter in the sendFile() call.

Maybe it should be added as feature/bug request to add this and maybe other missing mime types to the mimeTypes.php file.

Update: I submitted this as new issue 3210 on code.google.com

Hi twisted,

I’m still getting the same results (Works on every file exept for docx, xlsx,…). I replaced my


 Yii::app()->getRequest()->sendFile($model->fileName, $fileContent,$model->fileType);

method with the “traditional” way, as you call it ;), using manual header settings. Here’s how i did it:




	public function actionDownload($id){		

		

		$model = $this->loadModel($id);

		

		$securityManager =  new CSecurityManager;

		$securityManager->setEncryptionKey(Yii::app()->params['fileEncryptKey']);		

		

		$fileContent = $securityManager->decrypt($model->fileContent);

		

                header('Content-Description: File Transfer');

                header('Content-Type: '.$model->fileType);

                header('Content-Disposition: attachment; filename='.$model->fileName);

                header('Content-Transfer-Encoding: binary');

                header('Expires: 0');

                header('Cache-Control: must-revalidate');

                header('Pragma: public');

                header('Content-Length: ' . $model->fileSize);

                ob_clean();

                flush();

                echo $fileContent;

	}



In the MySql database, the fileType saved for the docx file is


application/vnd.openxmlformats-officedocument.wordprocessingml.document

, which should be the correct MIME-type for docx files. Did I miss out on anything?

-Benjie

What you mean with corrupted? Totally unreadable? Maybe encryption/decryption does not work correctly? What Yii version do you use?

Yep, totally unreadable. The encryption/decryption works well on other filetypes, though. The problem happens only with docx, xlsx,…

What if you try to base64_encode() the file contents before encrypt, then when you get the content from database, decrypt it, then base64_decode() and see if it works that way.

Finally! That did the trick. Must be because CSecurityManager uses string-based encryption? Thanks twisted!

For encryption, i used:


$this->fileContent = $securityManager->encrypt(base64_encode(file_get_contents($file->tempName)));

…and for decryption:


$fileContent = base64_decode($securityManager->decrypt($model->fileContent));