将新页面添加到PDF并使用iText 7创建签名

鑫达

对于一个项目,我必须在工作流程中由多个人在另外创建的页面上对PDF进行数字签名。为了实现这一点,我们基于Bruno Lowagie的示例,使用带有以下代码的iText 7库:

public static void main(String[] args) throws IOException, GeneralSecurityException, XMPException {
    String path = "F:/Java/keystores/testPdfSign";
    char[] pass = "test".toCharArray();

    KeyStore ks = KeyStore.getInstance("pkcs12", "SunJSSE");
    ks.load(new FileInputStream(path), pass);
    String alias = "";
    Enumeration<String> aliases = ks.aliases();
    while (alias.equals("tester")==false && aliases.hasMoreElements()) 
    {
        alias = aliases.nextElement();
    }
    PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);
    Certificate[] chain = ks.getCertificateChain(alias);
    PDFSign app = new PDFSign();
    app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA1, "SunJSSE", PdfSigner.CryptoStandard.CMS, "Test", "Test", null, null, null, 0);
}

public void sign(String src, String dest,
                 Certificate[] chain, PrivateKey pk,
                 String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
                 String reason, String location,
                 Collection<ICrlClient> crlList,
                 IOcspClient ocspClient,
                 ITSAClient tsaClient,
                 int estimatedSize)
        throws GeneralSecurityException, IOException, XMPException {
    // Creating the reader and the signer

    PdfDocument document = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST+"_temp"));
    if (initial == true)
    {
        document.addNewPage();
    }
    int pageCount = document.getNumberOfPages();
    document.close();
    PdfSigner signer = new PdfSigner(new PdfReader(DEST+"_temp"), new FileOutputStream(DEST), true); 
    // Creating the appearance
    if (initial == true)
    {
        signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
    }
    PdfSignatureAppearance appearance = signer.getSignatureAppearance()
            .setReason(reason)
            .setLocation(location)
            .setReuseAppearance(false);
    Rectangle rect = new Rectangle(10, 400, 100, 100);
    appearance
            .setPageRect(rect)
            .setPageNumber(pageCount);
    appearance.setRenderingMode(RenderingMode.NAME_AND_DESCRIPTION);
    signer.setFieldName(signer.getNewSigFieldName());
    // Creating the signature
    IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
    ProviderDigest digest = new ProviderDigest(provider);
    signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);

}

这会导致PDF的新签名版本中的签名无效,因为Adobe Acrobat Reader表示在签名后已对其进行了编辑。出乎意料的是,当我在Foxit Reader中打开文件时,它说它没有被修改并且是有效的。

另外,我尝试的操作是省去了添加新页面的第一步,而是仅在原始文档的最后一页上签名,然后该签名在Adobe Reader中有效,但对我的情况没有解决方案,因为额外的页面是一定有。我尝试的另一件事不是将certificateLevel设置为CERTIFIED_FORM_FILLING_AND_ANNOTATIONS,而是将其保留为default NOT_CERTIFIED,这样我在新页面上也具有有效的签名,但这也不是解决方案,因为它不会让我添加任何内容稍后还会有其他签名。

有人知道Adobe Reader将签名评级为无效和/或对此问题有解决方案的原因是什么?

提前致谢

大卫

mkl

简而言之

我无法复制OP的问题。运行他的代码(略微适应当地情况)导致java.security.NoSuchAlgorithmException: no such algorithm: SHA1 for provider SunJSSEsign另一方面,在调用程序的提供程序参数“ SunJSSE”替换为“ BC”之后,该代码将创建经过正确认证的PDF。

改编的代码

我通常以JUnit测试的形式检查stackoverflow中的代码。这意味着要进行一些更改。此外,OP的代码包含许多已引用但未定义的变量。这些必须给一个定义。最后,我加载文件以从资源作为流签名,而不是从文件系统作为文件签名。

因此:

final static File RESULT_FOLDER = new File("target/test-outputs", "signature");

@BeforeClass
public static void setUpBeforeClass() throws Exception
{
    RESULT_FOLDER.mkdirs();
    BouncyCastleProvider provider = new BouncyCastleProvider();
    Security.addProvider(provider);
}

