如何使用 iText 在所有文档页面中显示数字 PDF 签名?

2023-12-25

我已经研究数字签名功能几天了,现在一切正常,是时候尝试在所有页面上打印邮票了,但我做得不太好......

试图给出一个快速的简历,以显示邮票我所做的是创建 PdfStamper、PdfSignatureAppearance 和一个 Rectangle,然后调用

 appearance.setVisibleSignature(rectangle, 1, "SIGNATURE")

上面的第二个参数“1”是我想要显示图章的页码,现在可以为 1,因为我试图为了在其他页面中显示图章而创建 PdfStamper、PdfSignatureAppearance 和的其他实例一个矩形,但将其设置为第 2 页。如果它有效,我会将其放入循环中并不断更改页面参数。

但为什么没效果???好吧,在接近尾声时,我调用 MakeSignature 的方法,并且在参数中我必须传递我创建的外观之一,如果我多次调用它,则签名仅出现在与我传递给它的最后一个外观相关的页面上。

例如:

    MakeSignature.signDetached(appearance2, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
    MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);

印章将仅显示在第一页上。

也许我可以在这里得到一些帮助???

整个事情就是这样:

public String signPdfFirstTime(String src, String dest, PrivateKey pk, Certificate[] chain, String providerName, String conteudoBase64, X509Certificate cert, String alias) throws IOException, DocumentException, GeneralSecurityException
{
    byte[] conteudoBinario = Base64.decode(conteudoBase64);

    FileOutputStream fos = new FileOutputStream(path + File.separator + src);
    fos.write(conteudoBinario);
    fos.close();

    File f = new File(path + File.separator + src);
    FileInputStream in = new FileInputStream(f);
    PdfReader reader = new PdfReader(in);

    int qtypages = reader.getNumberOfPages(); 
    FileOutputStream os = new FileOutputStream(path + File.separator + dest);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
    // Creating the appearance
    PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
    Rectangle rectangle = new Rectangle(550, 50, 610, 500);// funciona vertical
    appearance.setVisibleSignature(rectangle, 1, "SIGNATURE");

    //Here I build a custom message...nothing relevant
    StringBuilder stampMessage = new StringBuilder();
    stampMessage.append("...");
    stampMessage.append(alias);
    stampMessage.append(" - ");
        // customize appearance layer 2 to display text vertically
    PdfTemplate layer2 = appearance.getLayer(2);
    layer2.transform(new AffineTransform(0, 1, -1, 0, rectangle.getWidth(), 0));
    Font font = new Font();
    font.setColor(BaseColor.BLACK);
    ColumnText ct2 = new ColumnText(layer2);
    ct2.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
    ct2.setSimpleColumn(new Phrase(stampMessage.toString(), font), 0, 0, rectangle.getHeight(), rectangle.getWidth(), 15, Element.ALIGN_LEFT);
    ct2.go();
    appearance.setCertificate(cert);

    //Here starts where I tried to make a second stamp to show in the page 2
    FileOutputStream fos2 = new FileOutputStream(path + File.separator + src);
    fos2.write(conteudoBinario);
    fos2.close();
    File f2 = new File(path + File.separator + src);
    FileInputStream in2 = new FileInputStream(f2);

    PdfReader reader2 = new PdfReader(in2);
    FileOutputStream os2 = new FileOutputStream(path + File.separator + dest);

    PdfStamper stamper2 = PdfStamper.createSignature(reader2, os2, '\0');
    // Creating the appearance
    PdfSignatureAppearance appearance2 = stamper2.getSignatureAppearance();

    Rectangle rectangle2 = new Rectangle(550, 50, 610, 500);// funciona vertical
    appearance2.setVisibleSignature(rectangle2, 3, "ASSINATURA2");

    //Cria a msg que aparece na estampa
    StringBuilder stampMessage2 = new StringBuilder();
    stampMessage2.append(" - ");

    PdfTemplate layer22 = appearance.getLayer(2);
    layer22.transform(new AffineTransform(0, 1, -1, 0, rectangle2.getWidth(), 0));
    Font font2 = new Font();
    font2.setColor(BaseColor.BLACK);
    ColumnText ct22 = new ColumnText(layer22);
    ct22.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
    ct22.setSimpleColumn(new Phrase(stampMessage2.toString(), font2), 0, 0, rectangle2.getHeight(), rectangle2.getWidth(), 15, Element.ALIGN_LEFT);
    ct22.go();
    appearance2.setCertificate(cert);

    // Creating the signature
    ExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, providerName);
    ExternalDigest digest = new BouncyCastleDigest();
    List<CrlClient> crlList = new ArrayList<CrlClient>();
    crlList.add(new CrlClientOnline());

    LtvVerification v = stamper.getLtvVerification();
    LtvVerification v2 = stamper2.getLtvVerification();

    OcspClient ocspClient = new OcspClientBouncyCastle();

    String url = CertificateUtil.getCRLURL(cert);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    X509CRL crl = (X509CRL) cf.generateCRL(new URL(url).openStream());
    System.out.println("CRL valid until: " + crl.getNextUpdate());
    System.out.println("Certificate revoked: " + crl.isRevoked(chain[0]));

    if (crl.isRevoked(chain[0])) {

        throw new GeneralSecurityException("CERTIFICADO REVOGADO!");
    }
    else {
        MakeSignature.processCrl(cert, crlList);

        MakeSignature.signDetached(appearance2, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
        MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
        os.close();
        byte[] b = this.read(f);
        return Base64.encodeBytes(b);
    }
}

