kerZy Hart
kerZy Hart

Reputation: 191

Exception when add digital signature to password producted pdf using PDFBOX?

When I am adding digital signature to the encrypted(password protected) PDF using PDF BOX am getting the following exceptions,

    Exception in thread "main" java.lang.NullPointerException
        at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.computeRevisionNumber(StandardSecurityHandler.java:128)
        at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.prepareDocumentForEncryption(StandardSecurityHandler.java:299)
        at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1457)
        at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1396)
        at com.seind.pdf.digitalsignature.CreateVisibleSignature.signPDF(CreateVisibleSignature.java:187)  
        at com.seind.pdf.digitalsignature.CreateVisibleSignature.main(CreateVisibleSignature.java:305)

But when I am using owner password to decrypt the PDF, its not working. its correct a password which I was used to encrypt... I hope you all understand the problem and here is my sample code:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;

import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * This is an example for visual signing a pdf with bouncy castle.

 * {@see CreateSignature}
 * @author Vakhtang Koroghlishvili
 */


public class CreateVisibleSignature implements SignatureInterface
{
        public static final String RESOURCE ="stock1.jpg";//"Paul_Cézanne_222.jpg";//"signature-stamp.jpg";//"SJG_Signature.png";//"amber-signature.png";// "Man-Utd-v-Bayern-Munich-018.jpg";//"check_256.png";//"signature-stamp.jpg";

    private static BouncyCastleProvider provider = new BouncyCastleProvider();

    private PrivateKey privKey;
    private Certificate[] cert;
    private SignatureOptions options;

    public CreateVisibleSignature()
        {

        }

    /**
     * Initialize the signature creator with a keystore (pkcs12) and pin that
     * should be used for the signature.
     *
     * @param keystore is a pkcs12 keystore.
     * @param pin is the pin for the keystore / private key
     */
    public CreateVisibleSignature(KeyStore keystore, char[] pin)
    {
        try
        {
            // grabs the first alias from the keystore and get the private key. An
            // alternative method or constructor could be used for setting a specific
            // alias that should be used.

            Enumeration<String> aliases = keystore.aliases();

            String alias = null;
            while (aliases.hasMoreElements())
            {
                alias = aliases.nextElement();
                System.out.println(" alias name "+alias);
            }

            privKey = (PrivateKey) keystore.getKey(alias, pin);
            cert = keystore.getCertificateChain(alias);
        }
        catch (KeyStoreException e)
        {
            e.printStackTrace();
        }
        catch (UnrecoverableKeyException e)
        {
            System.err.println("Could not extract private key.");
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e)
        {
            System.err.println("Unknown algorithm.");
            e.printStackTrace();
        }
    }

    /**
     * Signs the given pdf file.
     *
     * @param document is the pdf document
     * @param signatureProperties
     * @return the signed pdf document
     * @throws Exception 
     */
    public File signPDF(File document, PDVisibleSigProperties signatureProperties) throws Exception
    {

        PDDocument doc = openPDFDoc(document);




        byte[] buffer = new byte[8 * 1024];

        if (document == null || !document.exists())
        {
            new RuntimeException("Document for signing does not exist");
        }

        // creating output document and prepare the IO streams.
        String name = document.getName();

        String substring = name.substring(0, name.lastIndexOf("."));

        File outputDocument = new File(document.getParent(), substring + "_signed.pdf");

        FileInputStream fis = new FileInputStream(document);

        FileOutputStream fos = new FileOutputStream(outputDocument);

        int c;
        while ((c = fis.read(buffer)) != -1)
        {
            fos.write(buffer, 0, c);
        }
        fis.close();

        fis = new FileInputStream(outputDocument);

        // load document
      //  PDDocument doc = PDDocument.load(document);

        // create signature dictionary
        PDSignature signature = new PDSignature();
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
        // subfilter for basic and PAdES Part 2 signatures
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName(signatureProperties.getSignerName());
        signature.setLocation("chennai");
        //signature.setReason("reason for signature");

        // the signing date, needed for valid signature
        signature.setSignDate(Calendar.getInstance());

        // register signature dictionary and sign interface

       options = new SignatureOptions();

       options.setVisualSignature(signatureProperties);

       // options.setPage(signatureProperties.getPage());
       //options.setPreferedSignatureSize(signatureProperties.getPreferredSize());

       doc.addSignature(signature, this, options);

       doc.saveIncremental(fis, fos);

       return outputDocument;
    }

