Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

PDF Merging with Digital Signature and Password Protection

0.00/5 (No votes)
7 Jun 2017 1  
The tip will help you understand how the Word document can be converted into PDF and merge it as single PDF with digital signature for the secured transport of PDF.

Introduction

The tip will help you understand how a Word document can be converted to PDF and merge it as single PDF with a digital signature for the secured transport of PDF.

Background

This tip will give a basic idea to merge the PDFs into a single PDF from a Word doc, which can then be digitally signed using AsymmetricKey values by using various DLLs in conjunction.

The tip demonstrates the following points:

  • Replacing the word in the Word document and converting into PDF
  • Merging the list of PDF into Single PDF using Spire.Pdf
  • Digitally signing the PDF and placement of Signature in the PDF
  • Password protection of the signed PDF document

Using the Code

The code example below uses various DLLs to accomplish the task.

  1. This code provides the demonstration of how to merge the set of PDF documents into a single PDF
  2. Digitally sign the merged PDF document
  3. Password protection of the digitally signed PDF document.

Below is the list of DLLs which are used, please include this essential DLL into the source code before using the code.

Part 1 - Variable Declaration and Initialization

using iTextSharp.text;
using iTextSharp.text.pdf;
using Microsoft.Office.Interop.Word;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using Spire.Pdf;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;

Pkcs12Store pk12;
//First we'll read the certificate file and declare the certificate variable,
//a pfx file will be used and a password will be provided to validate the pfx file. 
try
{
pk12 = new Pkcs12Store(new FileStream(txtSignature.Text, FileMode.Open, FileAccess.Read), 
    txtPassword.Text.ToCharArray());
}
catch (Exception ex)
{
MessageBox.Show("Signature Passsword incorrect" + ex.Message);
return;
}

In the above piece of code:

  1. We are declaring the certificate variables
  2. Pkcs12Store Store is instantiated which takes four parameters:
    1. Signature text provided by user
    2. FileMode
    3. Accesstype
    4. Password provided by the user

These parameters would be used by the Pkcs12Store to access the certificate having a pfx extension. This certificate will be used later for digitally signing the document in the below code.

Part 2 - Loading the Document and Replacing the Values from the Database

#region Firstpage Document to pdf conversion and replacing of values
object fileName = Path.GetFullPath
(ConfigurationManager.AppSettings["TemplateDocument"].ToString());
Word.Application wordApp = new Word.Application { Visible = false };
Word.Document aDoc = 
wordApp.Documents.Open(ref fileName, ReadOnly: true, Visible: false);
 
aDoc.Activate();
string text = wordApp.ActiveDocument.Content.Text;
Word.Find fnd = wordApp.ActiveDocument.Content.Find;
fnd.ClearFormatting();
fnd.Replacement.ClearFormatting();
fnd.Forward = true;
fnd.Wrap = Word.WdFindWrap.wdFindContinue;
fnd.Text = "[##FormName]";
fnd.Replacement.Text = formName;
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##COMPANY]";
fnd.Replacement.Text = 
((System.Data.DataRowView)(cmbEntity.SelectedItem)).Row.ItemArray[2].ToString();
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##NAME]";
fnd.Replacement.Text = Convert.ToString(dr[0]["RES_DESC"]);
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##EMP_CODE]";
fnd.Replacement.Text = Convert.ToString(row["Emp_Code"]);
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
// // Any source code blocks look like this //
fnd.Text = "[##EMP_PAN]";
if (!String.IsNullOrEmpty(Convert.ToString(row["PAN_Number"])))
fnd.Replacement.Text = Convert.ToString(row["PAN_Number"]);
else
fnd.Replacement.Text = "PANNOTAVBL";
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##EMP_DESG]";
fnd.Replacement.Text = Convert.ToString(dr[0]["RES_DESIGNATION"]);
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##FINANCIAL_YEAR]";
fnd.Replacement.Text = Convert.ToString(cmbYear.SelectedItem.ToString());
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);
fnd.Text = "[##ASSESMENT_YEAR]";

var assesmentperiod = CalculateAssesmentYear
(Convert.ToString(cmbYear.SelectedItem.ToString()),"AP");
fnd.Replacement.Text = assesmentperiod.Item1+" - "+assesmentperiod.Item2;
fnd.Execute(Replace: Word.WdReplace.wdReplaceAll);

The above code reads the Doc Template, replaces the values from the database and converts it into the document that would be used by PDF conversion object.

Part 3 - Assigning User Name and Password to the Document for Authentication and Converting from Document to PDF

The code below explains how the files are read from the directory and are assigned with the security username and password before converting it to the secured or protected PDF files.

