3

I am working on an implementation where our system generates a PDF file for a user to download. The key of our process and system is that this PDF file should not be modifiable by the user or program on the users computer (at least, not without bad intent) as the file can be uploaded to the system later on where we need to make sure the file is in it`s original state by comparing its hash value.

We thought we accomplished this by first disabling all permissions (CanModify,CanAssembleDocument, etc.) and then encrypting the document with an owner`s password. This prevented the modification of the file by all readers we had access to. It now turns out that one of our users modifies a PDF as soon as he opens the file in Acrobat Reader and 'save as' the doc to a new pdf file. We cannot reproduce this with the same reader version (2015.006.30497) but he can, every time.

The alternative of signing the PDF document is not an option for us, at least not with a PKI or any visible signature that users can see in their reader. If there is some sort of invisible signing option that that would be great but I don't know how.

Below the code that we use to lock the PDF. For testing purposes we disabled ALL permissions, to no avail. We`re using PDFBox 2.0.11.

Any sugestions what options there are to better lock the file for modification?

    public static byte[] SealFile(byte[] pdfFile, String password) throws IOException
    {   PDDocument doc =PDDocument.load(pdfFile);
        ByteArrayOutputStream bos= new ByteArrayOutputStream();
        byte[] returnvalue =null;
        int keyLength = 256;

        AccessPermission ap = new AccessPermission();

        //Disable all
        ap.setCanModifyAnnotations(false);
        ap.setCanAssembleDocument(false); .
        ap.setCanFillInForm(false);
        ap.setCanModify(false);
        ap.setCanExtractContent(false);
        ap.setCanExtractForAccessibility(false);
        ap.setCanPrint(false);

        //The user password is empty ("") so user can read without password. The admin password is
        // set to lock/encrypt the document.
        StandardProtectionPolicy spp = new StandardProtectionPolicy(password, "", ap);
        spp.setEncryptionKeyLength(keyLength);
        spp.setPermissions(ap);
        doc.protect(spp);
        doc.save(bos);
        doc.close();
        bos.flush();
        return bos.toByteArray();
    }

This results in Adobe properties:

Adobe properties

Edit (solution):==========

As suggested by @mkl, (all credits to this person) we were able to solve the problem with the use of the appendOnly flag, which is part of the AcroForm functionality. Turned out that the signatureExists flag was not required for our problem to be solved. (and after reading the specs, was not applicable)

Below is the solution we implemented:

    /*
     *  This method is used to add the 'appendOnly flag' to the PDF document. This flag is part of
     *  the AcroForm functionality that instructs a PDF reader that the file is signed and should not be
     *  modified during the 'saved as' function. For full description see PDF specification PDF 32000-1:2008
     *  (https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf)
     *  paragraph 12.7.2 Interactive Form Dictionary
     */
    public static void addAcroFormSigFlags(PDDocument pdfDoc) {
        PDDocumentCatalog catalog = pdfDoc.getDocumentCatalog();
        PDAcroForm acroForm = catalog.getAcroForm();
        if (acroForm == null) {
            acroForm = new PDAcroForm(pdfDoc);
            catalog.setAcroForm(acroForm);

        }
        // AppendOnly:
        // If set, the document contains signatures that may be invalidated if the
        // file is saved (wirtten) in a way that alters its previous contents, as
        // opposed to an incremental update. Merely updating the file by appending
        // new information to the end of the previous version is safe (see h.7,
        // "Updating Example"). Conforming readers may use this flag to inform a
        // user requesting a full save that signatures will be invalidated and
        // require explicit confirmation before continuing with the operation
        acroForm.setAppendOnly(true);

        // SignatureExists: (Currently not used by us)
        // If set, the document contains at least one signature field. This flag
        // allows a conforming reader to enable user interface items (such as menu
        // items or pushbuttons) related to signature processing without having to
        // scan the entire document for the presence of signature fields.
//        acroForm.setSignaturesExist(true);

        // flag objects that changed (in case a 'saveIncremental' is done hereafter)
        catalog.getCOSObject().setNeedToBeUpdated(true);
        acroForm.getCOSObject().setNeedToBeUpdated(true);

    }
JPas
  • 33
  • 4
  • You can try and set the AcroForm flags that *claim* that a signature exists. This *should* at least result in any change being applied as incremental update which can be undone by truncating the file at its original size. – mkl Oct 26 '19 at 06:15
  • And always update to the latest version, currently 2.0.17. (Won't help with this problem either but it fixes bugs including security issues) – Tilman Hausherr Oct 27 '19 at 05:51
  • Thanks for the input @mkl and Tilman-Hausherr! I have upgraded to 2.0.17 (indeed did not solve the issue but good anyway) and looked into the AcroForm flags. I am fairly new to PDF development so had to look up AcroForms and some code to get this done. I will add the code to my post which I have tried but, unfortunately, it did not prevent the resulting PDF from being modified by Adobe Reader during the save-as action... If I mis-interpreted or missed anything on this subject than any help is welcome! – JPas Oct 30 '19 at 09:57
  • Please share an example PDF before and after manipulation by that Adobe Reader installation. – mkl Oct 30 '19 at 10:59
  • @mkl Hold your horses! After doing some more test (wanted to do some double checks with the user who was able to modify the pdf on his workstation) it does seem like this acroform and the 2 flags **signaturesExist** and **appendOnly** are having an effect! I`m currently doing some more tests. Keep you posted... – JPas Oct 30 '19 at 15:05
  • @mkl Great news: It turns out that you were pointing in the right direction. Using the **appendOnly** flag was exactly what we needed. Reading the PDF specification this seems to be what we were looking for and does the job well. We will probably combine it with the existing permissions+password encryption (code in my original post) to prevent appending new content. I will add the resulting code somewhere here. Thanks a LOT for your help!! I'm new here so tell me: will you write an answer to my request that I flag as answer or shall I do this? – JPas Oct 31 '19 at 10:24
  • That's great! (I'd really be interested, though, how those specific Adobe installations were tweaked to change the PDFs in the first place...) I'll write an answer. – mkl Oct 31 '19 at 11:40

1 Answers1

1

Even if actually signing the PDF document is not an option for you, you can try and set the AcroForm flags that claim that a signature exists.

This should prevent programs that are sensitive to these flags (like Adobe Reader) from applying changes to the PDF, or at least they should apply their changes as incremental update which can be undone by truncating the file at its original size.

The flags entry in question is the SigFlags entry in the AcroForm dictionary.

Bit positionName — Meaning

1SignaturesExist — If set, the document contains at least one signature field. This flag allows an interactive PDF processor to enable user interface items (such as menu items or push-buttons) related to signature processing without having to scan the entire document for the presence of signature fields.

2AppendOnly — If set, the document contains signatures that may be invalidated if the file is saved (written) in a way that alters its previous contents, as opposed to an incremental update. Merely updating the file by appending new information to the end of the previous version is safe (see H.7, "Updating example"). Interactive PDF processors may use this flag to inform a user requesting a full save that signatures will be invalidated and require explicit confirmation before continuing with the operation.

(ISO 32000-2, Table 225 — Signature flags)

Thus, you should set the SigFlags entry in the AcroForm dictionary in the Catalog to 3. You may have to create the AcroForm dictionary to start with if your PDF does not have a form definition yet

mkl
  • 90,588
  • 15
  • 125
  • 265