@Test
public void testSignLikeXinDHA() throws GeneralSecurityException, IOException, XMPException
{
    String path = "keystores/demo-rsa2048.p12";
    char[] pass = "demo-rsa2048".toCharArray();

    KeyStore ks = KeyStore.getInstance("pkcs12", "SunJSSE");
    ks.load(new FileInputStream(path), pass);
    String alias = "";
    Enumeration<String> aliases = ks.aliases();
    while (alias.equals("demo") == false && aliases.hasMoreElements())
    {
        alias = aliases.nextElement();
    }
    PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);
    Certificate[] chain = ks.getCertificateChain(alias);

    try ( InputStream resource = getClass().getResourceAsStream("/mkl/testarea/itext7/content/test.pdf"))
    {
        sign(resource, new File(RESULT_FOLDER, "test_XinDHA_signed_initial.pdf").getAbsolutePath(),
                chain, pk, DigestAlgorithms.SHA1, /*"SunJSSE"*/"BC", PdfSigner.CryptoStandard.CMS, "Test", "Test",
                null, null, null, 0, true);
    }
}

public void sign(InputStream src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
        String provider, PdfSigner.CryptoStandard subfilter, String reason, String location,
        Collection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize,
        boolean initial)
        throws GeneralSecurityException, IOException, XMPException
{
    // Creating the reader and the signer

    PdfDocument document = new PdfDocument(new PdfReader(src), new PdfWriter(dest + "_temp"));
    if (initial == true)
    {
        document.addNewPage();
    }
    int pageCount = document.getNumberOfPages();
    document.close();
    PdfSigner signer = new PdfSigner(new PdfReader(dest + "_temp"), new FileOutputStream(dest), true);
    // Creating the appearance
    if (initial == true)
    {
        signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
    }
    PdfSignatureAppearance appearance = signer.getSignatureAppearance().setReason(reason).setLocation(location)
            .setReuseAppearance(false);
    Rectangle rect = new Rectangle(10, 400, 100, 100);
    appearance.setPageRect(rect).setPageNumber(pageCount);
    appearance.setRenderingMode(RenderingMode.NAME_AND_DESCRIPTION);
    signer.setFieldName(signer.getNewSigFieldName());
    // Creating the signature
    IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
    ProviderDigest digest = new ProviderDigest(provider);
    signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}

AddPageAndSign.java

运行代码

我用一个相当新的Oracle的Java 8无限强度运行的Java代码TM密码系统扩展策略文件,BouncyCastle的1.49,和iText的无论是在版本7.0.0或7.0.1-快照(当前开发分支)。

(一定要使用从其网站下载的Oracle Java,Oracle JDK的某些变体(由某些Linux发行版提供)包含安全提供程序中的更改,这些更改可能会破坏您的代码。)

使用提供程序参数“ SunJSSE”运行代码会sign导致以下结果:

java.security.NoSuchAlgorithmException: no such algorithm: SHA1 for provider SunJSSE
    at sun.security.jca.GetInstance.getService(GetInstance.java:87)
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
    at java.security.Security.getImpl(Security.java:698)
    at java.security.MessageDigest.getInstance(MessageDigest.java:227)
    at com.itextpdf.signatures.SignUtils.getMessageDigest(SignUtils.java:134)
    at com.itextpdf.signatures.DigestAlgorithms.getMessageDigest(DigestAlgorithms.java:182)
    at com.itextpdf.signatures.ProviderDigest.getMessageDigest(ProviderDigest.java:69)
    at com.itextpdf.signatures.SignUtils.getMessageDigest(SignUtils.java:127)
    at com.itextpdf.signatures.PdfSigner.signDetached(PdfSigner.java:528)
    at mkl.testarea.itext7.signature.AddPageAndSign.sign(AddPageAndSign.java:125)
    at mkl.testarea.itext7.signature.AddPageAndSign.testSignLikeXinDHA(AddPageAndSign.java:81)

使用提供者参数“ BC”来sign调用代码来运行代码会生成经过正确认证的PDF,并在额外的页面上显示签名可视化:

签名面板的屏幕截图

为什么使用SunJSSE没有意义

实际上,使用“ SunJSSE”提供程序获得的异常不足为奇,因为该提供程序未提供SHA1算法。

根据Oracle的文档,它根本不提供MessageDigest算法,而只是结合了签名算法(SHA1withRSA)。

因此,IExternalSignature定义sign

IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);

将起作用,因为此处将使用SHA1withRSA,但在ProviderDigest那里定义为

ProviderDigest digest = new ProviderDigest(provider);

将失败,因为它尝试使用消息摘要算法SHA1。

作为旁白

您使用SHA1。由于此消息摘要算法在签名创建的上下文中越来越受信任,所以这不是一个好主意。我建议切换到SHA2 famaily的算法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用itext将签名添加到pdf

来自分类Dev

使用 IText7 将 SVG 图像添加到 PDF

来自分类Dev