object oMissing = System.Reflection.Missing.Value;
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetFullPath
(ConfigurationManager.AppSettings["TemplateDocument"].ToString()));
outputFileName = Path.GetFullPath(ConfigurationManager.AppSettings
["EmployeeFirstPage"]"ToString()) + 
Convert.ToString(row["Emp_Code"]) + 
dirInfo.Name.Replace(".docx", ".pdf");
object fileFormat = Word.WdSaveFormat.wdFormatPDF;
// Save document into PDF Format
if (File.Exists(Convert.ToString(outputFileName)))
{
File.Delete(Convert.ToString(outputFileName)); 
}
aDoc.SaveAs(ref outputFileName,
ref fileFormat, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing);
object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
((_Document)aDoc).Close(ref saveChanges, ref oMissing, ref oMissing);
aDoc = null;
((_Application)wordApp).Quit(ref oMissing, ref oMissing, ref oMissing);
wordApp = null;
// DoSearchAndReplaceInWord();
#endregion First page document
#region merging of entire documents 
//PdfDocument outputDocument = new PdfDocument();
 
List<string> lstfirspage = new List<string>();
lstfirspage.Add(outputFileName.ToString());
lstfirspage.AddRange(lstdocuments);
try
{
// Save the document...
PdfDocumentBase doc = Spire.Pdf.PdfDocument.MergeFiles(lstfirspage.ToArray<string>());
Spire.Pdf.Security.PdfSecurity securitySettings = doc.Security;
string year = Convert.ToString(cmbYear.SelectedItem);
string filename = Convert.ToString(row["Emp_Code"])+ "_Form16_" + year;
string outputUnSignedFile = @"" + txtDestination.Text + 
"\\TUnSigned\\" + filename + ".pdf";

outputFile = @"" + txtDestination.Text + "\\" + filename + ".pdf";
if (!String.IsNullOrWhiteSpace(Convert.ToString(row["PAN_Number"])))
{
if ((Convert.ToString(dr[0]["Res_Status"]) == "Active"))
{
securitySettings.UserPassword = Convert.ToString(row["PAN_Number"]).ToUpper();
securitySettings.OwnerPassword = Convert.ToString(row["PAN_Number"]).ToUpper();
}
word = "PAN in uppercase";
if (File.Exists(txtSource.Text + "\\" + TraceFile + ".pdf"))
{
if (File.Exists(outputUnSignedFile))
{
File.Delete(outputUnSignedFile);
}
doc.Save(outputUnSignedFile, FileFormat.PDF);
}
else
{
if (File.Exists(outputFile))
{
File.Delete(outputFile);
}
doc.Save(outputFile, FileFormat.PDF); 
}
} 
else
{
if ((Convert.ToString(dr[0]["Res_Status"]) == "Active"))
{
securitySettings.UserPassword = Convert.ToString(row["Emp_Code"]).ToUpper();
securitySettings.OwnerPassword = Convert.ToString(row["Emp_Code"]).ToUpper();
}
word = "Employee Code";
if (File.Exists(outputFile))
{
File.Delete(outputFile); 
}
doc.Save(outputFile, FileFormat.PDF);
} 
doc.Close(); 
Spire.Pdf.PdfDocument finaldoc = new Spire.Pdf.PdfDocument();
if (File.Exists(txtSource.Text + "\\" + TraceFile + ".pdf") 
&& !String.IsNullOrWhiteSpace(Convert.ToString(row["PAN_Number"])))
{
if (File.Exists(outputFile))
{
File.Delete(outputFile); 
}

Part 4 - Digitally Signing the PDF Document using SpirePdf and Asymmetric Key

The following code iterates through the private key entry and finds the suitable one, once the certificate is found the unsigned file will be verified for the signed certificate or key. Once the appropriate key is found, the output will show the green tick mark which satisfies that the PDF has been digitally verified through the desired or the provided certificate.

string alias = null;
//then Iterate through certificate entries to find the private key entry
System.Collections.IEnumerator i = pk12.Aliases.GetEnumerator();
while (i.MoveNext())
{
alias = ((string)i.Current);
if (pk12.IsKeyEntry(alias))
break;
}
AsymmetricKeyParameter Akp = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; ++k)
chain[k] = ce[k].Certificate;
 
char[] chararr = Convert.ToString(row["PAN_Number"]).ToUpper().ToCharArray();
Byte[] b = new Byte[chararr.Length];
for (int ifor = 0; ifor < chararr.Length; ifor++)
b[ifor] = Convert.ToByte(chararr[ifor]);
PdfReader reader = new PdfReader(outputUnSignedFile,b); 
FileStream fout = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
PdfStamper stp = PdfStamper.CreateSignature(reader, fout, '\0');
if ((Convert.ToString(dr[0]["Res_Status"]) == "Active"))
{
stp.SetEncryption(true, Convert.ToString(row["PAN_Number"]).ToUpper(), 
Convert.ToString(row["PAN_Number"]).ToUpper(), 
PdfWriter.ALLOW_SCREENREADERS | PdfWriter.ALLOW_PRINTING);
}
PdfSignatureAppearance sap = stp.SignatureAppearance;
sap.SetCrypto(Akp, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; 
Spire.Pdf.PdfDocument doccount = new Spire.Pdf.PdfDocument();
doccount.LoadFromFile(txtSource.Text + "\\" + TraceFile + ".pdf"); 
sap.SetVisibleSignature(new iTextSharp.text.Rectangle(545,40,455,80),
doccount.Pages.Count + 1, "Signature");
stp.Close();

}
try
{
if (File.Exists(outputUnSignedFile))
{
File.Delete(outputUnSignedFile);
}
if (File.Exists(Convert.ToString(outputFileName)))
{
File.Delete(Convert.ToString(outputFileName));
}
}
catch (Exception)
{
 
}
finally
{ 

}
#endregion merging of documents
}

The above code provides a small example of digitally signing and merging PDFs. Developers can use them accordingly for their use with modification according to the requirement.

Thanks for reading! Vote if you find it helpful!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here