Protecting Uploaded Files with PGP in Java

7 June 2010

I had to build a little website feature to allow clients to upload files. That’s no problem with Apache Tomcat and Apache’s Commons File Upload. The requirement that made this interesting was to encrypt files on receipt so that if the webserver machine gets compromised, the files are difficult to read.

The Commons FileUpload API allows catching the inbound upload stream from the remote client, so it’s possible to do some encryption without ever storing the file in the clear on the local system. However, I didn’t want to use a symmetric key like a simple password (for example, no password-protected zip archive). A symmetric key means the password have to be in a config file on the web server, or I would have to type the password in at each reboot. Even tho the machine is on a UPS and unlikely to restart on its own, a manual intervention at each restart didn’t look attractive. So I looked for a solution using asymmetric aka public-key cryptography. The idea is to encrypt the inbound stream using a public key on the server, move the file to a secure place, then decrypt the file using a private key on the secure machine. Because the private key is never on the webserver, the webserver cannot decrypt the files it creates, and neither can an attacker (at least not easily). That was the theory anyhow!

Well I’m not a crypto guy, and didn’t want to make the noob mistake of inventing something even less secure than cleartext. I searched for examples and stumbled on Java’s javax.crypto.CipherOutputStream. But that seems designed only for symmetric keys. After that I found many, many references to the Bouncy Castle stuff (http://bouncycastle.org/). I was a little worried about using code from people who would choose that sort of name, and their Javadoc didn’t give me any confidence either. But they provide great examples and a nice implementation of Open PGP (RFC 4880). I extended one of their file-encryption classes to a stream-encryption class, added in a helper method to generate the public and private keys, and had a working solution.

My solution relies heavily on the BouncyCastle provider and openPGP libraries. Below is the result, just a single class, for encrypting and decrypting data read from a jave InputStream and written to a java OutputStream. To use it, you have to choose a user identity (identifies the public key) and a pass phrase (protects the private key). The class also compresses the input during encryption, and decompresses again on decryption, because I was required to accept files up to many tens of megabytes. Nearly half of the class is code to allow invocation from the command line for testing; the core code is actually not that large. I know, accepting a password on the command line isn’t secure on a multi-user system. Making this class work on your system’s JRE may require fussing with policy files that control what key size can be used by java. I have never installed any special policies and whatever reason I didn’t hit this issue.

If this helps you please drop me a line.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store