Подписание и защита Pdfbox без сохранения в файловой системе

#java #encryption #pdfbox #signature

#java #шифрование #pdfbox #подпись

Вопрос:

Поддерживает ли pdfbox подписание во время выполнения после создания и защиты pdf. В настоящее время я успешно загружаюсь из файловой системы и выполняю это.

Я пытаюсь подписать защищенный PDF-файл «на лету» и вернуть полученный документ, не сохраняя его снова, не используя механизм сохранения pdf на протяжении всего процесса.

 public byte[] attachPdf(){
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PDDocument doc = sign(generatedPdf());//generated pdf
    doc.save(byteArrayOutputStream);
    response = new ResponseEntity<>(byteArrayOutputStream.toByteArray(), headers, HttpStatus.OK);
    doc.close();
}


public PDDocument sign(PDDocument doc1){
        //FileOutputStream fos = new FileOutputStream(signFile);
        //PDDocument doc = PDDocument.load(inputFile, "*******");
        //doc.setAllSecurityToBeRemoved(true);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        doc1.save(byteArrayOutputStream);
        PDDocument doc = PDDocument.load(byteArrayOutputStream.toByteArray());
        int accessPermissions = SigUtils.getMDPPermission(doc);

        PDSignature signature = null;
        PDRectangle rect = null;

        if (signature == null)
        {
            // create signature dictionary
            signature = new PDSignature();
        }

        if (rect == null)
        {
            rect = createSignatureRectangle(doc, humanRect);
        }
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName("test");
        signature.setLocation("testL");
        signature.setReason("testR");
        signature.setSignDate(Calendar.getInstance());
        SignatureInterface signatureInterface = isExternalSigning() ? null : this;
        signatureOptions = new SignatureOptions();
        signatureOptions.setVisualSignature(createVisualSignatureTemplate(doc, doc.getNumberOfPages()-1, rect, signature));
        signatureOptions.setPage(doc.getNumberOfPages()-1);
        doc.addSignature(signature, signatureInterface, signatureOptions);
        //doc.save(baos);
        //doc.saveIncremental(fos);
        //IOUtils.closeQuietly(signatureOptions);
        return doc;
        }
  

Комментарии:

1. Нет, это невозможно. Код всегда считывается из существующего PDF-файла и из добавочной части для создания его подписи. (Теоретически это возможно, и я видел такие PDF-файлы, но они не были созданы PDFBox)

2. Теоретически вы могли бы начать с загрузки небольшого PDF-файла без страниц, а затем поместить всю свою работу как инкрементную. Вам просто нужно позаботиться о том, чтобы все ваши изменения были помечены для обновления, что было бы довольно сложно.

3. Можно ли сохранить, создав файл в памяти, например, используя ByteArrayOutputStream вместо файла физической файловой системы?

4. ДА. Однако PDFBox создает локальный файл из него внутри. (Возможно, можно загрузить из массива байтов из этого ByteArrayOutputStream, который быстрее, чем из ByteArrayInputStream, но я не проверял, работает ли это для signing => попробуйте)

5. К сожалению, это не работает! подписание прошло успешно, но при его открытии я получаю сообщение об ошибке подписи. Есть ли какое-то обходное решение для этого?

Ответ №1:

  • Как было предложено, измененный на новый объект ByteArrayOutputStream и используемый метод saveIncremental заставил его работать. Фрагмент ниже.

 public PDDocument sign(PDDocument doc1){
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
     doc1.save(byteArrayOutputStream);
     PDDocument doc = PDDocument.load(byteArrayOutputStream.toByteArray());
     int accessPermissions = SigUtils.getMDPPermission(doc);

     //sign doc here
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     doc.saveIncremental(baos);
     IOUtils.closeQuietly(signatureOptions);
     return baos.toByteArray();
}