我不明白为什么getRangeStream()返回的inputStream在同一文件的每次代码迭代时都不同。通常,它应该返回“使用外部签名时可以清除的文档字节”,这对我来说意味着对于相同的输入文件,应该返回相同的字节数组。但它不是......
PdfReader pdfReader = new PdfReader(new FileInputStream(inPdfFile), null);
AcroFields acroFields = pdfReader.getAcroFields();
boolean hasSignature = acroFields.getSignatureNames().size() > 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfStamper pdfStamper = PdfStamper.createSignature(pdfReader, byteArrayOutputStream, '\0', null, hasSignature);
pdfStamper.setXmpMetadata(pdfReader.getMetadata());
PdfSignatureAppearance pdfSignatureAppearance = pdfStamper.getSignatureAppearance();
PdfSignature pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
pdfSignature.setReason("reason");
pdfSignature.setLocation("location");
pdfSignature.setContact("contact");
pdfSignatureAppearance.setCryptoDictionary(pdfSignature);
// certify the pdf, if requested
/* if (certificationLevel > 0) {
// check: at most one certification per pdf is allowed
if (pdfReader.getCertificationLevel() != PdfSignatureAppearance.NOT_CERTIFIED)
throw new Exception("Could not apply -certlevel option. At most one certification per pdf is allowed, but source pdf contained already a certification.");
pdfSignatureAppearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
}*/
pdfSignatureAppearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(30000 * 2 + 2));
pdfSignatureAppearance.preClose(exc);
InputStream rangeStream = pdfSignatureAppearance.getRangeStream();
集成的pdf签名不是简单地附加到现有的pdf,而是签名表单字段的值(以及一些元信息)。并且可互操作的这种签名必须签署除签名字段值中为其保留的空间之外的所有内容。
因此,每当您尝试签署现有的pdf时,通常都必须做好准备:如果pdf中还没有表单结构,则必须添加表单结构。如果还没有空的签名表单字段,则必须添加这样的表单字段。并且必须准备签名值,特别是签名时间。
无论何时创建或更新pdf,都会生成ID,确定创建或修改时间,并将这些数据添加到创建/更新的pdf中。
因此,每次运行中的代码都会操作源pdf,因此生成的pdf具有不同的ID,修改时间和签名时间。由于签名标志着除了它的占位符之外的所有东西,它也标志着这些可变数据。
因此,哈希在每次运行中都有所不同。
有关更多详细信息,请阅读this answer及其中引用的文章。