使用iText-2.1.7为PDF添加签名后提示文档被篡改的问题排查
错误含义解释
“Document has been altered or corrupted since it was signed” 意味着Adobe Acrobat在验证PDF签名时,发现当前文档的实际内容哈希值与签名嵌入的哈希值不匹配,判定文档签名后被篡改或签名过程本身存在错误导致验证失败。
问题定位与修复方案
你的代码核心问题在于PKCS7结构生成时传递了错误的哈希值,导致签名验证时哈希不匹配。以下是具体修复步骤:
1. 修正getEncodedPKCS7的参数传递
原代码中调用sgn.getEncodedPKCS7(signedHash, appearance.getSignDate())时,错误地将签名后的signedHash作为第一个参数传入,而该方法需要的是原始文档内容的哈希值(即appeareanceHash)。
将该行代码修改为:
val encodedPKCS7 = sgn.getEncodedPKCS7(appeareanceHash, appearance.getSignDate())
2. 验证其他潜在问题(可选)
- 确认
KalkanProvider正确注册且支持SHA256和SHA256withRSA算法,避免因算法支持问题导致签名生成错误。 - 检查
estimatedSize设置是否足够:8192字节对于大多数PKCS7签名已经足够,若签名过大可适当调整(如16384),确保填充后的签名长度不超过预留的空间。 - 确认
CryptUtils中的证书链、私钥、证书均有效且匹配,避免因密钥/证书问题导致签名无效。
修复后的完整代码
def postProcessPdf(pdf: Array[Byte], os: OutputStream): Unit = { val reader = new PdfReader(pdf) Security.addProvider(new KalkanProvider) val stamper = PdfStamper.createSignature(reader, os, '\u0000') val appearance = stamper.getSignatureAppearance val signDate = Calendar.getInstance val pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED) pdfSignature.setDate(new PdfDate(signDate)) pdfSignature.setCert(CryptUtils.cert.getEncoded) appearance.setCryptoDictionary(pdfSignature) appearance.setCrypto(null, CryptUtils.chain, null, PdfSignatureAppearance.WINCER_SIGNED) appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED) val estimatedSize = 8192 val exc = new HashMap[PdfName, Int]() exc.put(PdfName.CONTENTS, estimatedSize * 2 + 2) appearance.preClose(exc) val data = appearance.getRangeStream() val sgn = new PdfPKCS7(null, CryptUtils.chain, null, "SHA256", null, false) val digest = MessageDigest.getInstance("SHA256","KALKAN") val dataBytes = IOUtils.toByteArray(data) digest.update(dataBytes) val appeareanceHash = digest.digest() val hashToSign = sgn.getAuthenticatedAttributeBytes(appeareanceHash, appearance.getSignDate(), null) val signature = Signature.getInstance("SHA256withRSA","KALKAN") signature.initSign(CryptUtils.privateKey) signature.update(hashToSign) val signedHash = signature.sign() sgn.setExternalDigest(signedHash,null,"RSA") // 修正此处的参数,传入文档哈希appeareanceHash而非签名后的signedHash val encodedPKCS7 = sgn.getEncodedPKCS7(appeareanceHash, appearance.getSignDate()) val paddedSig = new Array[Byte](estimatedSize) System.arraycopy(encodedPKCS7, 0, paddedSig, 0, encodedPKCS7.length) val dic = new PdfDictionary() dic.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true)) appearance.close(dic) }
内容的提问来源于stack exchange,提问作者superkuzet
相关产品推荐
相关产品推荐

