使用itext

时间:2016-10-07 14:04:44

标签: java itext digital-signature

我有一个带有多个签名的数字签名pdf。现在我想只删除其中一个签名。我正在使用itext。代码如下:

PdfReader reader = new PdfReader(src_path);

PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest_path));


         {
                AcroFields.Item item =        stamper.getAcroFields().getFieldItem(fieldname);

                ClearSignatureDictionary(item.getMerged(0));
                ClearSignatureDictionary(item.getWidget(0));
                ClearSignatureDictionary(item.getValue(0));
            }
        }

 private static void ClearSignatureDictionary(PdfDictionary dic)
  {
    dic.remove(PdfName.AP);
    dic.remove(PdfName.AS);
    dic.remove(PdfName.V);
    dic.remove(PdfName.DV);
    dic.remove(PdfName.SV);
    dic.remove(PdfName.FF);
    dic.put(PdfName.F, new PdfNumber(4));
 }

但是当我用删除的签名打开文档时,它在Acrobat阅读器上给出了以下错误 “至少有一个签​​名无效”

1 个答案:

答案 0 :(得分:2)

您无法从签名文档中的字典中删除密钥,并希望签名保持有效。您只能删除添加的最后一个签名。如果文档由多人签名,并且您要删除第一个签名,则所有后续签名都将被破坏。

此图片解释了原因:

enter image description here

此图像显示每个新的数字签名都保持原始字节不变。每个新签名都会添加新字节。 Rev1表示具有1个数字签名的文档的字节。 Rev2表示具有2个数字签名的文档的字节。第二个数字签名完全标志着Rev1。如果您删除第一个签名,则第二个签名将无效。

数字签名是一种特殊类型的表单字段。使用iText,您可以获得PDF的签名表单字段的名称,如下所示:

PdfReader reader = new PdfReader(path);
AcroFields fields = reader.getAcroFields();
ArrayList<String> names = fields.getSignatureNames();

您只能删除涵盖整个文档的签名,例如,如果我们有"sig1""sig2""sig3"(按此顺序添加),则只有{{1将返回true。

您可以获得这样的修订总数:fields.signatureCoversWholeDocument("sig3")以及类似的特定修订:fields.getTotalRevisions()(前提是有一个名为fields.getRevision("sig1")的签名字段。)< / p>

假设图像代表您的文档,并且您必须删除1个签名,那么您只能通过删除在修订版3(Rev3)中添加的所有字节来删除第三个签名。使用iText,这意味着返回修订版2(Rev2)。该修订是使用签名字段"sig1"签署的。 您可以像这样提取此修订:

sig2

文件FileOutputStream os = new FileOutputStream("revision2.pdf"); byte bb[] = new byte[1028]; InputStream ip = fields.extractRevision("sig2"); int n = 0; while ((n = ip.read(bb)) > 0) os.write(bb, 0, n); os.close(); ip.close(); 将是由revision2.pdf"sig1"签名的文件,不包含创建"sig2"时添加的字节。