Class PublicKeyEncryptionHandler

  • All Implemented Interfaces:
    java.lang.Cloneable

    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(InputStream,EncryptionHandler), StandardEncryptionHandler
    • 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​(java.security.KeyStore keystore,
                                          java.lang.String alias,
                                          char[] password)
                                   throws java.security.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:
        java.security.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​(java.security.KeyStore keystore,
                                     java.lang.String alias,
                                     char[] password)
                              throws java.security.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:
        java.security.GeneralSecurityException
        Since:
        2.8.2
      • hasRight

        public boolean hasRight​(java.lang.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 java.lang.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 java.lang.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 java.lang.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 java.io.OutputStream getEncryptionStream​(java.io.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 java.io.InputStream getDecryptionStream​(java.io.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 java.io.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:
        java.io.IOException
      • chooseRecipient

        protected boolean chooseRecipient​(javax.security.auth.x500.X500Principal[] issuers,
                                          java.math.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 java.io.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:
        java.io.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