将可见的电子签名添加到PDF

我知道这将是一个非常特殊的话题。 电子签名PDF远不是主流用例。 但是,我将其编写的原因有两个:第一,我认为它对真正需要它的人非常有用;第二,我认为随着eIDAS法规的普及,它将变得越来越普遍。电子签名在欧洲各地都得到认可(由于某些无聊的法律细节,现在还不完全正确 ,但无论如何)。

因此,用例是什么-首先,您必须使用数字签名对PDF进行电子签名(法律术语为“电子签名”,因此尽管它们不完全匹配,但我将互换使用它们-例如,任何电子应用于其他数据的数据可以看作是电子签名,其中数字签名是基于PKI的签名)。

其次,您可能希望在页面上实际显示签名,而不是让PDF阅读器识别签名并将其显示在侧面板上。 这是为什么? 因为人们习惯于在页面上看到签名,有些人可能坚持要使签名可见(真实的故事–我评论说,分离的签名“不是真正的电子签名,因为在页面上不可见”)。

现在,请注意我在“页面”上写了“页面”。 是的,电子文档没有页面-它是字节流。 因此,仅在最后一页上签名即可。 但是,人们还是习惯于对所有页面进行签名,因此他们希望电子签名在所有页面上都可见。

这使任务变得棘手– PDF可以在最后一页上有一个数字签名框,但效果很好。 因此,必须添加看起来像签名框的其他类型的批注,然后单击以打开签名面板(就像实际的签名框一样)。

我必须在这里介绍DSS ,这是欧盟委员会提供的一组很棒的组件 ,可用于签名和验证各种电子签名。 它是开源的,您可以随意使用。 部署演示应用程序 ,仅使用库。 它包括开箱即用的签名功能-只需检查PAdESServicePDFBoxSignatureService即可 。 它甚至还包括一次可视化签名的选项(在特定页面上)。

但是,它没有选择在多个页面上显示“图章”(图像)的选项。 这就是为什么我分叉并实现功能的原因。 我的大部分更改都在loadAndStampDocument(..)方法的PDFBoxSignatureService中。 如果要使用该功能,则可以从我的叉子中构建一个jar并将其使用(通过将适当的SignatureImageParameters传递给PAdESSErvice.sign(..)来定义签名的外观)。

为什么首先需要这样做? 因为当文档签名后,您将无法再对其进行修改,因为您将更改哈希。 但是,PDF具有增量更新,可以将其追加到文档中,从而具有较新的版本,而无需修改原始版本中的任何内容。 这样,签名仍然有效(原始签名的内容不会被修改),但是会添加新内容。 在我们的案例中,这些新内容是一些“注释”,它们表示图像和可打开区域,可打开签名面板(至少在Adobe Reader中)。 并且在添加签名框之前添加它们时,如果签名者不止一个,则第二个签名者的注释将在第一个签名之后添加。

可悲的是,PDFBox不支持该功能。 好吧,它几乎可以做到–下面的代码看起来很笨拙,花了一段时间才弄清楚应该确切地调用什么以及何时调用,但是仅需一个反射调用即可工作:

for (PDPage page : pdDocument.getPages()) {
        // reset existing annotations (needed in order to have the stamps added)
        page.setAnnotations(null);
    }
    // reset document outline (needed in order to have the stamps added)
    pdDocument.getDocumentCatalog().setDocumentOutline(null);
    List<PDAnnotation> annotations = addStamps(pdDocument, parameters);
			
    setDocumentId(parameters, pdDocument);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (COSWriter writer = new COSWriter(baos, new RandomAccessBuffer(pdfBytes))) {
        // force-add the annotations (wouldn't be saved in incremental updates otherwise)
        annotations.forEach(ann -> addObjectToWrite(writer, ann.getCOSObject()));
				
        // technically the same as saveIncremental but with more control
        writer.write(pdDocument);
    }
    pdDocument.close();
    pdDocument = PDDocument.load(baos.toByteArray());
    ...
}

private void addObjectToWrite(COSWriter writer, COSDictionary cosObject) {
    // the COSWriter does not expose the addObjectToWrite method, so we need reflection to add the annotations
    try {
        Method method = writer.getClass().getDeclaredMethod("addObjectToWrite", COSBase.class);
        method.setAccessible(true);
        method.invoke(writer, cosObject);
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

它的作用是–加载原始PDF,清除一些内部目录,将注释(图像)添加到所有页面,然后“强制添加注释”,因为“否则它们将不会保存在增量更新中”。 我希望PDFBox可以使其更加简单明了,但是暂时可行,并且不会使现有签名无效。

我希望这篇文章能为您介绍:

  • 具有法律约束力的电子签名的存在
  • DSS实用程序的存在
  • 用于PDF签名的PAdES标准
  • 如何在PDF文档中放置多个签名框

我希望随着时间的推移,这篇文章会越来越流行,因为越来越多的企业意识到他们可以使用电子签名。

翻译自: https://www.javacodegeeks.com/2018/02/adding-visible-electronic-signatures-pdfs.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值