Merge encrypted pdf file programmatically exception

Tags: , , , ,



I have been using the following code to merge encrypted pdf files programmatically.

public void mergeMyFiles(String filesToBeMerged[], String mergedFileLocation, String password) {
    try {
        int pageOffset = 0;
        ArrayList masterBookMarkList = new ArrayList();

        int fileIndex = 0;
        String outFile = mergedFileLocation;
        Document document = null;
        PdfCopy writer = null;
        PdfReader reader = null;
        PdfReader.unethicalreading = true;
        for (fileIndex = 0; fileIndex < filesToBeMerged.length; fileIndex++) {
            /**
             * Create a reader for the file that we are reading
             */
            reader = new PdfReader(filesToBeMerged[fileIndex], password.getBytes());
            /**
             * Replace all the local named links with the actual destinations.
             */
            reader.consolidateNamedDestinations();

            /**
             * Retrieve the total number of pages for this document
             */
            int totalPages = reader.getNumberOfPages();

            /**
             * Get the list of bookmarks for the current document
             * If the bookmarks are not empty, store the bookmarks
             * into a master list
             */
            List bookmarks = SimpleBookmark.getBookmark(reader);
            if (bookmarks != null) {
                if (pageOffset != 0)
                    SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset,
                        null);
                masterBookMarkList.addAll(bookmarks);
                System.out.println("Bookmarks found and storing...");
            } else {
                System.out.println("No bookmarks in this file...");
            }
            pageOffset += totalPages;

            /**
             * Merging the files to the first file.
             * If we are passing file1, file2 and file3,
             * we will merge file2 and file3 to file1.
             */
            if (fileIndex == 0) {
                /**
                 * Create the document object from the reader
                 */
                document = new Document(reader.getPageSizeWithRotation(1));

                /**
                 * Create a pdf write that listens to this document.
                 * Any changes to this document will be written the file
                 *
                 * outFile is a location where the final merged document
                 * will be written to.
                 */

                System.out.println("Creating an empty PDF...");
                writer = new PdfCopy(document, new FileOutputStream(outFile));
                /**
                 * Open this document
                 */
                document.open();
            }
            /**
             * Add the conent of the file into this document (writer).
             * Loop through multiple Pages
             */
            System.out.println("Merging File: " + filesToBeMerged[fileIndex]);
            PdfImportedPage page;
            for (int currentPage = 1; currentPage <= totalPages; currentPage++) {
                page = writer.getImportedPage(reader, currentPage);
                writer.addPage(page);
            }

            /**
             * This will get the documents acroform.
             * This will return null if no acroform is part of the document.
             *
             * Acroforms are PDFs that have been turned into fillable forms.
             */
            System.out.println("Checking for Acroforms");
            PRAcroForm form = reader.getAcroForm();
            if (form != null) {
                //writer.copyAcroForm(reader);
                writer.addDocument(reader);
                System.out.println("Acroforms found and copied");
            } else
                System.out.println("Acroforms not found for this file");

            System.out.println();
        }
        /**
         * After looping through all the files, add the master bookmarklist.
         * If individual PDF documents had separate bookmarks, master bookmark
         * list will contain a combination of all those bookmarks in the
         * merged document.
         */
        if (!masterBookMarkList.isEmpty()) {
            writer.setOutlines(masterBookMarkList);
            System.out.println("All bookmarks combined and added");

        } else {
            System.out.println("No bookmarks to add in the new file");

        }

        /**
         * Finally Close the main document, which will trigger the pdfcopy
         * to write back to the filesystem.
         */
        document.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I started getting this error recently upon trying to create the pdfReader at this line of code:

reader = new PdfReader(filesToBeMerged[fileIndex], password.getBytes());

com.itextpdf.text.exceptions.InvalidPdfException: Unknown encryption type R = 6 at com.itextpdf.text.pdf.PdfReader.readPdf(PdfReader.java:738) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:181) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:219) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:207) at com.project.mainPageShop.mergeMyFiles(mainPageShop.java:4368) at com.project.mainPageShop$DownloadFileAsync.onPostExecute(mainPageShop.java:11757) at com.project.mainPageShop$DownloadFileAsync.onPostExecute(mainPageShop.java:11628) at android.os.AsyncTask.finish(AsyncTask.java:755) at android.os.AsyncTask.access$900(AsyncTask.java:192) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:237) at android.app.ActivityThread.main(ActivityThread.java:7814) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068)

Kindly note that the password is correct, and same file which use to work using this code, is now raising this exception.

UPDATE:

I have used the following code using com.itextpdf:itext7-core:7.0.2