        PDDocument openPDFDoc(File pdfFile) throws Exception 
    {

        File originalPDF = pdfFile;

        PDFParser parser = new PDFParser(new BufferedInputStream(new FileInputStream(originalPDF)));

        parser.parse();

        PDDocument originialPdfDoc = parser.getPDDocument();

        boolean isOriginalDocEncrypted = originialPdfDoc.isEncrypted();

        if (isOriginalDocEncrypted)
        {

            originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));

        }


        return originialPdfDoc;
    } 


    /**
     * SignatureInterface implementation.
     *
     * This method will be called from inside of the pdfbox and create the pkcs7 signature.
     * The given InputStream contains the bytes that are given by the byte range.
     *
     * This method is for internal use only. <-- TODO this method should be private
     *
     * Use your favorite cryptographic library to implement pkcs7 signature creation.
     */
    @SuppressWarnings("deprecation")
    @Override
    public byte[] sign(InputStream content) throws IOException
    {
        CMSProcessableInputStream input = new CMSProcessableInputStream(content);
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        // CertificateChain
        List<Certificate> certList = Arrays.asList(cert);

        CertStore certStore = null;
        try
        {
            certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), provider);
            gen.addSigner(privKey, (X509Certificate) certList.get(0), CMSSignedGenerator.DIGEST_SHA256);
            gen.addCertificatesAndCRLs(certStore);
            CMSSignedData signedData = gen.generate(input, false, provider);
            return signedData.getEncoded();
        }
        catch (Exception e)
        {
            // should be handled
            System.err.println("Error while creating pkcs7 signature.");
            e.printStackTrace();
        }
        throw new RuntimeException("Problem while preparing signature");
    }

    public static void main(String[] args) throws Exception
    {
        //String pdfPath="E:\\outputs1\\iText in Action.pdf";

          String pdfPath="E:\\outputs1\\CNB_20131029_AAPL034_0490301_NSEFO_ECN_iPass.pdf";

        //  new PdfOptimize().reducePdfSize(pdfPath);

          File ksFile = new File("E:/sol.p12");

          KeyStore keystore = KeyStore.getInstance("PKCS12", provider);

          char[] pin = "xxxxxxx".toCharArray();

          keystore.load(new FileInputStream(ksFile), pin);



          //String pdfPath="E:\\temp\\pdf\\security\\password\\hello_iText.pdf";

            File document = new File(pdfPath);

            CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());

            FileInputStream image = new FileInputStream(RESOURCE);

            PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(pdfPath, image, 1);

            visibleSig.xAxis(660).yAxis(480).zoom(-50).signatureFieldName("signature");

            visibleSig.height(37);

            visibleSig.width(70);

            //visibleSig.imageSizeInPercents(50);

            PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();

            signatureProperties.signerName("XXXXXXX").signerLocation("chennai").signatureReason("Security").preferredSize(0)
                    .page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();


            signatureProperties.setPdVisibleSignature(visibleSig);

            signing.signPDF(document, signatureProperties);

    }


}

And most of the methods are deprecated which are used to verify the owner password ,user password and etc.

Upvotes: 3

Views: 2676

Answers (1)

santhosh kumar
santhosh kumar

Reputation: 21

Even the password you used is a correct one , when the PDF is Password protected it has some securities added to it. So you need to remove those securites.

In your openPDFDoc(File pdfFile) method

Add these lines to your method

if (isOriginalDocEncrypted)
{
    originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));
    **originialPdfDoc.setAllSecurityToBeRemoved(true);**
}

This will remove the securities set to the PDF

Now you can do the job.

Upvotes: 2

Related Questions