Java 使用摘要对pdf进行异步签名

Java 使用摘要对pdf进行异步签名,java,pdf,pdfbox,pkcs#7,Java,Pdf,Pdfbox,Pkcs#7,我正在尝试执行以下PDF签名设置,在客户端和服务器之间分为异步步骤: 服务器接收pdf并计算其摘要 服务器将摘要发送到客户端 客户端稍后对哈希进行签名 客户端将签名发送到服务器 服务器将签名嵌入到pdf中 我的立足点主要在和 第二个问题允许我编写大部分代码,但是我发现文件的完整性受到了破坏。我似乎无法序列化中间pdf以便稍后嵌入签名(以确保没有时间戳被更改,等等)。但从第一个问题开始,这似乎是一个比我想象的更难的问题。这真的能做到吗 我用的是pdfbox 服务器代码: PDDoc

我正在尝试执行以下PDF签名设置,在客户端和服务器之间分为异步步骤:

  • 服务器接收pdf并计算其摘要
  • 服务器将摘要发送到客户端
  • 客户端稍后对哈希进行签名
  • 客户端将签名发送到服务器
  • 服务器将签名嵌入到pdf中
  • 我的立足点主要在和

    第二个问题允许我编写大部分代码,但是我发现文件的完整性受到了破坏。我似乎无法序列化中间pdf以便稍后嵌入签名(以确保没有时间戳被更改,等等)。但从第一个问题开始,这似乎是一个比我想象的更难的问题。这真的能做到吗

    我用的是pdfbox

    服务器代码:

            PDDocument document = PDDocument.load(documentFile);
            PDSignature signature = new PDSignature();
            signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
            signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
            signature.setName("Example User");
            signature.setLocation("Los Angeles, CA");
            signature.setReason("Testing");
            Calendar date = Calendar.getInstance();
            signature.setSignDate(date);
            document.addSignature(signature);
    
            ExternalSigningSupport externalSigningSupport = document.saveIncrementalForExternalSigning(null);
    
            byte[] content = IOUtils.toByteArray(externalSigningSupport.getContent());
            MessageDigest md = MessageDigest.getInstance("SHA256", new BouncyCastleProvider());
            byte[] digest = md.digest(content); // this is sent to client
    
    我所做的基本工作是将摘要发送到客户端进行签名,然后在服务器上重新执行上述步骤并设置客户端签名:

            ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(fos);
            externalSigning.setSignature(encodedSignature); // encodedSignature is received from client and computed based on the digest sent by the server
    
    这个设置最终导致文件的完整性被破坏,因为一旦我在服务器上嵌入了
    encodedSignature
    ,我就会创建一个新的PDSignature。是否有办法序列化调用addSignature后创建的PDDocument,以便稍后在服务器上对其进行反序列化并添加客户端的签名

    我所做的基本工作是将摘要发送给客户端进行签名,然后在服务器上重新执行上述步骤并设置客户端签名

    如果希望上述步骤生成相同的文档,则需要

    • 确保这些步骤的输入相同且正确
    • 提供相同的修订id种子值
    如果执行此操作,则上述步骤的输出与任务所需的输出相同

    确保输入相同 上述步骤中的一个步骤容易导致不同的输入:

    Calendar date = Calendar.getInstance();
    signature.setSignDate(date);
    
    为了保证输入相同,您必须仅确定一次
    日期
    ,并在每次为同一签名事务执行这些步骤时使用该单一值

    提供相同的修订id种子值 按照规范的建议,PDFBox尝试为每个PDF版本提供其唯一的ID。不过,在本例中,执行上述步骤时,我们需要相同的版本ID

    幸运的是,PDFBox允许我们提供它用来使修订ID足够唯一的种子值

    由于我们不希望在签署同一文档时始终使用相同的修订ID,而只是在当前签名事务中,因此我们应该仅在同一事务中使用相同的种子值。由于种子值很长,我们可以简单地使用与上面讨论的
    日期
    对应的时间(以毫秒为单位),即:

    pdDocument.setDocumentId(date.getTimeInMillis());
    

    我只是有时间来试试这个。我发现:无法写入签名,org.apache.pdfbox.pdfwriter.COSWriter.writeExternalSignature(COSWriter.java:789)的空间不足。我通过之前为签名分配空间来解决这个问题,但这是一种与此初始技术非常不同的方法。“这是一种与此初始技术非常不同的方法。”-实际上,这并没有改变太多原始方式,只需使用
    document.addSignature(签名,选项)
    而不是
    文档。添加签名(签名)
    <这里的代码>选项需要是一个SignatureOptions`实例,在该实例中,您将PreferredSignatureSize设置为足够高的值……您有完整的示例吗?