I'm working on an application that allows users to generate certain PDF documents using templates, then sign those documents and store the signed documents for later verification.
When using completely external (detached, say RSA) signature, I can do the following optimization: as a document is generated using a template from a small structured dataset, I can ignore the document itself and only store structured data along with signature.
This greatly reduces requirements for disk space and throughput, as PDF file is 50-100 times bigger than it's source data.
However, recently we've got a requirement to use signatures embedded in PDF files themselves. Here it is - iText comes to rescue!
The idea is to have the following process:
- Generate PDF on server. This includes getting the source data, transforming it to PDF using template, then using iText insert an empty signature container to it.
- Send PDF to client for signing
- Extract user signature from PDF. Store it separately along with source data, template version, and byte ranges used for signing
- When a document is requested, generate the same document from source data, then insert stored signature using previously recorded byte ranges.
So far, sounds so good.
However, the problem is getting repeatable result during transformation chain Source Data -> PDF -> PDF + Signature Container
The step Source Data -> PDF obviously works fine. The problem is with inserting a Signature Container. Each time I'm using the same code on the same PDF i get different result (in bytes) of resulting PDF + Container.
I'm using roughly the following code to prepare document for signing:
PdfReader reader = new PdfReader(resultDocument);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
PdfSignatureAppearance sap = stamper.getSignatureAppearance();
sap.setReason("Sign reason");
sap.setLocation("Sign location");
sap.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
sap.setSignDate(externallyStoredSignDate)
PdfSignature dic = new PdfSignature(
PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(sap.getReason());
dic.setLocation(sap.getLocation());
dic.setContact(sap.getContact());
dic.setDate(new PdfDate(sap.getSignDate()));
sap.setCryptoDictionary(dic);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
sap.preClose(exc);
InputStream data = sap.getRangeStream(); // Whooops - different every time!
Any help on how to get repeatable PDFs with prepared space for signatures is greatly appreciated! Thanks in advance.