“自签名应用以来,文档已被更改或损坏”使用itext将签名应用于pdf后出现错误

时间:2014-07-20 03:01:40

标签: java pdf itext digital-signature

我收到错误“当签名应用于使用itext的pdf时,文档已被更改或损坏,因为签名已被应用。”

生成数字签名的pdf但绿色复选标记未到来。要获得绿色复选标记,必须采取哪些措施。

现在它说签名是无效的。

我使用以下链接作为参考 http://itextpdf.com/examples/iia.php?id=222

我使用以下代码使用iText应用签名。

    String path = "resources/examplestore";
    String keystore_password = "password";
    String key_password = "password";
    String alias = "signFiles";
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(path), keystore_password.toCharArray());
    PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
    Certificate[] chain = ks.getCertificateChain(alias);
    String path = "resources/examplestore";
    String keystore_password = "password";
    String key_password = "password";
    String alias = "signFiles";
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(path), keystore_password.toCharArray());
    PrivateKey pk = (PrivateKey) ks.getKey(alias, key_password.toCharArray());
    Certificate[] chain = ks.getCertificateChain(alias);

    PdfReader reader = new PdfReader(src);
    FileOutputStream os = new FileOutputStream(dest);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);

    PdfSignatureAppearance appearance = stamper
            .getSignatureAppearance();
    appearance.setReason("I'm approving this.");
    appearance.setLocation("Foobar");
    appearance.setVisibleSignature(new Rectangle(160, 732, 232, 780), 1, "second");

    ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
    ExternalDigest digest = new BouncyCastleDigest();
    MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);

    I also Verify the code after this.

1 个答案:

答案 0 :(得分:1)

我在这个答案中并不完全确定,因为我几乎不需要处理DSA签名,通常我必须处理RSA或ECDSA签名。

HASH值正常。

在看到“自签名被应用以来文档已被更改或损坏”消息时的第一个假设是实际文档散列与签名中包含的文档散列不同。 (更改文档会产生这样的差异。)但是,对于文档,签名的签名属性messageDigest中的HASH值是正确的。

因此,问题在于签名本身。

一个非常明显的特点是使用的签名算法:

1071 06    7:             OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
            :               (ANSI X9.57 algorithm)
    <05 00>
1080 05    0:             NULL
            :             }

这是特殊的,因为签名算法需要包括HASH算法以允许验证,例如,

The algorithm identifier for DSA with SHA-1 signature values is:

  id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
      us(840) x9-57 (10040) x9cm(4) 3 }
  

RFC 3370 section 3.1 DSA

When SHA-224 is used, the OID is:

id-dsa-with-sha224 OBJECT IDENTIFIER  ::=  { joint-iso-ccitt(2)
   country(16) us(840) organization(1) gov(101) csor(3)
   algorithms(4) id-dsa-with-sha2(3) 1 }.

When SHA-256 is used, the OID is:

id-dsa-with-sha256 OBJECT IDENTIFIER  ::=  { joint-iso-ccitt(2)
   country(16) us(840) organization(1) gov(101) csor(3)
   algorithms(4) id-dsa-with-sha2(3) 2 }.
  

RFC 5758 section 3.1 DSA Signature Algorithm

在旧的SMIME规范中,使用id-dsa而不是id-dsa-with-XXX被解释为id-dsa-with-sha1。

因此,如果在验证期间,您的签名中的算法标识符完全被接受,则它被解释为已在SHA1的上下文中使用;但是,您的代码(我假设签名firstsecond的签名代码在这方面是一致的),包含:

ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");

即。你的代码哈希使用SHA-256。因此,您的签名将无法得到正面验证。

问题

背景问题是,DSA签名的com.itextpdf.text.pdf.security.PdfPKCS7.setExternalDigest(byte[], byte[], String)仅在digestEncryptionAlgorithmOid中存储id-dsa OID,PdfPKCS7.getEncodedPKCS7(byte[], Calendar, TSAClient, byte[], Collection<byte[]>, CryptoStandard)使用digestEncryptionAlgorithmOid作为签名算法OID。

因此,对于所有DSA签名,id-dsa用作签名算法,即使它实际上根本不应该使用,如果使用它意味着SHA-1。

PS:在签名算法中不包括HASH算法的RSA签名的情况下,值没有问题,因为RSA签名实际上是提到所使用的HASH算法的编码结构。另一方面,DSA不是关于解码而是关于检查,所以没有任何隐含的HASH算法。