【发布时间】:2023-02-06 13:42:30
【问题描述】:
我想签署已经包含签名字段的 PDF。我需要添加新的签名字段以保留现有的未签名签名字段。签署此类 PDF 后,我看到代码添加的新签名字段始终无效。说“文件已被更改”。
以下代码用于计算文档的哈希值:
private DocumentSignatureStructure createSignatureStructureAndComputeHash(byte[] inputFile, File tempFile,
SignatureProperties sigProperties)
throws IOException, NoSuchAlgorithmException {
try (FileOutputStream fos = new FileOutputStream(tempFile);
PDDocument doc = PDDocument.load(inputFile);
SignatureOptions signatureOptions = new SignatureOptions();) {
signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
signatureOptions.setPage(sigProperties.getPage() - 1);
if (sigProperties.isVisibleSignature()) {
PDRectangle rect = createSignatureRectangle(doc, sigProperties);
signatureOptions.setVisualSignature(createVisualSignatureTemplate(doc, rect, sigProperties));
}
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setSignDate(Calendar.getInstance());
doc.addSignature(signature, signatureOptions);
ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
MessageDigest digest = MessageDigest.getInstance(sigProperties.getHashAlgorithm().getAlgoName());
byte[] hashBytes = digest.digest(IOUtils.toByteArray(externalSigning.getContent()));
String base64Hash = Base64.toBase64String(hashBytes);
externalSigning.setSignature(new byte[0]);
int offset = signature.getByteRange()[1] + 1;
IOUtils.closeQuietly(signatureOptions);
return DocumentSignatureStructure.builder().offset(offset)
.hashValue(base64Hash)
.build();
}
}
嵌入签名代码:
byte[] originalDocumentByte = docBlob.getBytes(1L, (int) docBlob.length());
File file = new File(getTempFolderPath(), getTempFileName("signed"));
try (FileOutputStream fos = new FileOutputStream(file);) {
fos.write(originalDocumentByte);
}
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
raf.seek(documentSignatureStructure.getOffset());
raf.write(Hex.getBytes(Base64.decode(encodedSignature)));
}
Blob signedAndLtvBlob;
try (PDDocument doc = PDDocument.load(file);
FileOutputStream fos = new FileOutputStream(file);
FileInputStream fis = new FileInputStream(file)) {
if (createDss) {
log.info("Adding revocation information to DSS dictionary of PDF");
makeLtv(doc, revocationData);
}
doc.saveIncremental(fos);
}
它不适用于上面的代码。
在谷歌上搜索,发现很少有 COSObject 'NeedToBeUpdated' 标志需要设置为 true 的解决方案。 在上面的代码中添加新的签名字段之前添加了下面的代码块。
//..
if (sigProperties.isVisibleSignature()) {
PDRectangle rect = createSignatureRectangle(doc, sigProperties);
signatureOptions.setVisualSignature(createVisualSignatureTemplate(doc, rect, sigProperties));
}
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
COSDictionary catalogDictionary = doc.getDocumentCatalog().getCOSObject();
catalogDictionary.setNeedToBeUpdated(true);
COSDictionary acroFormDictionary = (COSDictionary) catalogDictionary.getDictionaryObject(COSName.ACRO_FORM);
acroFormDictionary.setNeedToBeUpdated(true);
COSArray array = (COSArray) acroFormDictionary.getDictionaryObject(COSName.FIELDS);
array.setNeedToBeUpdated(true);
for (PDField field : acroForm.getFieldTree()) {
if (field instanceof PDSignatureField) {
COSDictionary fieldDictionary = field.getCOSObject();
COSDictionary dictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.AP);
dictionary.setNeedToBeUpdated(true);
COSStream stream = (COSStream) dictionary.getDictionaryObject(COSName.N);
stream.setNeedToBeUpdated(true);
while (fieldDictionary != null)
{
fieldDictionary.setNeedToBeUpdated(true);
fieldDictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.PARENT);
}
}
}
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
//..
即使这样也行不通。
我在这里缺少的是什么?
PDF文件:https://drive.google.com/file/d/1-vu9_WIfFo198v6AxoBMxCuyX1rE2FOS/view?usp=share_link
签名PDF(无效):https://drive.google.com/file/d/1DD0aKVkonH9a_CfGrj9mACe6DBt4Ijsj/view?usp=share_link
【问题讨论】:
-
请分享一个像这样签名的示例 PDF 以供分析。
-
@mkl 共享 PDF
-
谢谢,但是你能分享一下PDF吗签名无效进行分析。
-
@mkl 添加了签名 PDF
-
谢谢@mkl。我在错误的地方寻找解决方案,因为它与流用于读取和写入文件数据的方式有关。签名现在有效。谢谢。