如何在签名后锁定PDF文档?
Adobe Acrobat可以在签署PDF文档后锁定该文档。这将更改文档权限,以便Acrobat不再提供对文档的再次签名或修改批注或表单的功能。这似乎是一个合理的行动,在一个文件被多个实体签署审查,并最终由负责人发布之后 iTextSharp还可以签署文档,还可以向已签署的文档添加更多签名。iTextSharp基本上也可以设置文档的权限,但不知何故,我无法让它设置与Acrobat X Pro相同的权限。我设置了以下权限:如何在签名后锁定PDF文档?,pdf,permissions,itextsharp,signing,Pdf,Permissions,Itextsharp,Signing,Adobe Acrobat可以在签署PDF文档后锁定该文档。这将更改文档权限,以便Acrobat不再提供对文档的再次签名或修改批注或表单的功能。这似乎是一个合理的行动,在一个文件被多个实体签署审查,并最终由负责人发布之后 iTextSharp还可以签署文档,还可以向已签署的文档添加更多签名。iTextSharp基本上也可以设置文档的权限,但不知何故,我无法让它设置与Acrobat X Pro相同的权限。我设置了以下权限: PdfWriter.ALLOW_COPY PdfWriter.ALLOW
- PdfWriter.ALLOW_COPY
- PdfWriter.ALLOW_降级_打印
- PdfWriter.ALLOW_打印
- PdfWriter.ALLOW_屏幕阅读器
- PdfWriter.ALLOW_程序集
- PdfWriter.ALLOW_FILL_
- PdfWriter.ALLOW_MODIFY_注释
- PdfWriter.ALLOW_MODIFY_内容
- 打印:允许(OK)
- 修改单据:不允许(确定)
- 组装:不允许(正常)
- 复制内容:允许(确定)
- 屏幕阅读器:允许(OK)
- 删除页面:允许(不确定)
- 注释:允许(不确定)
- 填写表格:允许(不允许)
- 标志:允许(不正常)
- 创建模板:允许(未知)
我进一步研究了这个问题,它似乎来自这里:权限只能通过PdfStamper.SetEncryption方法设置,作为其第四个参数。但是调用此方法并附加签名会导致以下DocumentException:“附加模式不支持更改加密状态。”我没有看到设置权限但不设置加密的方法。这就是问题所在吗?iTextSharp是否不支持实际可能的功能?如果您的用例只需要对未签名的PDF进行签名,那么锁定将很容易:您只需为
pdfsignaturepearance
对象设置CertificationLevel=certificated\u NO\u CHANGES\u ALLOWED
。但是你的用例是
将新签名字段中的新签名添加到现有PDF中,该PDF可能已签名,也可能未签名
解决方案有些困难:必须使用FieldMDP转换方法,而不是DocMDP转换方法(用于认证)。有关详细信息,请阅读,尤其是第12.8节
我试图一步完成这项工作,但不幸的是,iText在其当前状态(版本5.4.4)下只正确地支持现有字段中的锁字典
@Bruno为签名时在运行时创建的字段添加锁字典支持应该不会太困难
因此,这里有一个两步解决方案,首先添加一个带有锁定信息的空签名字段,然后对该字段进行签名。我是用Java实现的(我更熟悉Java),但移植到C#应该不会太难
正如您所看到的,在第二步对准备好的空签名字段进行签名时,没有什么特别的事情要做,iText会在引擎盖下应用锁
不过,这项功能仅在iText 5.3.2之后才可用,我还没有检查它何时完全移植到iTextSharp
对于测试运行(使用自签名测试证书,因此出现警告),我得到:
输入文件签名一次:
输出文件已签名两次并锁定:
您是否阅读过Bruno Lowagie(iText软件)的白皮书,特别是第2.5.5节签名后锁定字段和文档?相应的c#/iTextSharp示例可以在iTextSharp SVN存储库中找到。不,还没有。但它看起来足够好,所以我认为它将为我的问题提供一个答案。同时,我发现了如何使用认证签名,并将其与Acrobat的行为进行了比较。但是锁定是另一个用例。(Adobe的帮助翻译成德语是错误的,它自相矛盾,无法理解。这也无助于了解这件事。)难道这一章只是关于创建可以在Acrobat中签名的签名字段,而Acrobat又会在签名后添加锁吗?那不是我想做的。iText将直接添加签名,而不仅仅是一个字段。所以iText也是需要添加锁的人。好的,所以本质上你的代码必须像AdobeReader那样签名。这是可能的,但需要一些自己的编码。从开始阅读该文档开始,我就知道我无论如何都需要升级iText,关于数字签名,我已经做了很多改变。所以我可能不得不重写它。更新它需要一些时间。布鲁诺是谁?请注意,@回复在回答中不起作用。这是众所周知的,但如果读者是布鲁诺,它仍然是向读者发出信号的一种方式。我在这里向布鲁诺·洛瓦吉讲话。
// STEP 1 --- prepare a signature field with locking information
//
// Creating the reader and the stamper for adding the field
PdfReader reader = new PdfReader(SRC);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos, (char)0, true);
// adding the empty signature field
PdfFormField field = PdfFormField.createSignature(stamper.getWriter());
field.setFieldName("Signature");
field.put(PdfName.LOCK, stamper.getWriter().addToBody(new PdfSigLockDictionary(LockPermissions.NO_CHANGES_ALLOWED)).getIndirectReference());
field.setFlags(PdfAnnotation.FLAGS_PRINT);
field.setPage(1);
field.setWidget(new Rectangle(150, 250, 300, 401), PdfAnnotation.HIGHLIGHT_INVERT);
stamper.addAnnotation(field, 1);
// finishing the intermediate PDF
stamper.close();
reader.close();
// STEP 2 --- sign the prepared signature field, nothing special
//
// Creating the reader and the stamper for signing
reader = new PdfReader(baos.toByteArray());
FileOutputStream os = new FileOutputStream("target/test-outputs/test_signed-with-lock-field-2step.pdf");
stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason("reason");
appearance.setLocation("location");
appearance.setVisibleSignature("Signature");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, "BC");
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, CryptoStandard.CMS);