iText

Support for Message Authentication Code (MAC) integrity protection

With the release of iText 9.0, new functionality was introduced to check the integrity of a PDF file: MAC-based integrity protection.

This is a feature that requires PDF 2.0, and was introduced with the ISO-32004 standard. For more information on this feature, here is a very good technical overview on the PDF Association website. In addition, there is a detailed explanation about the difference between MACs and digital signatures.

To add such a MAC details to a protected PDF file with iText Core, you have to specify the MacProperties() in the WriterProperties (Java/.NET).

Create MAC integrity protection

This is a very simple code sample to add the the new functionality:

Java
package com.example;
import java.security.Security;
import com.itextpdf.bouncycastleconnector.BouncyCastleFactoryCreator;
import com.itextpdf.kernel.mac.MacProperties;
import com.itextpdf.kernel.mac.MacProperties.MacDigestAlgorithm;
import com.itextpdf.kernel.pdf.EncryptionConstants;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfVersion;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.Document;

public class Main {
    public static void main(String[] args) throws Exception{
        byte[] USERPASSWORD = "".getBytes();
        byte[] MASTERPASSWORD = "master".getBytes();
        Security.addProvider(BouncyCastleFactoryCreator.getFactory().getProvider());
        //Initialize PDF writer with MacProperties        
        WriterProperties writerProperties = 
            new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0).setStandardEncryption(
                USERPASSWORD, 
                MASTERPASSWORD, 
                0, 
                EncryptionConstants.ENCRYPTION_AES_256,
                new MacProperties(MacDigestAlgorithm.SHA_256));
        PdfWriter writer = new PdfWriter("MacIntegrity.pdf", writerProperties);
        //Initialize PDF document
        PdfDocument pdf = new PdfDocument(writer);
        // Initialize document
        Document document = new Document(pdf);
        //Add paragraph to the document
        document.add(new Paragraph("Hello Mac Integrity!"));
        //Close document
        document.close();
    }
}
C#
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using System.Text;
using iText.Kernel.Mac;
using static iText.Kernel.Mac.MacProperties;
class Program
{
    static void Main() {
        //Initialize PDF writer with MacProperties        
        WriterProperties writerProperties = 
            new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0).SetStandardEncryption(
                Encoding.ASCII.GetBytes(""), 
                Encoding.ASCII.GetBytes("master") , 
                0,
                EncryptionConstants.ENCRYPTION_AES_256,
                new MacProperties(MacDigestAlgorithm.SHA_256));
        PdfWriter writer = new PdfWriter("MacIntegrity.pdf", writerProperties);
        //Initialize PDF document
        PdfDocument pdf = new PdfDocument(writer);
        // Initialize document
        Document document = new Document(pdf);
        //Add paragraph to the document
        document.Add(new Paragraph("Hello Mac Integrity!"));
        //Close document
        document.Close();
    }
}

Validate MAC integrity

When a PDF file is read, the MAC validation will be processed. When the validation is broken, an exception occurs:

Java
package com.example;
import java.security.Security;
import com.itextpdf.bouncycastleconnector.BouncyCastleFactoryCreator;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.ReaderProperties;

public class testMacIntegrity {
    public static void main(String[] args) throws Exception{
        //Initialize PDF writer
        byte[] USERPASSWORD = "".getBytes();
        String inputfile = "MacIntegrity.pdf";
        Security.addProvider(BouncyCastleFactoryCreator.getFactory().getProvider());
         try {
            PdfDocument test = new PdfDocument(
                        new PdfReader(inputfile,
                         new ReaderProperties().setPassword(USERPASSWORD)));
            System.out.println(inputfile + " is valid");
        }
        catch (Exception e) {
            System.out.println("Error: " + e);
        }
    }
}
C#
using iText.Kernel.Pdf;
using System.Text;
class Program
{
    static void Main() {
        string inputfile = "MacIntegrity.pdf";
        byte[] USERPASSWORD = Encoding.ASCII.GetBytes("");
        try {
            PdfDocument test = new PdfDocument(
                        new PdfReader(inputfile,
                        new ReaderProperties().SetPassword(USERPASSWORD)));
            Console.WriteLine(inputfile + " is valid");
        }
        catch (Exception e) {
            Console.WriteLine("Error: " + e);
        }
    }
}