使用PDFBOX将数字签名添加到密码生成pdf时出现异常?

时间:2014-04-03 15:36:20

标签: pdf pdf-generation digital-signature pdfbox

当我使用PDF添加数字签名到加密(受密码保护)PDF BOX时,我会收到以下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)

但是当我使用所有者密码decrypt PDF时,它无效。它是正确的密码我用来加密...我希望你们都明白这个问题,这是我的示例代码:

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);

    }


}

大多数方法都是deprecated,用于验证所有者密码,用户密码等。

1 个答案:

答案 0 :(得分:2)

即使您使用的密码是正确的密码,当PDF受密码保护时,它也会添加一些证券。所以你需要删除那些证券。

openPDFDoc(文件pdfFile)方法

将这些行添加到您的方法

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

这将删除设置为PDF的证券

现在你可以胜任。