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:
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();
}
}
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:
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);
}
}
}
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);
}
}
}