用api提供的签名哈希值签署PDF文件

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

我正试图用 PDFBox 和第三方签名供应商。

我的程序。

  1. 从用户输入中获取pdf文件
  2. 用给定的pdf内容创建PDD文档。
  3. 创建一个PDSignature,包含所有给定的属性,如组织或位置,但不包含签名哈希值本身。
  4. 将此签名对象添加到PDD文档中,并从PDD文档中创建一个摘要以发送给API。
  5. 等待 API 的成功回复(包含签名哈希值),并将此哈希值插入 PDDocuments 的 PDSignature 对象中,而不改变整个文档。

我的问题是,我可以创建PDDocument的PDSignature对象。

我可以创建PDDocument,PDSignature和它的摘要,并将其发送给API。然后我从API得到正确有效的签名哈希值,我可以把它添加到PDDocument中,但每当这样做的时候,生成的pdf由于 "被更改或操纵 "而有一个无效的签名(签名者、时间戳和证书都是有效的)。我也尝试使用 ExternalSigningSupportPDFBox 但我不能使用它,因为我总是遇到一个错误。

"java.lang.IllegalStateException: signature reserve byte range has been changed after addSignature(), please set the byte range that existed after addSignature()".

我的代码可以使用,但签名无效。 My Code that works but invalidates the signature:

//Pending Signature is just a DTO
public static PendingSignature createPendingSignatureFromPdf(InputStream pdf2sign, OutputStream fos, String sigName, String sigLocation, String sigReason, String contactInfo, Date forcedDate, Long revisionId) throws IOException {
    
        File pdfFileToSigned = createTempFile("chars", "" + Calendar.getInstance().getTimeInMillis());
        File pdfPreparedToBeSigned = createTempFile("chars", "" + Calendar.getInstance().getTimeInMillis());
        File pdfHashPreparedToBeSigned = createTempFile("chars", "" + Calendar.getInstance().getTimeInMillis());
    
        try {
            if (fos == null) {
                fos = new FileOutputStream(pdfPreparedToBeSigned);
            }
    
            FileUtils.copyInputStreamToFile(pdf2sign, pdfFileToSigned);
    
            PDDocument doc = PDDocument.load(pdfFileToSigned);
            PDSignature signature = new PDSignature();
    
            signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
            signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
    
            if (contactInfo != null && !contactInfo.isEmpty()) {
                signature.setContactInfo(contactInfo);
            }
            if (sigLocation != null && !sigLocation.isEmpty()) {
                signature.setLocation(sigLocation);
            }
            if (sigReason != null && !sigReason.isEmpty()) {
                signature.setReason(sigReason);
            }
            if (sigName != null && !sigName.isEmpty()) {
                signature.setName(sigName);
            }
            if (forcedDate != null) {
                SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
                Calendar cal = Calendar.getInstance();
                cal.setTime(sdf.parse(sdf.format(forcedDate)));
                signature.setSignDate(cal);
            }
    
            final OutputStream outputStream = new FileOutputStream(pdfHashPreparedToBeSigned);
            SignatureInterface signatureInterface = new SignatureInterface() {
                @Override
                public byte[] sign(InputStream content) throws IOException {
                    try {
                        MessageDigest digest = MessageDigest.getInstance("SHA-256");
                        byte[] imp = digest.digest(content.toString().getBytes(StandardCharsets.UTF_16));
                        IOUtils.copy(new ByteArrayInputStream(imp), outputStream);
                        return new byte[0];
                    } catch (NoSuchAlgorithmException e) {
                        e.printStackTrace();
                        return new byte[0];
                    }
                }
            };
    
            SignatureOptions signatureOptions = new SignatureOptions();
            signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 8);
    
            doc.addSignature(signature, signatureInterface, signatureOptions);
    
            if (revisionId != null) {
                doc.setDocumentId(revisionId);
            } else {
                doc.setDocumentId(0L);
            }
            doc.saveIncremental(fos);
    
            PendingSignature pendingSignature = new PendingSignature(doc, signature, IOUtils.toByteArray(new FileInputStream(pdfHashPreparedToBeSigned)));
            return pendingSignature;
        } catch (IOException | ParseException e) {
            throw new IOException(e);
        } finally {
            fos.close();
            pdf2sign.close();
            FileUtils.deleteQuietly(pdfFileToSigned);
            FileUtils.deleteQuietly(pdfPreparedToBeSigned);
            FileUtils.deleteQuietly(pdfHashPreparedToBeSigned);
        }
     }
    
    //Gets called when the api returns sucess with the signedbytes
    public static File insertHashToPdf(PendingSignature pendingSignature, final byte[] signedBytes) throws IOException {
    
        File outputDocument = createTempFile("chars", "" + Calendar.getInstance().getTimeInMillis());
    
        FileOutputStream fos = new FileOutputStream(outputDocument);
    
        PDDocument doc = pendingSignature.getPdfDocument();
        PDSignature pdfSignature = pendingSignature.getPdfSignature();
    
        //Produces signature that it invalid because it was altered or manipulated
        pdfSignature.setContents(signedBytes);
    
        doc.saveIncremental(fos);
    
        if (fos != null) {
            fos.close();
        }
    
        return outputDocument;
    }

签名看起来是这样的。

InvalidSignature

有谁知道如何在不使签名无效的情况下将签名哈希插入到整个PDDocument中?

java pdf pdfbox sign pkcs#7
1个回答
1
投票

所以我终于找到了一个可行的解决方案。

链接到日保存的repo。https:/github.comcrs2195signaturetreemasterRemoteSignature-%20PDFBoxCSC-PDFBox。

© www.soinside.com 2019 - 2024. All rights reserved.