-
Portable File Encryption with PHP and Java
Posted on June 9th, 2010 No commentsI had a client project come up recently that required HIPAA compliance which meant encryption was going to be involved. The goal was to collect patient information and then store it in encrypted pdf files so they could be downloaded, decrypted, and entered into another system. It did not sound like the most efficient system however that was the spec I was given. I had never worked with symmetric encryption before although it has always been a topic of interest so I jumped at the opportunity to expand my knowledge of cryptography.
The first few days of my attempt to implement this process was spent doing research into some cryptography fundamentals and sifting through documentation on AES and php’s mcrypt module as well as evaluating third party crypto utilities. My initial understanding gave me the wrong impression that a file encrypted with one utility could be easily decrypted with another utility using the same algorithm. This assumption lead to endless frustration as I attempted to decrypt files that I had encrypted with php/mcrypt with no success. Eventually I realized that file encryption worked much the same way media files worked (actual media data encoded with a codec and stored in a container format). Now that I understood that, I was able to come up with a workable end to end solution.
My first attempt was to implement the file format used by AESCrypt described here. I liked this utility because it was cross platform and integrated into the file manager for Windows (This translated to minimal learning curve for the client). My inexperience with pack() and creating binary file formats lead me to fail in this endeavor although I would like to come back to this as I think the php world could benefit from a AESCrypt module. The solution that eventually succeeded was to forego the container format all together and just write a custom decrypter that expected raw encrypted data.
I was pleased to learn that java had a readily available crypto module that was compatible with mcrypt’s AES implementation so it seemed the natural solution to write a Swing application that powered the custom decrypter. The application I ended up writing supported decrypting single files, or entire folders full of encrypted files of any type. Here’s the meat of my solution.
The server side part of the solution was a class that encrypted a pdf that had been generated by a parent class:
-
-
<?php
-
-
class Form_Submission_EncryptedPdf_Adapter extends Form_Submission_Pdf_Adapter {
-
-
protected function pkcs5_unpad($text){
-
}
-
-
protected function pkcs5_pad($text, $blocksize) {
-
}
-
-
/* parent class creates pdf file */
-
parent::output($pOptions);
-
-
$source_filepath = FP::get(‘docroot’) . FP::get(‘baseUrl’) . ‘/pdfs/’ . $this->_filename;
-
$encrypted_filepath = $source_filepath . ‘.enc’;
-
-
-
-
$iv = ’1234567812345678′;
-
-
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
-
$pdf_data = $this->pkcs5_pad($pdf_data, $size);
-
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, ”, MCRYPT_MODE_CBC, ”);
-
mcrypt_generic_init($td, $key, $iv);
-
$encrypted_data = mcrypt_generic($td, $pdf_data);
-
mcrypt_generic_deinit($td);
-
mcrypt_module_close($td);
-
-
file_put_contents($encrypted_filepath, $encrypted_data);
-
-
}
-
}
-
-
?>
-
There’s nothing particularly special happening here. I read in the binary data of the generated pdf file. Specify a 128 bit initialization vector and read in a 128 bit key from a file that leaves above the document root of the server (The IV could be read in from a dynamic source as well allowing it to be changed by the client but I chose to hard code it for simplicity). The binary data is than encrypted with the Rijndael 128 algorithm and then stored in another file with the ‘enc’ extension. When i’m done i make sure to delete the original pdf. Now the client can periodically log into the server and download the encrypted pdfs for processing.
On the client end, the java/swing application wraps around the decrypter class which looks like this:
-
-
import java.io.*;
-
import java.security.InvalidAlgorithmParameterException;
-
import java.security.InvalidKeyException;
-
import java.security.NoSuchAlgorithmException;
-
-
import javax.crypto.Cipher;
-
import javax.crypto.CipherInputStream;
-
import javax.crypto.NoSuchPaddingException;
-
import javax.crypto.spec.IvParameterSpec;
-
import javax.crypto.spec.SecretKeySpec;
-
-
public class AESDecrypter {
-
-
protected Cipher cipher = null;
-
-
this.key = pKey;
-
this.iv = pIV;
-
-
try {
-
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
-
} catch (javax.crypto.NoSuchPaddingException x2){
-
}
-
}
-
-
-
try {
-
SecretKeySpec keySpec = new SecretKeySpec(this.key.getBytes(), "AES");
-
IvParameterSpec ivSpec = new IvParameterSpec(this.iv.getBytes());
-
this.cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
-
}
-
-
try {
-
CipherInputStream cis = new CipherInputStream(fis, this.cipher);
-
-
String decryptedFileName = null;
-
-
if (sourceFileName.endsWith(".enc")){
-
decryptedFileName = sourceFileName.substring(0, sourceFileName.lastIndexOf(‘.’)) ;
-
} else {
-
return false;
-
}
-
-
-
-
-
byte[] b = new byte[32768];
-
int i;
-
-
while ((i = cis.read(b)) != -1) {
-
fos.write(b, 0, i);
-
}
-
-
fos.flush();
-
fos.close();
-
cis.close();
-
fis.close();
-
return false;
-
}
-
return true;
-
}
-
}
-
The class is instantiated with the key and iv which are read in dynamically and then is passed a File object through the decryptFile() method which does the actual work of decrypting the file. The implementation reads in the encrypted binary data and decrypts it with a CipherInputStream which is configured with the same algorithm, key, and initialization vector as our php class was. The method will only decrypt the file if it has a file extension of .enc which prevents files that are not encrypted or have already been decrypted from being processed again (essentially turning them to garbage).
It’s not a very complex solution however I struggled to find good information on this type of problem. It seems every symmetric encryption solution is a custom solution in itself so hopefully this will save other developers the huge frustration I experienced when learning this.
Cryptography, Java, PHP Cryptography, decryption, encryption, Java, mcrypt, php, security, swingRelated Topics
Leave a reply
-


