Created
April 23, 2018 19:48
-
-
Save jabez007/8e1faa49e43f8f63480f5d9f8b6fd18c to your computer and use it in GitHub Desktop.
Adding a digital and visible signature to a PDF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using iTextSharp.text; | |
using iTextSharp.text.pdf; | |
using iTextSharp.text.pdf.security; | |
using Org.BouncyCastle.Crypto; | |
using Org.BouncyCastle.Security; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Reflection; | |
using System.Security.Cryptography; | |
using System.Security.Cryptography.X509Certificates; | |
namespace SignedReport | |
{ | |
class SigningPdf : IDisposable | |
{ | |
PdfReader reader = new PdfReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SignedReport.Template.pdf")); | |
MemoryStream outputStream = new MemoryStream(); | |
PdfStamper stamper; | |
public AttestationPdf() | |
{ | |
stamper = PdfStamper.CreateSignature(reader, outputStream, '\0'); | |
} | |
public void AddReport() | |
{ | |
} | |
public void AddSignature() | |
{ | |
AddDate(); | |
ApplySignature(); | |
stamper.Close(); | |
} | |
private void AddDate() | |
{ | |
stamper.AcroFields.SetField("Date", DateTime.Today.ToShortDateString()); | |
} | |
private void ApplySignature() | |
{ | |
PdfSignatureAppearance appearance = stamper.SignatureAppearance; | |
appearance.Reason = ""; | |
appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; | |
appearance.Location = Environment.MachineName; | |
appearance.SignatureGraphic = Image.GetInstance(Assembly.GetExecutingAssembly().GetManifestResourceStream("SignedReport.signature.png")); | |
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC; | |
appearance.SetVisibleSignature("Signature"); | |
AsymmetricCipherKeyPair keyPair = null; | |
Oid signatureHashAlgorithm = null; | |
List<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>(); | |
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine)) | |
{ | |
certStore.Open(OpenFlags.ReadOnly); | |
foreach (var cert in certStore.Certificates) | |
{ | |
if (cert.HasPrivateKey) | |
{ | |
// Get CN and Thumbprint from App.config | |
if (cert.SubjectName.Name.Replace(" ", "").Contains(@"CN=commonName")) | |
{ | |
// make sure when the certificate was loaded into the certificate store | |
//that the allow export option was checked. | |
keyPair = DotNetUtilities.GetKeyPair(cert.PrivateKey); | |
signatureHashAlgorithm = cert.SignatureAlgorithm; | |
chain.Add(DotNetUtilities.FromX509Certificate(cert)); | |
} | |
} | |
} | |
} | |
appearance.Certificate = chain[0]; | |
appearance.SignDate = DateTime.Now; | |
IExternalSignature exSig = new PrivateKeySignature(keyPair.Private, "SHA-256"); | |
MakeSignature.SignDetached(appearance, exSig, chain, null, null, null, 0, CryptoStandard.CMS); | |
} | |
public void SaveAs(string filePath) | |
{ | |
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write)) | |
{ | |
byte[] output = outputStream.ToArray(); | |
file.Write(output, 0, output.Length); | |
} | |
} | |
#region IDisposable Support | |
private bool disposedValue = false; // To detect redundant calls | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!disposedValue) | |
{ | |
if (disposing) | |
{ | |
// TODO: dispose managed state (managed objects). | |
stamper.Dispose(); | |
reader.Dispose(); | |
outputStream.Dispose(); | |
} | |
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. | |
// TODO: set large fields to null. | |
disposedValue = true; | |
} | |
} | |
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. | |
// ~AttestationPdf() { | |
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above. | |
// Dispose(false); | |
// } | |
// This code added to correctly implement the disposable pattern. | |
public void Dispose() | |
{ | |
// Do not change this code. Put cleanup code in Dispose(bool disposing) above. | |
Dispose(true); | |
// TODO: uncomment the following line if the finalizer is overridden above. | |
// GC.SuppressFinalize(this); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment