Add Digital Signature to a PDF using IText 8 - Stack Overflow

admin2025-04-27  6

I have implemented a feature to digitally sign a document using iText 8.0.5 in Java. However, after signing the document, it shows that the document has been altered or modified.

How to properly digitally sign the document using iText 8.0.5?

import javax.security.auth.x500.X500Principal;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Calendar;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PdfSigner.CryptoStandard;
import com.itextpdf.signatures.SignatureFieldAppearance;

public class PdfEmbedder {

    public String pdfSigner(String src, String dest, String signatureValue, String certificateString) throws Exception {
        signatureValue = signatureValue.trim().replaceAll("[^A-Za-z0-9+/=]", "");
        byte[] decodedSignatureValue;
        try {
            decodedSignatureValue = Base64.getDecoder().decode(signatureValue);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid Base64 encoded signature value", e);
        }
    
        certificateString = certificateString.trim()
                .replaceAll("-----BEGIN CERTIFICATE-----|-----END CERTIFICATE-----", "")
                .replaceAll("\\s+", "");
        byte[] decodedCertificate = Base64.getDecoder().decode(certificateString);
    
        Security.addProvider(new BouncyCastleProvider());
    
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        InputStream certificateInputStream = new ByteArrayInputStream(decodedCertificate);
        X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(certificateInputStream);
    
        PdfReader reader = new PdfReader(src);
        PdfWriter writer = new PdfWriter(dest);
        PdfSigner signer = new PdfSigner(reader, writer, new PdfSigner.StampingProperties().useAppendMode());
    
        Calendar signingDate = Calendar.getInstance();
        PdfDocument pdfDocument = signer.getDocument();
        PdfPage firstPage = pdfDocument.getFirstPage();
        Rectangle pageSize = firstPage.getPageSize();
    
        float sigWidth = 200;
        float sigHeight = 50;
        float xPos = pageSize.getWidth() - (sigWidth + 20);
        float yPos = 10;
        Rectangle rect = new Rectangle(xPos, yPos, sigWidth, sigHeight);
    
        if (firstPage.getRotation() == 90) {
            rect = new Rectangle(pageSize.getWidth() - sigHeight, pageSize.getHeight() - sigWidth, sigHeight, sigWidth);
        }
    
        signer.setPageRect(rect).setPageNumber(1).setSignDate(signingDate);
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss XXX");
        String formattedDate = sdf.format(signingDate.getTime());
    
        SignatureFieldAppearance appearance = new SignatureFieldAppearance("app");
        appearance.setContent("Digitally signed by " + getSignerName(certificate) + "\nDate: " + formattedDate);
        appearance.setFontSize(8);
        signer.setSignatureAppearance(appearance);
        signer.setFieldName("sig");
    
        IExternalSignature externalSignature = new IExternalSignature() {
            @Override
            public byte[] sign(byte[] messageHash) throws GeneralSecurityException {
                return decodedSignatureValue;
            }
    
            @Override
            public String getDigestAlgorithmName() {
                return DigestAlgorithms.SHA256;
            }
    
            @Override
            public String getSignatureAlgorithmName() {
                return "RSA";
            }
    
            @Override
            public ISignatureMechanismParams getSignatureMechanismParameters() {
                return null;
            }
        };
    
        X509Certificate[] chain = new X509Certificate[]{certificate};
    
        signer.signDetached(new BouncyCastleDigest(), externalSignature, chain, null, null, null, 8192, CryptoStandard.CMS);
    
        return "Document signed successfully with certificate";
    }
    
    public static String getSignerName(X509Certificate certificate) {
        X500Principal principal = certificate.getSubjectX500Principal();
        String dn = principal.getName();
        for (String part : dn.split(",")) {
            if (part.trim().startsWith("CN=")) {
                return part.trim().substring(3);
            }
        }
        return "Unknown";
    }

}
转载请注明原文地址:http://anycun.com/QandA/1745710979a91157.html