Here is an C# example of signing a PDF file with certificate in file using the latest free MPL & GPL version of iText. It can be downloaded from here (source) or here(DLL) or via NuGet package manager in Visual Studio.
After importing iText in the project you have access to the following functions.
The code for PDF processing goes like this:
var _certificate = new X509Certificate2(@"C:\cert.pfx", "iLikeMyCertPass" , X509KeyStorageFlags.Exportable); var certParser = new Org.BouncyCastle.X509.X509CertificateParser(); var chain = new Org.BouncyCastle.X509.X509Certificate[] { certParser.ReadCertificate(_certificate.RawData) }; AsymmetricKeyParameter bouncyCastlePrivateKey = DotNetUtilities.GetKeyPair(_certificate.PrivateKey).Private; var reader = new PdfReader(@"C:\test.pdf"); var writer = new FileStream(@"C:\test-signed.pdf"), FileMode.Create, FileAccess.Write); PdfStamper st = PdfStamper.CreateSignature(reader, writer, '\0'); PdfSignatureAppearance sap = st.SignatureAppearance; sap.Layer2Font = new Font(Font.UNDEFINED, 4); sap.Reason = "I can sign it!"; sap.Location = "At home"; sap.SetVisibleSignature(new Rectangle(0, 0, 120, 35), reader.NumberOfPages, "Signature"); sap.Render = PdfSignatureAppearance.SignatureRender.Description; sap.SetCrypto(bouncyCastlePrivateKey, chain, null, PdfName.ADOBE_PPKLITE); sap.Acro6Layers = true; //if I uncomment the following line the status of file is UNKNOWN in Acrobat reader //sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; reader.Appendable = true; var dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); dic.Reason = sap.Reason; dic.Contact = sap.Contact; dic.Location = sap.Location; dic.Date = new PdfDate(sap.SignDate); sap.CryptoDictionary = dic; int contentEstimated = 15000; //you can modify this you have loads of contents in signature var exc = new Hashtable(); exc[PdfName.CONTENTS] = contentEstimated*2 + 2; sap.PreClose(exc); PdfPKCS7 sgn = new PdfPKCS7(bouncyCastlePrivateKey, chain, null, "SHA-1", false); IDigest messageDigest = DigestUtilities.GetDigest("SHA-1"); Stream data = sap.RangeStream; byte[] buf = new byte[contentEstimated]; int n; while ((n = data.Read(buf, 0, buf.Length)) > 0) { messageDigest.BlockUpdate(buf, 0, n); } byte[] hash = new byte[messageDigest.GetDigestSize()]; messageDigest.DoFinal(hash, 0); DateTime cal = DateTime.Now; byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, null); sgn.Update(sh, 0, sh.Length); byte[] encodedSig = sgn.GetEncodedPKCS7(hash, cal, null, null); if (contentEstimated + 2 < encodedSig.Length) throw new Exception("Not enough space"); var paddedSig = new byte[contentEstimated]; Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length); var dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2);
Leave any feedback if it doesn’t work.
Leave a Reply