如何使用pdfbox删除数字签名PDF的只读模式和签名

问题描述 投票:0回答:1

有时我们希望删除 PDF 文档的写保护/“加密”和数字签名,以便可以更改和重新签名文档。例如。因为原始文档丢失或被更改,并且数字签名已损坏(例如this文档)。

为此,我们使用了以下 iText 8 代码(事实上,展平 AcroForm 并不是最好的方法,例如因为交互式表单被禁用等):

public static byte[] cleanUpPdfItext(byte[] originalPdfData) throws Exception {
    // Read the PDF document
    try (
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            PdfReader pdfReader = new PdfReader(new ByteArrayInputStream(originalPdfData)).setUnethicalReading(true);
            PdfWriter pdfWriter = new PdfWriter(byteArrayOutputStream);
            PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter)
    ) {
        // Create the signature utils
        SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);

        // Check if encrypted and/or contains signatures
        boolean isEncrypted = pdfReader.isEncrypted();
        boolean hasSignatures = !signatureUtil.getSignatureNames().isEmpty();

        // Handle all cases
        if (isEncrypted && hasSignatures) { // Encrypted and signatures
            // Remove the signatures
            PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDocument, true);
            form.flattenFields();

            // Write the changes to the output stream, so we can read them
            pdfDocument.close();

            // Get the manipulated document
            return byteArrayOutputStream.toByteArray();
        } else if (isEncrypted) { // Encrypted but no signatures
            // Write the changes to the output stream, so we can read them
            pdfDocument.close();

            // Get the manipulated document
            return byteArrayOutputStream.toByteArray();
        } else { // Not encrypted/no signatures
            // Return the original document data
            return originalPdfData;
        }
    }
}

问题: 使用 pdfbox 执行此操作的等效代码是什么?删除写保护/“加密”并删除所有现有签名(尚未丢失),以便可以编辑和撤销文档?

我想出了这个初始版本:

public static byte[] cleanUpPdfbox(byte[] original) throws Exception {
    try (
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            PDDocument pdDocument = Loader.loadPDF(original)
    ) {
        // Check if encrypted or read only
        AccessPermission accessPermission = pdDocument.getCurrentAccessPermission();
        boolean isEncrypted = pdDocument.isEncrypted() || accessPermission.isReadOnly();

        // Check if signatures exist
        boolean hasSignatures = false;
        PDAcroForm pdAcroForm = pdDocument.getDocumentCatalog().getAcroForm();
        if (pdAcroForm != null) {
            // Get a list of all signature fields
            List<PDSignature> pdSignatures = pdDocument.getSignatureDictionaries();
            hasSignatures = !pdSignatures.isEmpty();
        }

        // Remove all security if required
        if (isEncrypted) {
            pdDocument.setAllSecurityToBeRemoved(true);
        }

        // Remove all signatures
        if (hasSignatures) {
            // TODO: Code in question
        }

        // Write the document
        pdDocument.save(byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }
}
java pdf itext pdfbox
1个回答
0
投票

如果有修改,您可以在倒数第二个 %%EOF 之后中断。但是该文件不使用修订版。此解决方案从 fields 数组中删除签名字段(希望它位于顶层),并从页面上的注释数组中删除它。并从文档目录中删除 Perms 条目。

    try (PDDocument doc = Loader.loadPDF(new File("Encrypted.pdf")))
    {
        PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
        
        List<PDField> oldFieldList = acroForm.getFields();
        List<PDField> newFieldList = new ArrayList<>();
        for (PDField field : oldFieldList)
        {
            if (!(field instanceof PDSignatureField))
            {
                newFieldList.add(field);
            }
        }
        acroForm.setFields(newFieldList);
        for (PDPage page : doc.getPages())
        {
            List<PDAnnotation> oldAnnotationList = page.getAnnotations();
            List<PDAnnotation> newAnnotationList = new ArrayList<>();
            for (PDAnnotation ann : oldAnnotationList)
            {
                if (ann instanceof PDAnnotationWidget && ann.getCOSObject().containsKey(COSName.V))
                {
                    continue;
                }
                newAnnotationList.add(ann);
            }
            page.setAnnotations(newAnnotationList);
        }

        doc.setAllSecurityToBeRemoved(true);
        doc.getDocumentCatalog().getCOSObject().removeItem(COSName.PERMS);
        doc.save(new File("SO79055588-saved.pdf"));
    }
© www.soinside.com 2019 - 2024. All rights reserved.