使用 iText 的 Java PDF 数字签名可见,但不可打印

标签 java pdf itext certificate digital-signature

我正在使用 iText 的方法使用数字证书对 PDF 进行签名,并使用 PdfSignatureAppearance 生成文档中可见的签名,但我希望可见的签名不要打印出来。我看到 PdfAnnotation 类中有类似的东西,您可以在其中为此添加一个标志。有没有办法用数字签名来做到这一点? 我的代码:

PdfStamper stp = null;
try {
    PdfReader reader = new PdfReader(pdfInputFileName);

    stp = PdfStamper.createSignature(reader, fout, '\0');
    PdfSignatureAppearance sap = stp.getSignatureAppearance();

    sap.setCrypto(privateKey, certificateChain, null, PdfSignatureAppearance.WINCER_SIGNED);

    sap.setReason(reason);
    sap.setLocation(location);
    sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    sap.setVisibleSignature(new Rectangle(30, 830, 170, 770), 1, null);

    stp.close();

} catch (DocumentException | IOException e) {

    logger.error("An unknown error accoured while signing the PDF file: " + e.getMessage());
}

这是由该代码签名的 PDF 的链接,当我打印它时,签名印章总是出现在打印中: https://s3.amazonaws.com/gxzadminlocal/anexo_28276.pdf

最佳答案

如果签名字段尚不存在并且必须创建它,当前的 iText 5 版本会自动设置 PRINT 标志。但是,如果您填写现有的签名字段,则该标志不会受到影响。因此,您可能希望在第一步中添加一个没有 PRINT 标志的空签名字段,并在第二步中使用该字段进行签名,例如使用以下代码:

准备 PDF

您可以准备一个带有空签名字段的 PDF 而无需设置 PRINT 标志,如下所示:

try (   InputStream resource = SOURCE_STREAM;
        OutputStream os = INTERMEDIATE_OUTPUT_STREAM) {
    PdfReader reader = new PdfReader(resource);
    PdfStamper stamper = new PdfStamper(reader, os);
    PdfFormField field = PdfFormField.createSignature(stamper.getWriter());
    field.setFieldName("Signature");
    field.setWidget(new Rectangle(30, 830, 170, 770), PdfAnnotation.HIGHLIGHT_NONE);
    stamper.addAnnotation(field, 1);
    stamper.close();
}

( CreateSignature 测试 signWidgetNoPrint 通过 1)

特别是你不这样做

field.setFlags(PdfAnnotation.FLAGS_PRINT);

这里!

签署准备好的 PDF

创建中间 PDF 后,您可以按如下方式对其进行签名:

try (   InputStream resource = INTERMEDIATE_INPUT_STREAM;
        OutputStream os = RESULT_STREAM) {
    PdfReader reader = new PdfReader(resource);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');

    PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
    appearance.setReason("reason");
    appearance.setLocation("location");
    appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    appearance.setVisibleSignature("Signature");

    ExternalSignature pks = new PrivateKeySignature(pk, "SHA512", "BC");
    ExternalDigest digest = new BouncyCastleDigest();
    MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
}

( CreateSignature 测试 signWidgetNoPrint 通过 2)

假设您已在pk中准备好私钥,在chain中准备好证书链;并假设您已将 Bouncy CaSTLe 注册为安全提供商。

在结果 PDF 中,签名可视化显示在屏幕上,但不会打印出来。

关于使用 iText 的 Java PDF 数字签名可见,但不可打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53193048/

相关文章:

java - Apache Camel 与 Kafka Producer 的内存泄漏

java - 如何从 Activity 的弹出菜单中选择回收者 View 的复选框?

java - 将(服务器端)一组 PDF 文档合并到 JAVA 中的一个大 PDF 文档的最简单方法是什么

image - grails-访问 Controller 中的图像以在pdf中使用

java - 使用 RtfWriter2 时将页脚打印为第 X 页,共 Y 页

c# - 在 pdf 文件中搜索文本,如果文本存在则返回坐标

java - Spring PDF 生成 + i18n

java - Java Web 服务中使用的 url 保存在哪里?

java - AtomicInteger 是否处理同步?

javascript - 从 iframe 创建 PDF 文件