Pdfbox 签名 - saveIncremental 与 saveIncrementalForExternalSigning

SoT*_*SoT 6 java digital-signature pdfbox

我正在对 pdf 文件进行签名,但我有些担心。从 pdfbox 示例中,我看到了两种签署 pdf 的方法。第一个是:

document.saveIncremental(output);
Run Code Online (Sandbox Code Playgroud)

第二种方式:

ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());

if (isLateExternalSigning()) {
    // this saves the file with a 0 signature
    externalSigning.setSignature(new byte[0]);
    // remember the offset (add 1 because of "<")
    int offset = signature.getByteRange()[1] + 1;
    // now write the signature at the correct offset without any PDFBox methods
    RandomAccessFile raf = new RandomAccessFile(signedFile, "rw");
    raf.seek(offset);
    raf.write(Hex.getBytes(cmsSignature));
    raf.close();
} else {
    // set signature bytes received from the service and save the file
    externalSigning.setSignature(cmsSignature);
}
Run Code Online (Sandbox Code Playgroud)

saveIncremental和之间有什么区别saveIncrementalForExternalSigning?我的意思是这些方法的用例。

每种方法的目的是什么?

什么是“增量”?

什么是“外部签名”?是像政府这样的第三方吗?

mkl*_*mkl 6

什么是“增量”?

保存对 pdf 的更改时,有两种选择,一种可以保存全新的 pdf 文件,也可以将更改附加到原始文件(的副本)。后一种技术称为增量更新

再次签署已签名的 pdf 时,必须将新签名的添加内容作为增量更新应用,以防止现有签名无效:

具有多个签名的 pdf 草图

(有关背景和参考资料,请参阅此答案。)

因此,pdf 库还需要在增量更新中支持对 PDF 进行签名。

为了简单起见,PDFBox支持在增量更新中对 PDF 进行签名,因此已经以这种方式添加了第一个签名。

saveIncremental和之间有什么区别saveIncrementalForExternalSigning

saveIncremental

创建签名的 pdfsaveIncremental使用回调来生成签名容器:您在调用中选择的实现sign方法用于检索要签名的文档字节的签名容器。SignatureInterfacePDDocument.addSignaturesaveIncremental

在 pdfbox 签名示例中,该sign方法在 中实现CreateSignatureBase,并在 中设置为签名接口signPDF

saveIncrementalForExternalSigning

使用创建签名的 pdfsaveIncrementalForExternalSigning不需要SignatureInterface实现。相反,它返回一个ExternalSigningSupport对象,您可以从中检索要签名的数据 ( getContent),然后您可以创建一个签名容器,最终可以使用另一种ExternalSigningSupport方法 ( setSignature) 将其注入到 pdf 中。

到目前为止,这听起来只是支持不同编程模式偏好、回调与非回调、顺序的选项。

不过,这里还有一个附加选项,也称为延迟签名:您可以注入一个虚拟签名,而不是注入实际的签名容器:

externalSigning.setSignature(new byte[0]);
Run Code Online (Sandbox Code Playgroud)

并检索签名容器的占位符(十六进制编码)所在的位置:

int offset = signature.getByteRange()[1] + 1;
Run Code Online (Sandbox Code Playgroud)

因此,现在您可以计算要签名的哈希值,将文件和偏移量存储在数据库中,并调用某些签名服务,而无需将 pdf 保存在内存中。

最终您可以注入签名容器,如示例代码所示:

RandomAccessFile raf = new RandomAccessFile(signedFile, "rw");
raf.seek(offset);
raf.write(Hex.getBytes(cmsSignature));
raf.close();
Run Code Online (Sandbox Code Playgroud)

这些方法的用例

如上所述,乍一看,这两种方法仅支持不同的编程模式:回调和顺序。

不过,附加选项确实允许支持附加用例,在某些情况下特别方便:

  • 如果签名服务很慢,例如因为请求是批量收集和处理的或者因为等待第二个因素的确认。

  • 如果签名容器的检索和注入应在与 pdf 的准备不同的程序中进行,甚至可能在不同的计算机中进行。

什么是“外部签名”?是像政府这样的第三方吗?

这里的“外部”是指程序的执行。虽然回调感觉非常内部,但按顺序分离调用的感觉就不那么明显了,并且延迟签名可以被视为真正的外部

第三方签名服务(无论是政府还是非政府)都可以集成到任一架构中。根据他们的表现,延迟方法可能更可取。