I have an encrypted file (AES Symmetric encryption).For backup purposes and to save disk space, Can I compress (lossless) the file without worrying about messing up the decryption? If so, can you recommend some good compression programs for this purpose?
Compress an encrypted file
backupcompressionencryption
Related Solutions
This is a facinating problem. I've been in similar situations where I was required to solve a problem the wrong way. That being said, I'm not aware of a general purpose crypto module that will let you decrypt static files as they are served. I searched for several hours but I wasn't able to find anything. That's not surprising as it seems like a fairly specialized problem.
Nonetheless, I see several options.
- Write your own C module and implement it as a filter handler.
- Use mod_ext_filter and an external executable1 to decrypt the file.
- If all of the files have a specific extension, add a handler to call a CGI script to decrypt and serve the file. For example,
Action decrypt /cgi-bin/decrypt.pl
andAddHandler decrypt .html
will cause all requests for files ending in .html to call /cgi-bin/decrypt.pl which will need to read, decrypt, and serve the file. See http://httpd.apache.org/docs/current/handler.html#examples. - Use mod_php and mod_rewrite to transparently decrypt and serve static files of any type from one or more specific locations.
I took the liberty of implementing a proof of concept of the fourth option which I'll share here. I chose PHP in this instance because it's ubiquitous, it usually contains the necessary crypto functions, and it's fast since it's an Apache module written in C.
Assuming that all encrypted files are stored in a directory called data
and are encrypted using the same key, I created the directory in my document root then created an encrypted file using OpenSSL.
cd /var/www
mkdir data
echo 'This is my plaintext content.' | openssl aes-256-cbc -a -k secret -out data/test.txt
Then I created decrypt.php
in my document root with the following content:
<?php
# NOTE: This is proof-of-concept code. You should audit it for security before
# using it in a production environment.
# The key to use to decrypt the files
$key = 'secret';
$filename = $_SERVER["DOCUMENT_ROOT"] . htmlspecialchars($_SERVER['REQUEST_URI']);
$data = file_get_contents($filename);
$plaintext = decrypt($key, $data);
# Determine the MIME type of the decrypted content
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$content_type = finfo_buffer($finfo, $plaintext);
finfo_close($finfo);
header("Content-type: $content_type");
print $plaintext;
function decrypt($password, $encrypted_data) {
$encrypted_data = base64_decode($encrypted_data);
$salt = substr($encrypted_data, 8, 8);
$cyphertext = substr($encrypted_data, 16);
$password = $password . $salt;
$md5_hash = array();
$md5_hash[0] = md5($password, true);
$result = $md5_hash[0];
$rounds = 3;
for ($i = 1; $i < $rounds; $i++) {
$md5_hash[$i] = md5($md5_hash[$i - 1] . $password, true);
$result .= $md5_hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
return openssl_decrypt($cyphertext, 'aes-256-cbc', $key, true, $iv);
}
?>
If your content is not base64 encoded then you can remove the first line in the decrypt function which reads $encrypted_data = base64_decode($encrypted_data);
.
Finally, in my Apache configuration I added the following entries:
<directory /var/www/>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^data/ /decrypt.php [L]
</directory>
Now any file requested from http://www.example.com/data
will be decrypted and served, including from within subdirectories. Since the rewrite condition is limiting the rewrite to files, directory indexes still work. I have the PHP script determine the MIME type of the decrypted content and update the header accordingly so I can serve encrypted images, documents, web pages, and so on.
This probably won't be as fast as a custom Apache module, but it should be close. If you're going to be serving a lot of encrypted content and performance is an issue, you might be able to speed things up a little bit by installing the Alternative PHP Cache so the PHP page doesn't have to be compiled for every request.
Please keep in mind that you may need to increase the settings for PHP's memory usage if you are decrypting large files.
1 You said that you feel like this option is a hack. Why? Although the result may be slow, mod_ext_filter is a supported core module and will do the job once you write a filter program for it to use.
2 I borrowed the decrypt() function from http://us3.php.net/manual/en/function.openssl-decrypt.php#107210.
Now that you've figured out why they're compressed, you can uncompress them by running the following from a command prompt on the root drive:
compact /u /s
http://technet.microsoft.com/en-us/library/bb490884.aspx
In addition, when running the Disk Cleanup utility, the option to compress old files is just that, an option. If you don't want to compress old files as part of the cleanup then unselect the check box.
This is the correct command line for uncompressing the entire C drive:
compact /u /s:C:\ /i *.*
Run that from the command line and wait....
Best Answer
You can compress it, but it is unlikely to save much disk space. By its nature, encryption rarely leaves a file compressible by much.
Try it for yourself to see if there is any file size savings.
One data point:
test.log
is the original, andtest.log.bz2
andtest.log.gz
are simply compressed with bzip2 and gzip, respectively.If I encrypt it (
gpg --symmetric --cipher-algo AES --output test-AES.gpg test.log
) the encrypted file (test-AES.gpg
) is slightly larger than compressed versions. Compressing the encrypted file actually adds a little size (test-AES.gpg.bz2
andtest-AES.gpg.gz
).Compressing first then encrypting does show some savings (
test-bz2-AES.gpg
andtest-gz-AES.gpg
), especially with bzip2.Of course, your experience may differ given different encryption software and/or different compression software.
You should consider whether the file size savings you get simply via encryption is enough, or if compressing then encrypting is worth the extra step in the process.