这实际上是对可用选项的讨论......

有一些根本不同的方法打印签名在所有页面上盖章:

  • 创建具有多个可视化效果的单个签名字段,每页一个。
  • 在单个页面上创建具有单个可视化的单个签名字段,例如最后一个文档页面,并在所有其他页面上创建具有相同内容的图像。
  • 每页创建一个签名字段,每个签名字段在其页面上都有一个可视化效果。

PDF 签名字段的“可视化”是与该字段直接关联的小部件;特别是,可以单击它们来打开签名验证对话框。与这些小部件相比,第二个选项中的“图像”只是没有此类关联操作的图像。

单一签名,多重可视化

这很可能是 OP 心中的选择。特别是这是更好的选择,至少乍一看:

  • 在每个页面上,签名图像处于活动状态并允许打开签名验证对话框;
  • but still only one digital signature has to be created, which means
    • Adobe Reader 左侧签名面板上只有一个条目,
    • 仅需要验证一个签名容器(因此,没有明确的验证结果),并且
    • 私钥仅使用一次,因此不需要多次输入 PIN,并且在按签名付费的签名服务中,只需为一次签名事件付费。

但也有很多缺点:

  • 同一签名的多次可视化可能会对该签名的法律价值产生负面影响。

    因此,Adobe 多年前就决定不在其软件中创建具有多种可视化效果的签名字段,请参见。例如

    文档中签名的位置可能会影响其法律含义。为此原因, 签名字段绝不会引用多个注释。如果多个位置与一个 签名时,含义可能会变得模糊。

    (数字签名外观 http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/acrobat_digital_signature_appearances_v9.pdfAdobe Acrobat 版本 9 的白皮书,日期为 2008 年 5 月 5 日)

    例如。在德国,有关书面签名的管辖权垂直限制了签名者合法签署的文件部分,他通常不受签名下方书写的任何内容的法律约束。其他法律体系中也可能存在类似的管辖权。

    如果电子签名在签署的文档中具有可视化效果,则此类管辖权可能类似(或者至少必须付出很大的努力来解释差异)。如果同一签名有多个可视化,这可能意味着只有第一个可视化之前的所有内容都被视为已签名。

    (我不是律师,所以请不要考虑这个法律咨询。)

  • 由于此类潜在的法律问题,即将推出的 PDF 2.0 标准中的签名字段将只允许有一个小部件。因此,根据该标准,具有多个小部件的签名可能会被视为无效。

  • 现在 Adob​​e Reader 的签名面板已包含“签名所在的页面”,参见该屏幕截图的最后一行:

    该面板上没有关联条目(具有正确页码)的活动签名字段可能会受到彻底怀疑。

单个签名,最后一页上的单个可视化,其他页面上的非活动图像

在使用该选项的情况下,先前选项的缺点不适用或至少仅在较小程度上适用。特别是,如果单纯的图像与可视化略有不同,提示表明它们是副本,则最终的真实可视化可能会被视为绑定签名位置。

不过,此选项的主要缺点是,对于已签名的文档,不允许仅将图像添加到内容中。因此,此选项不能用于文档的第二个或第三个签名者,但 OP 表明该解决方案最终必须允许多个人签署文件.

人们可以考虑将这些图像添加为注释,而不是内容;对于某些类型的集成 PDF 签名,允许在签名后添加和删除注释。但是,如果允许添加这些注释,通常也允许在签名后再次删除它们,这使得这些签名图像非常不稳定。

多个签名(每页一个),每个签名一个可视化

此选项没有其他选项的缺点,因为每个可视化对应于不同的数字签名。因此,最后一份保证签名者受整个文件的法律约束。

但它确实有其自身的缺点:

  • 在验证过程中,所有这些签名都将得到验证。这可能意味着高资源要求,甚至更糟糕的模糊结果(如果某些验证失败而某些验证成功)。
  • Adobe Reader 签名面板上充满了条目。
  • 私钥会被多次使用,如果是按签名付费,签名服务会很昂贵,如果是 SSCD(特别是智能卡或令牌),可能需要多次输入 PIN,并且还需要相当长的时间

实施选项

iText 允许以相当直接的开箱即用方式实现第二个和第三个选项。

使用 iText 可以实现第一个选项,但需要使用低级 API 和 Java 反射,或者对 iText 进行一些修补。


不过,考虑到每个选项的问题,我建议完全不要这样做,在要签名的内容末尾签名是最不模糊的签名方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 iText 在所有文档页面中显示数字 PDF 签名? 的相关文章

  • Grails 3.x bootRun 失败

    我正在尝试在 grails 3 1 11 中运行一个项目 但出现错误 失败 构建失败并出现异常 什么地方出了错 任务 bootRun 执行失败 进程 命令 C Program Files Java jdk1 8 0 111 bin java
  • Java中反射是如何实现的?

    Java 7 语言规范很早就指出 本规范没有详细描述反射 我只是想知道 反射在Java中是如何实现的 我不是问它是如何使用的 我知道可能没有我正在寻找的具体答案 但任何信息将不胜感激 我在 Stackoverflow 上发现了这个 关于 C
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