使用itextsharp将新页面和标签添加到新的pdf文档中

来自分类Dev

使用xmlworker创建PDF时新页面中的内容

来自分类Dev

使用adbe.pkcs7.detached创建签名的PDF

来自分类Dev

将新页面中的图像添加到现有的PDF文件中

来自分类Dev

使用.der-Certificate对文件签名并创建签名(pkcs#7)

来自分类Dev

使用itext将边框添加到pdf页面

来自分类Dev

JAVA-如何使用原始PDF和单独的PKCS#7签名数据创建签名PDF

来自分类Dev

如何使用带有 C# 的 itext7 将 u3d 添加到现有的 pdf 中

来自分类Dev

使用 itextsharp 检查添加元素是否会创建新页面

来自分类Dev

C# Docusign - 将签名元素添加到 PDF

来自分类Dev

点击图片并重定向到新页面,将点击图片动态添加到新页面?

来自分类Dev

使用php形式将记录添加到mysql数据库中,而无需离开/刷新页面

来自分类Dev

创建新页面时,如何访问DotNetNuke使用的模板?

来自分类Dev

如何使用 Tkinter 中的类创建新页面?

来自分类Dev

使用PHP为Apple Wallet通行证创建PKCS#7分离签名

来自分类Dev

使用.pfx证书封装,签名和创建PKCS#7 DER消息

来自分类Dev

在CentOS 7中使用GnuPG创建和发送自签名公钥

来自分类Dev

我可以使用pkcs11-tool创建pkcs#7签名吗?

来自分类Dev

使用充气城堡创建带有预签名数据的PKCS7

来自分类Dev

如何使用 PKCS 7 和 SHA 算法在 C# 中创建数字签名并验证它

来自分类Dev

如何将图像添加到使用Nreco PdfGenrator创建的PDF中

来自分类Dev

将图片(png文件)添加到使用R创建的pdf文件的标题中

来自分类Dev

如何将新页面添加到Android应用程序?

来自分类Dev

刷新页面,直到将新数据添加到数据库中

来自分类Dev

EPiServer 9-以编程方式将块添加到新页面

来自分类Dev

如何将word中的表格添加到新页面

来自分类Dev

动态创建pdf并使用itext对其进行签名

Related 相关文章

  1. 1

    使用itext将签名添加到pdf

  2. 2

    使用 IText7 将 SVG 图像添加到 PDF

  3. 3

    使用itextsharp将新页面和标签添加到新的pdf文档中

  4. 4

    使用xmlworker创建PDF时新页面中的内容

  5. 5

    使用adbe.pkcs7.detached创建签名的PDF

  6. 6

    将新页面中的图像添加到现有的PDF文件中

  7. 7

    使用.der-Certificate对文件签名并创建签名(pkcs#7)

  8. 8

    使用itext将边框添加到pdf页面

  9. 9

    JAVA-如何使用原始PDF和单独的PKCS#7签名数据创建签名PDF

  10. 10

    如何使用带有 C# 的 itext7 将 u3d 添加到现有的 pdf 中

  11. 11

    使用 itextsharp 检查添加元素是否会创建新页面

  12. 12

    C# Docusign - 将签名元素添加到 PDF

  13. 13

    点击图片并重定向到新页面,将点击图片动态添加到新页面?

  14. 14

    使用php形式将记录添加到mysql数据库中,而无需离开/刷新页面

  15. 15

    创建新页面时,如何访问DotNetNuke使用的模板?

  16. 16

    如何使用 Tkinter 中的类创建新页面?

  17. 17

    使用PHP为Apple Wallet通行证创建PKCS#7分离签名

  18. 18

    使用.pfx证书封装,签名和创建PKCS#7 DER消息

  19. 19

    在CentOS 7中使用GnuPG创建和发送自签名公钥

  20. 20

    我可以使用pkcs11-tool创建pkcs#7签名吗?

  21. 21

    使用充气城堡创建带有预签名数据的PKCS7

  22. 22

    如何使用 PKCS 7 和 SHA 算法在 C# 中创建数字签名并验证它

  23. 23

    如何将图像添加到使用Nreco PdfGenrator创建的PDF中

  24. 24

    将图片(png文件)添加到使用R创建的pdf文件的标题中

  25. 25

    如何将新页面添加到Android应用程序?

  26. 26

    刷新页面,直到将新数据添加到数据库中

  27. 27

    EPiServer 9-以编程方式将块添加到新页面

  28. 28

    如何将word中的表格添加到新页面

  29. 29

    动态创建pdf并使用itext对其进行签名

热门标签

归档