英文:
Compare signed PDF with original (initial) PDF
问题
在使用 iText 对 PDF 文档进行签名后,现在我想要比较已签名文档与原始文档。
通常情况下,在删除签名后,我应该可以确保原始文档和签名文档相等。
如何实现这个目标?
更新 1:
以下是我目前使用的函数,它允许删除签名并检查两个 PDF 文档,但问题是返回值始终为 FALSE:
public static void main(String[] args) throws Exception, GeneralSecurityException, DocumentException {
testRemoveSignatureFromPDFSignedFirmaCerta();
File file1 = new File(SRC);
File file2 = new File(DEST_After_Delete);
boolean compare1and2 = FileUtils.contentEquals(file1, file2);
System.out.println("Are test1.txt and test2.txt the same? " + compare1and2);
}
public static void testRemoveSignatureFromPDFSignedFirmaCerta() throws IOException, GeneralSecurityException, DocumentException {
try (InputStream inputStream = new FileInputStream(DEST);
OutputStream outputStream = new FileOutputStream(new File(DEST_After_Delete))) {
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader reader = new PdfReader(inputStream, null);
AcroFields af = reader.getAcroFields();
ArrayList<String> names = af.getSignatureNames();
for (String name : names) {
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
PdfPKCS7 pk = af.verifySignature(name, provider.getName());
System.out.println("SignatureDate: " + pk.getSignDate());
System.out.println("Certificate: " + pk.getSigningCertificate());
System.out.println("Document modified: " + !pk.verify());
af.removeField(name);
}
PdfStamper stamper = new PdfStamper(reader, outputStream, '\0');
stamper.close();
}
}
这段代码用于删除签名并比较两个 PDF 文档。
英文:
After making a signature on a PDF document using iText, now I want to make a comparison between the signed document and the original document.
Normally I should have equality between the original document and the signed document (after deleting the signature I think).
How can i do that ?
UPDATE 1 :
here is the function I use for the moment which allows to delete the signature and after checking the two PDFs but the problem is that the return is always FALSE :
public static void main(String[] args) throws Exception,
GeneralSecurityException,
DocumentException {
testRemoveSignatureFromPDFSignedFirmaCerta();
File file1 = new File(SRC);
File file2 = new File(DEST_After_Delete);
boolean compare1and2 = FileUtils.contentEquals(file1, file2);
System.out.println("Are test1.txt and test2.txt the same? " +
compare1and2);
}
public static void testRemoveSignatureFromPDFSignedFirmaCerta() throws
IOException, GeneralSecurityException, DocumentException
{
try ( InputStream inputStream = new FileInputStream(DEST);
OutputStream outputStream = new FileOutputStream(new
File(DEST_After_Delete)))
{
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader reader = new PdfReader(inputStream, null);
AcroFields af = reader.getAcroFields();
ArrayList<String> names = af.getSignatureNames();
for (String name : names) {
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " +
af.signatureCoversWholeDocument(name));
PdfPKCS7 pk = af.verifySignature(name, provider.getName());
System.out.println("SignatureDate: " + pk.getSignDate());
System.out.println("Certificate: " + pk.getSigningCertificate());
System.out.println("Document modified: " + !pk.verify());
af.removeField(name);
}
PdfStamper stamper = new PdfStamper(reader, outputStream, '\0');
stamper.close();
}
}
答案1
得分: 1
这取决于情况。
在生成集成PDF签名时,通常首先准备PDF,方法如下:
- 选择一个现有的或添加一个新的空白签名字段;
- 向该字段添加一个值字典,包括一个最终嵌入签名容器的占位符;
- (可选)更新现有的或创建新的签名可视化效果;
- (可选)如果签名字段具有签名锁定字典,则将其他各种表单字段设置为只读;
- (可选)如果这些注释尚未具有外观效果,则创建并添加注释的外观效果,以便在签名后PDF的外观中没有可变性;
- (可选)进行其他任意更改,例如修复无效或可疑的PDF对象等。
保存了这个准备好的PDF后,您计算要签名的字节范围的哈希摘要(基本上除了前面提到的占位符之外的所有内容),然后本地创建或远程请求一个签名容器来签署该哈希值,最后将该签名容器嵌入到占位符中。
基本上有两种应用这些更改的方式:
- 可以完全保存新的PDF。在这种情况下,模拟原始PDF的对象可能会发生重大变化,它们在文档中的顺序可能会改变,压缩可能会改变,对象可能会被重新编号,等等等等。
- 更改附加到原始PDF作为增量更新。在这种情况下,文件的开头保持原始PDF的每个字节。
(如果使用iText应用签名:在iText中以增量更新的方式应用更改是通过使用附加模式来完成的。)
在前一种情况下,进行比较非常困难,特别是如果存在许多那些“任意其他更改”。此外,您不能期望通过删除签名来恢复原始PDF,因为它在内部可能仍然非常不同。我在这里没有容易实现的想法。
在后一种情况下,您可以轻松检查签名的文件是否确实基于未签名的文件,方法是测试签名的PDF文件是否以未签名的PDF文件的字节开头。然而,评估更改本身在这里也很困难。
英文:
It depends.
When generating integrated PDF signatures, you usually first prepare the PDF by
- selecting an existing or adding a new, empty signature field;
- adding a value dictionary to that field including a place holder for the signature container to embed eventually;
- (optionally) updating the existing or creating a new visualization for the signature;
- (optionally) rendering assorted other form fields read-only if the signature field has a signature lock dictionary;
- (optionally) creating and adding appearances to annotations if those annotations had no appearances yet, so there is no variability in the PDF appearance after signing; and
- (optionally) doing arbitrary other changes, e.g. repairs of invalid or questionable PDF objects etc.
Having saved this prepared PDF, you calculate the hash digest of the byte ranges to sign (essentially everything but the afore mentioned place holder), locally create or remotely request a signature container signing that hash value, and eventually you embed that signature container in the place holder.
There essentially are two ways to apply these changes:
- The PDF can be completely saved anew. In this case the objects modelling the original PDF may be substantially changed, their order in the document may change, compression may change, objects may be renumbered, etc etc etc.
- The changes are appended to the original PDF as an incremental update. In this case the start of the file remains the original PDF byte-by-byte.
(If the signature is applied with iText: applying changes as an incremental update in iText is done by using the append mode.)
In the former case a comparison is very difficult, in particular if there are lots of those "arbitrary other changes". Also you cannot expect to get back the original PDF by removing the signature, it may still be very different internally. I don't have an easy-to-implement idea here.
In the latter case you can easily check whether the signed file indeed is based on the unsigned one by testing whether as a file the signed PDF starts with the bytes of the unsigned one. An evaluation of the changes themselves, though, is difficult here, too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论