public void mergePDFFiles(String FILE1, String FILE2, String mergedFileLocation, String password) {
    try {
        PdfReader pdf1 = new PdfReader(FILE1);
        pdf1.setUnethicalReading(true);
        PdfReader pdf2 = new PdfReader(FILE2);
        pdf2.setUnethicalReading(true);
        PdfDocument pdfDocument = new PdfDocument(pdf1, new PdfWriter(mergedFileLocation));
        PdfDocument pdfDocument2 = new PdfDocument(pdf2);

        PdfMerger merger = new PdfMerger(pdfDocument);
        merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages());

        pdfDocument2.close();
        pdfDocument.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

This is the logcat Result:

FATAL EXCEPTION: main Process: com.project, PID: 7665 com.itextpdf.kernel.PdfException: Unknown encryption type R == 6. at com.itextpdf.kernel.pdf.PdfEncryption.readAndSetCryptoModeForStdHandler(PdfEncryption.java:508) at com.itextpdf.kernel.pdf.PdfEncryption.(PdfEncryption.java:181) at com.itextpdf.kernel.pdf.PdfReader.readDecryptObj(PdfReader.java:1061) at com.itextpdf.kernel.pdf.PdfReader.readPdf(PdfReader.java:531) at com.itextpdf.kernel.pdf.PdfDocument.open(PdfDocument.java:1585) at com.itextpdf.kernel.pdf.PdfDocument.(PdfDocument.java:281) at com.itextpdf.kernel.pdf.PdfDocument.(PdfDocument.java:249) at com.project.mainPageShop.mergePDFFiles(mainPageShop.java:4353) at com.neelwafurat.iKitabForAndroid.mainPageShop$DownloadFileAsync.onPostExecute(mainPageShop.java:11788) at com.project.mainPageShop$DownloadFileAsync.onPostExecute(mainPageShop.java:11659) at android.os.AsyncTask.finish(AsyncTask.java:755) at android.os.AsyncTask.access$900(AsyncTask.java:192) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:237) at android.app.ActivityThread.main(ActivityThread.java:7814) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068)

The error is occurring at the following line:

PdfDocument pdfDocument = new PdfDocument(pdf1, new PdfWriter(mergedFileLocation));

Find below links for sample encrypted pdf files used with password: 123456

https://smallpdf.com/shared#st=8921059d-6615-4264-a3f6-c76d476dc168&fn=test+1.pdf&ct=1602755420749&tl=share-document&rf=link

https://smallpdf.com/shared#st=7d3c11c7-b34d-4399-bc03-c66b7be788d0&fn=test+2.pdf&ct=1602755505331&tl=share-document&rf=link

Answer

Revision 6 of the standard security handler is not supported in iText 5 or iText 7.0.2. It was introduced in iText 7.1.0 in the context of PDF 2.0 support.

I have slightly tweaked your code sample to test. Note that you were not passing the password to the PdfReader instance.

Also note that the password you shared for the sample PDFs (123456) is the user password, not the owner password.

A user password, also called open password, is used to open a PDF document, i.e. to give access to the content. All other restrictions are handled by an owner password, also called permissions password, e.g. allowing/preventing a document being printed.

For your sample documents, both the open password and permissions password are set:

PDF permissions

If you have the owner password available, you should use it the process the PDF, i.e. pass it to the PdfReader instance. That allows you to avoid the unethicalreading setting.

Test code:

public void mergePDFFiles(String FILE1, String FILE2, String mergedFileLocation, String password)
{
    try {
        PdfReader pdf1 = new PdfReader(FILE1,
            new ReaderProperties().setPassword(password.getBytes()));
        pdf1.setUnethicalReading(true);
        PdfReader pdf2 = new PdfReader(FILE2,
            new ReaderProperties().setPassword(password.getBytes()));
        pdf2.setUnethicalReading(true);
        PdfDocument pdfDocument = new PdfDocument(pdf1, new PdfWriter(mergedFileLocation));
        PdfDocument pdfDocument2 = new PdfDocument(pdf2);

        PdfMerger merger = new PdfMerger(pdfDocument);
        merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages());

        pdfDocument2.close();
        pdfDocument.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

iText 7.0.2 does not support revision 6, as you’ve noticed:

Exception in thread "main" com.itextpdf.kernel.PdfException: Unknown encryption type R == 6.
    at com.itextpdf.kernel.pdf.PdfEncryption.readAndSetCryptoModeForStdHandler(PdfEncryption.java:508)
    at com.itextpdf.kernel.pdf.PdfEncryption.<init>(PdfEncryption.java:181)
    at com.itextpdf.kernel.pdf.PdfReader.readDecryptObj(PdfReader.java:1061)
    at com.itextpdf.kernel.pdf.PdfReader.readPdf(PdfReader.java:531)
    at com.itextpdf.kernel.pdf.PdfDocument.open(PdfDocument.java:1585)
    at com.itextpdf.kernel.pdf.PdfDocument.<init>(PdfDocument.java:281)
    at com.itextpdf.kernel.pdf.PdfDocument.<init>(PdfDocument.java:249)

Starting from iText 7.1.0 up until the current release (7.1.13), your 2 sample files will merge correctly, resulting in a 4-page output file.



Source: stackoverflow