org.faceless.pdf2
Class PublicKeyEncryptionHandler

java.lang.Object
  extended by org.faceless.pdf2.EncryptionHandler
      extended by org.faceless.pdf2.PublicKeyEncryptionHandler
All Implemented Interfaces:
Cloneable
Direct Known Subclasses:
PublicKeyPromptEncryptionHandler

public class PublicKeyEncryptionHandler
extends EncryptionHandler

The PublicKeyEncryptionHandler can be used to encrypt and decrypt documents using public/private key Encryption, so documents can only be opened by certain individuals. It requires Java 1.4 or later, as it uses the javax.crypto package. The resulting documents can be opened in Acrobat 5 or later with the appropriate private key.

We're going to assume you're familiar with public key cryptography if you're using this class, and instead jump straight in and give a couple of examples showing how to decrypt and encrypt a document. First, some important notes:

  1. This handler only works with Java 1.4 or above
  2. You must download and install the unrestricted policy files for the Sun JCE. You can download these from the same place you download Java - for Suns current 1.4.2 release, they are available at http://java.sun.com/j2se/1.4.2/download.html. If they're not installed, you'll see an exception like: java.lang.SecurityException: Unsupported keysize or algorithm parameters
  3. You will need a JCE provider that implements the ciphers you need. Any JCE provider should work, including the default Sun JCE provider and the Bouncy Castle provider (available at http://www.bouncycastle.org).

Once these steps are done, to encrypt a document you need the X.509 certificate of the person you're sending it to. Typically you'd get this from a KeyStore, as in this example:

 KeyStore keystore = KeyStore.getInstance("PKCS12");
 keystore.load(new FileInputStream("keystore.p12"), "password".toCharArray());
 X509Certificate cert = (X509Certificate)keystore.getCertificate("john");

 PublicKeyEncryptionHandler handler = new PublicKeyEncryptionHandler(5);
 handler.addRecipient(cert, StandardEncryptionHandler.PRINT_HIGHRES,
                            StandardEncryptionHandler.CHANGE_ALL,
                            StandardEncryptionHandler.EXTRACT_ALL);

 pdf.setEncryptionHandler(handler);
 
Other ways to get a certificate include using the FormSignature.loadPKCS7KeyStore(java.io.InputStream) method to load your X.509 certificates from a PKCS#7 object, or the CertificateFactory class to load the certificate from .cer files exported by Acrobat:

 FileInputStream fis = new FileInputStream("certificate.cer");
 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
 

To decrypt a document, you will need a KeyStore containing a private key that matches the public key used to encrypt the document. Typically this will be done like so:

 KeyStore keystore = KeyStore.getInstance("PKCS12");
 keystore.load(new FileInputStream("keystore.p12"), "storepassword".toCharArray());
 EncryptionHandler handler = new PublicKeyEncryptionHandler(keystore,
                                                            null,
                                                            "keypassword".toCharArray());

 PDF pdf = new PDF(new PDFReader(new File("encrypted.pdf"), handler));
 

Since:
2.2.5
See Also:
FormSignature, PDFReader.PDFReader(InputStream,EncryptionHandler), StandardEncryptionHandler

Constructor Summary
PublicKeyEncryptionHandler()
          Create a new PublicKeyEncryptionHandler for decrypting a document encrypted with the Adobe.PubSec public key encryption handler.
PublicKeyEncryptionHandler(int acrobatversion)
          Create a new PublicKeyEncryptionHandler for encrypting a document.
PublicKeyEncryptionHandler(KeyStore keystore, String alias, char[] password)
          Create a new PublicKeyEncryptionHandler for decrypting a document encrypted with the Adobe.PubSec public key encryption handler.
 
Method Summary
 void addRecipient(X509Certificate recipient, int print, int extraction, int change)
          Add a recipient to the list of people that can open the document
protected  boolean chooseRecipient(X500Principal[] issuers, BigInteger[] serials)
          This method is called by prepareToDecrypt() to give an implementation the chance to select an appropriate entry from the KeyStore if it hasn't already been done.
 void finishedDecrypt()
          This method is called after the PDF has been read.
 void finishedEncrypt()
          This method is called after the PDF has been written.
 int getChange()
          Return the value of the "Change" flags.
 InputStream getDecryptionStream(InputStream in, int num, int gen)
          Return a FilterInputStream that will decrypt anything read from it.
 String getDescription()
          Return a textual description of the encryption used
 int getEncryptedStreamLength(int len)
          Return the length that a stream of the specified length would be after encryption.
 OutputStream getEncryptionStream(OutputStream out, int num, int gen)
          Return a FilterOutputStream that will encrypt anything written to it.
 int getExtract()
          Return the value of the "Extract" flags.
 String getFilterName()
          Return the name of the "Filter" field in the Encryption dictionary.
 int getPrint()
          Return the value of the "Print" flags.
 String getSubFilterName()
          Return the name of the "Subfilter" field in the Encryption dictionary.
 boolean hasRight(String right)
          Returns true if the EncryptionHandler wil grant the specified right to the PDF library.
 boolean isMetadataEncrypted()
          This method returns true if XMP MetaData should be stored encrypted, or false otherwise.
 boolean isRequired()
          This method should return true if the document needs to be encrypted.
 void prepareToDecrypt()
          This method is called just before the PDF is read in.
 void prepareToEncrypt()
          This method is called when the PDF is about to be written out.
 void setDecryptionKey(KeyStore keystore, String alias, char[] password)
          Set the private key to use to decrypt the document
 void setEncryptedMetadata(boolean encrypt)
          Set whether XMP Metadata is to be encrypted or not.
 
Methods inherited from class org.faceless.pdf2.EncryptionHandler
clone, containsKey, getArrayValueSize, getBooleanValue, getDecryptedStreamLength, getDictionaryValueKeys, getFileId, getNameValue, getNumericValue, getStringValue, getTextStringValue, isEmbeddedFileEncrypted, isStreamEncrypted, isStringEncrypted, markChanged, putArrayValue, putBooleanValue, putDictionaryValue, putNameValue, putNumericValue, putStringValue, putTextStringValue, setFileId
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

PublicKeyEncryptionHandler

public PublicKeyEncryptionHandler()
Create a new PublicKeyEncryptionHandler for decrypting a document encrypted with the Adobe.PubSec public key encryption handler. This constructor must be followed by a call to setDecryptionKey().

Since:
2.8.2

PublicKeyEncryptionHandler

public PublicKeyEncryptionHandler(KeyStore keystore,
                                  String alias,
                                  char[] password)
                           throws GeneralSecurityException
Create a new PublicKeyEncryptionHandler for decrypting a document encrypted with the Adobe.PubSec public key encryption handler.

Parameters:
keystore - the KeyStore containing the private key to decrypt the document with
alias - the alias of the key to use, or null to use the first key that fits
password - the password to decrypt the private key, or null if no password is required
Throws:
GeneralSecurityException
Since:
2.2.5

PublicKeyEncryptionHandler

public PublicKeyEncryptionHandler(int acrobatversion)
Create a new PublicKeyEncryptionHandler for encrypting a document. Recipients can be added using the addRecipient() method. The version number specifies the minimum release of Acrobat required to open the document - valid values are from 5 to 8, to target Acrobat 5.0 to 8.0 respectively. Targetting Acrobat 7.0 or above will result in the AES cipher being used if it's available. Targetting earlier version will use the RC4 cipher.

Parameters:
acrobatversion - the version of Acrobat that is being targeted. Must be between 5 and 8.
Since:
2.2.5
Method Detail

setEncryptedMetadata

public void setEncryptedMetadata(boolean encrypt)
Set whether XMP Metadata is to be encrypted or not. Unencrypted Metadata is supported by Acrobat 6.0 and later.

Parameters:
encrypt - whether to encrypt the XMP Metadata when saving the file.
Since:
2.8.2

setDecryptionKey

public void setDecryptionKey(KeyStore keystore,
                             String alias,
                             char[] password)
                      throws GeneralSecurityException
Set the private key to use to decrypt the document

Parameters:
keystore - the KeyStore containing the private key to decrypt the document with
alias - the alias of the key to use, or null to use the first key that fits
password - the password to decrypt the private key, or null if no password is required
Throws:
GeneralSecurityException
Since:
2.8.2

addRecipient

public void addRecipient(X509Certificate recipient,
                         int print,
                         int extraction,
                         int change)
Add a recipient to the list of people that can open the document

Parameters:
recipient - the X.509 certificate of the recipient
print - one of StandardEncryptionHandler.PRINT_NONE StandardEncryptionHandler.PRINT_LOWRES StandardEncryptionHandler.PRINT_HIGHRES
extraction - one of StandardEncryptionHandler.EXTRACT_NONE StandardEncryptionHandler.EXTRACT_ACCESSIBILITY StandardEncryptionHandler.EXTRACT_ALL
change - one of StandardEncryptionHandler.CHANGE_NONE StandardEncryptionHandler.CHANGE_LAYOUT StandardEncryptionHandler.CHANGE_FORMS StandardEncryptionHandler.CHANGE_ANNOTATIONS StandardEncryptionHandler.CHANGE_ALL
Since:
2.2.5

getChange

public int getChange()
Return the value of the "Change" flags. Only valid after decrypting a document.

Returns:
one of StandardEncryptionHandler.CHANGE_NONE StandardEncryptionHandler.CHANGE_LAYOUT StandardEncryptionHandler.CHANGE_FORMS StandardEncryptionHandler.CHANGE_ANNOTATIONS or StandardEncryptionHandler.CHANGE_ALL
Since:
2.6.5

getExtract

public int getExtract()
Return the value of the "Extract" flags. Only valid after decrypting a document.

Returns:
one of StandardEncryptionHandler.EXTRACT_NONE StandardEncryptionHandler.EXTRACT_ACCESSIBILITY StandardEncryptionHandler.EXTRACT_ALL
Since:
2.6.5

getPrint

public int getPrint()
Return the value of the "Print" flags. Only valid after decrypting a document.

Returns:
one of StandardEncryptionHandler.PRINT_NONE StandardEncryptionHandler.PRINT_LOWRES StandardEncryptionHandler.PRINT_HIGHRES
Since:
2.6.5

hasRight

public boolean hasRight(String right)
Description copied from class: EncryptionHandler
Returns true if the EncryptionHandler wil grant the specified right to the PDF library. The default implementation of this method returns true, but subclasses will override this method based on the rights applied to the document. This method should always return super.hasRight() if it doesn't recognise the value of "right"

Overrides:
hasRight in class EncryptionHandler
Parameters:
right - an interned() String defining the usage right the PDF library is querying.

getFilterName

public String getFilterName()
Description copied from class: EncryptionHandler
Return the name of the "Filter" field in the Encryption dictionary. This is used to determine whether an appropriate filter has been supplied by the decryption process. For example, the StandardEncryptionHandler class returns "Standard" from this method.

Specified by:
getFilterName in class EncryptionHandler

getSubFilterName

public String getSubFilterName()
Description copied from class: EncryptionHandler
Return the name of the "Subfilter" field in the Encryption dictionary. This is used to determine whether an appropriate filter has been supplied by the decryption process. As "Subfilter" is an optional field, this method may return null.

Specified by:
getSubFilterName in class EncryptionHandler

getDescription

public String getDescription()
Return a textual description of the encryption used

Since:
2.8.2

isRequired

public boolean isRequired()
Description copied from class: EncryptionHandler
This method should return true if the document needs to be encrypted. For example, the StandardEncryptionHandler returns false here if and only if no passwords are set and the document is set to allow full access.

Specified by:
isRequired in class EncryptionHandler

isMetadataEncrypted

public boolean isMetadataEncrypted()
Description copied from class: EncryptionHandler
This method returns true if XMP MetaData should be stored encrypted, or false otherwise. The default implementation returns true, subclasses should override as necessary.

Overrides:
isMetadataEncrypted in class EncryptionHandler

getEncryptedStreamLength

public int getEncryptedStreamLength(int len)
Description copied from class: EncryptionHandler
Return the length that a stream of the specified length would be after encryption. Generally this will be the same same as the input length (and that's what this method returns, unless overridden), but for some Encryption algorithms like AES, the size may be rounded up to the nearest block size.

Overrides:
getEncryptedStreamLength in class EncryptionHandler

getEncryptionStream

public OutputStream getEncryptionStream(OutputStream out,
                                        int num,
                                        int gen)
Description copied from class: EncryptionHandler
Return a FilterOutputStream that will encrypt anything written to it. The encryption parameters are set in EncryptionHandler.prepareToEncrypt(), which is called once at the start of the render.

Specified by:
getEncryptionStream in class EncryptionHandler
Parameters:
out - the OuptutStream that should be written to
num - the object number of the top-level object
gen - the generation number of the top-level object

getDecryptionStream

public InputStream getDecryptionStream(InputStream in,
                                       int num,
                                       int gen)
Description copied from class: EncryptionHandler
Return a FilterInputStream that will decrypt anything read from it. The decryption parameters are set in EncryptionHandler.prepareToDecrypt(), which is called once at the start of the PDF read.

Specified by:
getDecryptionStream in class EncryptionHandler
Parameters:
in - the InputStream that should be read from
num - the object number of the top-level object
gen - the generation number of the top-level object

prepareToDecrypt

public void prepareToDecrypt()
                      throws IOException
Description copied from class: EncryptionHandler
This method is called just before the PDF is read in. It is expected that this method will read various parameters from the Encrypt dictionary by way of the various get... methods, and use them and the value of EncryptionHandler.getFileId() to set its internal state so that it's ready to start decryption. It may throw an IOException if these parameters are invalid, in which case the document cannot be read.

Specified by:
prepareToDecrypt in class EncryptionHandler
Throws:
IOException

chooseRecipient

protected boolean chooseRecipient(X500Principal[] issuers,
                                  BigInteger[] serials)
This method is called by prepareToDecrypt() to give an implementation the chance to select an appropriate entry from the KeyStore if it hasn't already been done. The supplied arrays are equal length and indicate the Issuer and SerialNumber of all the recipients that can decrypt this document. By default this method does nothing.

Parameters:
issuers - an array listing all the X.509 Certificate Issuers
serials - an array listing all the X.509 Certificate Serial Numbers.
Returns:
true if the decryption should continue, false otherwise
Since:
2.8.3

prepareToEncrypt

public void prepareToEncrypt()
                      throws IOException
Description copied from class: EncryptionHandler
This method is called when the PDF is about to be written out. It is expected that this method will write various parameters which have been set by the user to the Encrypt dictionary (including the "Filter" field) by way of the various put... methods, and will use these and the value of EncryptionHandler.getFileId() to set its internal state so that it's ready to start encryption. It may throw an IOException if these parameters are in any way invalid, in which case the document cannot be written.

Specified by:
prepareToEncrypt in class EncryptionHandler
Throws:
IOException

finishedEncrypt

public void finishedEncrypt()
Description copied from class: EncryptionHandler
This method is called after the PDF has been written. It may be used to clean up any internal state that needs to be cleaned.

Specified by:
finishedEncrypt in class EncryptionHandler

finishedDecrypt

public void finishedDecrypt()
Description copied from class: EncryptionHandler
This method is called after the PDF has been read. It may be used to clean up any internal state that needs to be cleaned.

Specified by:
finishedDecrypt in class EncryptionHandler


Copyright © 2001-2013 Big Faceless Organization