title: Encrypting files with php/mcrypt is corrupting docx (and other Microsoft Office 2007) files but others are fine
body: <p>I'm working with a CodeIgniter application to encrypt uploaded files then decrypt them when downloaded so they can be stored safely (alongside other security measures). This is all working fine, apart from docx (and other Microsoft Office 2007+) files. When these are downloaded they are successfully decrypted but Office detects them as corrupt. These can be repaired, so they're not totally corrupted, but something has changed in the file from the original version which is making Office see them as corrupt. As I mentioned, this doesn't seem to be happening to any other file types (that I have noticed). The docx files are also slightly different in size (only a matter of bytes), whereas other types are not.</p>
  <p>To encrypt, I upload the file, read the contents into a string with file_get_contents(), then run the string through CodeIgniter's encode() in the encrypt library then save the file back to disk, deleting the original:</p>
  <pre><code>function mcrypt_encode($data, $key)
  {
      $init_size = mcrypt_get_iv_size($this-&gt;_get_cipher(), $this-&gt;_get_mode());
      $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
      return $this-&gt;_add_cipher_noise($init_vect.mcrypt_encrypt($this-&gt;_get_cipher(), $key, $data, $this-&gt;_get_mode(), $init_vect), $key);
  }
  </code></pre>
  <p>and to decode:</p>
  <pre><code>function mcrypt_decode($data, $key)
  {
      $data = $this-&gt;_remove_cipher_noise($data, $key);
      $init_size = mcrypt_get_iv_size($this-&gt;_get_cipher(), $this-&gt;_get_mode());
  
      if ($init_size &gt; strlen($data))
      {
          return FALSE;
      }
  
      $init_vect = substr($data, 0, $init_size);
      $data = substr($data, $init_size);
      return rtrim(mcrypt_decrypt($this-&gt;_get_cipher(), $key, $data, $this-&gt;_get_mode(), $init_vect), &quot;\0&quot;);
  }
  </code></pre>
  <p>Then run the decoded string through CodeIgniter's <a href="http://codeigniter.com/user_guide/helpers/download_helper.html" rel="nofollow noreferrer">force_download()</a></p>
  <p>The default cipher is MCRYPT_RIJNDAEL_256 and mode is MCRYPT_MODE_CBC. Mcrypt is enabled on my server along with MCRYPT_RIJNDAEL_256.</p>
  <p>If anyone could point me in the right direction as to why this might be happening it would be greatly appreciated.</p>
  <p>Many thanks</p>