Public Key Encryption and PDF

Encrypting a PDF for individual users

A PDF can be protected in a number of ways. Most of the time it's sufficient to add a password - anyone who knows the PDF password can open it, and (if the document author allowed it) can print, copy text and so on.

However if you want to allow only some users to print, this requires a different aproach. The simplest approach is to use Public Key Cryptography. Anyone familiar with public key crypto may raise an eyebrow at the use of the word "simple" there, but our API hides a lot of the complexity. Read on...

Generating a Key

The first thing Public Key cryptography requires is a key pair. This consists of one public key and one private one - the private you keep to yourself for decryption, and the public one you give out, usually in the form of an X.509 Certificate.

The first way to do this is to use the Java keytool program. At it's simplest you could do something like the following:

keytool -genkeypair -alias jamesbond
What is your first and last name?
[Unknown]:  James Bond
What is the name of your organizational unit?
[Unknown]:  
What is the name of your organization?
[Unknown]:  MI6
What is the name of your City or Locality?
[Unknown]:  London
What is the name of your State or Province?
[Unknown]:    
What is the two-letter country code for this unit?
[Unknown]:  GB
Is CN=James Bond, OU=Unknown, O=MI6, L=London, ST=Unknown, C=GB correct?
[no]: yes Enter key password for jamesbond (RETURN if same as keystore password):
That will create a new keypair in the Java Keystore - you now need to export the X.509 certificate for that key, which you can do with the command
keytool -exportcert -alias jamesbond -file jamesbond.cer

Alternatively, our PDF viewer can easily create and export a new key. The clip below shows how to create a new keypair and export the X.509 certificate to a file.

You can also do the same operation in Acrobat. Here's how to create a new identity and export the certificate file in Acrobat 9.

Encrypting a PDF with a public key

Now you have the X.509 certificate file containing the details of the public key. To encrypt a PDF so that it can be opened by the owner of that key you'd need something like the following code:
import org.faceless.pdf2.*;
import java.security.*;
import java.security.cert.*;
import java.io.*;

public void encrypt(PDF pdf, String file) throws Exception {
	CertificateFactory cf =
	CertificateFactory.getInstance("X.509");
	InputStream in = new FileInputStream(file);
	X509Certificate cert = (X509Certificate)
	 cf.generateCertificate(in);
	in.close();
	 
	PublicKeyEncryptionHandler handler =
	   new PublicKeyEncryptionHandler(5);
	handler.addRecipient(cert,
	   StandardEncryptionHandler.PRINT_HIGHRES,
	   StandardEncryptionHandler.CHANGE_ALL,
	   StandardEncryptionHandler.EXTRACT_ALL);
	   
	pdf.setEncryptionHandler(handler);
}

Note we're adding a recipient to the handler - the PublicKeyEncryptionHandler can encrypt a document for more than one recipient, with different permissions if required. So it's quite possible to create a document which allows one recipient to print it but not another. Just call addRecipient once for each certificate you are encrypting for.

Opening the PDF

Opening the PDF in question couldn't be easier, in both Acrobat and our PDF Viewer. Simply open the PDF as normal - if the user has one or more private keys in their keystore which can decrypt the PDF they will be prompted to select one.

If you want to open the PDF using our API, this is easily done too. If you know which key you're going to use, then you can simply specify it like so:

EncryptionHandler handler = new PublicKeyEncryptionHandler(keystore, "myalias", "password".toCharArray());
PDF pdf = new PDF(new PDFReader(new File("file.pdf"), handler));
If you want to choose the key dynamically, then you can override the chooseRecipient method on the PublicKeyEncryptionHandler class. This is given a list of recipients the PDF was encrypted for, and you can choose an appropriate key and call setDecryptionKey to decrypt the PDF. The viewer has an example of this called PublicKeyPromptEncryptionHandler.java, and the source code for that is included with the viewer.

 

Summary

Public Key encryption has a well-deserved reputation for complexity, but most of it relates to key management. For situations where you can guide the user through creating and exporting their digital identity, public key encryption is a very effective way of controlling document distribution. If you're encrypting for multiple users you'll need to remember that each addition recipient adds anywhere between 500B and 2KB to the file, depending on the complexity of the certificate and the key length.