You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PDFBox 2.x如何检测PDF文档签名后是否被篡改?

Hey there! Let's break down why PDFBox's ShowSignature.java isn't catching tampering from Adobe Illustrator, and how to fix it for your ETSI.CAdES.detached signatures. The core issue lies in how different tools modify signed PDFs and PDFBox's default validation behavior.

How to Detect Tampering for ETSI.CAdES.detached Signatures in PDFBox

First, let's clarify the behavior you're seeing:

  • When modifying with PDFBox, you're altering the signed byte range directly—both Adobe Reader and PDFBox catch this easily because it breaks the core cryptographic hash.
  • Adobe Illustrator might be modifying elements in "unsigned" incremental update areas, but Adobe Reader checks stricter structural integrity rules that ShowSignature.java doesn't enforce by default.

Step 1: Validate the Full CAdES Signature Chain

The default ShowSignature.java only checks basic cryptographic validity of the signature itself. For ETSI.CAdES.detached signatures, you need to verify the message digest attribute—this ensures the actual document content matches what was signed. Here's how to extend the validation with BouncyCastle (required for CMS/CAdES operations):

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureValidator;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ValidationResult;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.asn1.DEROctetString;

import java.io.File;
import java.security.cert.X509Certificate;
import java.util.Iterator;

public class EnhancedSignatureChecker {
    public static void main(String[] args) throws Exception {
        PDDocument document = PDDocument.load(new File("tampered-document.pdf"));
        PDSignature signature = document.getLastSignature();
        
        // Basic signature validation
        SignatureValidator validator = new SignatureValidator(signature);
        ValidationResult basicResult = validator.validate();
        if (basicResult.getStatus() != ValidationResult.Status.VALID) {
            System.out.println("Basic signature validation failed: " + basicResult.getStatus());
        }

        // Validate CAdES message digest (critical for tampering detection)
        CMSProcessableByteArray signedContent = new CMSProcessableByteArray(signature.getSignedContent());
        CMSSignedData cmsData = new CMSSignedData(signedContent, signature.getContents());
        SignerInformationStore signerStore = cmsData.getSignerInfos();
        
        Iterator<SignerInformation> signerIter = signerStore.getSigners().iterator();
        while (signerIter.hasNext()) {
            SignerInformation signer = signerIter.next();
            X509Certificate cert = (X509Certificate) cmsData.getCertificates().getMatches(signer.getSID()).iterator().next();
            
            // Verify the message digest matches the document content
            if (!signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
                System.out.println("Tampering detected: Document content doesn't match signed digest");
            }
        }
        
        document.close();
    }
}

Step 2: Verify the Signed Byte Range Integrity

Illustrator might modify parts of the PDF outside the initial signed byte range but still break the signature's intent. To replicate Adobe's strict check, compare the hash of the actual signed byte range to the hash stored in the signature:

import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.Arrays;

// Add this inside the main method after retrieving the signature
byte[] fullDocumentBytes = Files.readAllBytes(new File("tampered-document.pdf").toPath());
int[] byteRange = signature.getByteRange();

// Extract the exact bytes that were signed
byte[] signedBytes = new byte[byteRange[2] + byteRange[3]];
System.arraycopy(fullDocumentBytes, byteRange[0], signedBytes, 0, byteRange[2]);
System.arraycopy(fullDocumentBytes, byteRange[2], signedBytes, byteRange[2], byteRange[3]);

// Calculate hash of the extracted bytes
MessageDigest digest = MessageDigest.getInstance(signature.getDigestAlgorithm());
byte[] calculatedHash = digest.digest(signedBytes);

// Extract the stored hash from the CAdES attributes
DEROctetString storedDigest = (DEROctetString) signer.getSignedAttributes().get(CMSAttributes.messageDigest)
        .getAttrValues().getObjectAt(0);
byte[] storedHash = storedDigest.getOctets();

if (!Arrays.equals(calculatedHash, storedHash)) {
    System.out.println("Tampering detected: Byte range hash mismatch");
}

Step 3: Check Document Structural Integrity

Adobe Reader also validates the PDF's cross-reference table, object streams, and revision history. To cover these cases:

  • Use PDFBox's PDFParser to check if objects in the signed revision have been modified or deleted
  • Validate that incremental updates don't alter the signed document's logical structure

Why This Works

The default ShowSignature.java is a minimal example—it only checks if the signature is cryptographically valid, not if the document's content matches what was signed. By validating the CAdES message digest and byte range consistency, you'll catch tampering from tools like Illustrator, matching Adobe Reader's stricter checks.

内容的提问来源于stack exchange,提问作者Anders Andrén

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:08:57