Click here to Skip to main content
13,549,157 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

28.7K views
33 bookmarked
Posted 30 Jan 2015
Licenced CPOL

PDF Merging with Digital Signature and Password Protection

, 7 Jun 2017
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gunaprasad Shetty
Software Developer (Senior)
India India
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
QuestionNo download files? Pin
Rodrigo Belo8-Jul-16 10:38
memberRodrigo Belo8-Jul-16 10:38 
QuestionAbout format Pin
Nelek18-Jan-16 1:47
protectorNelek18-Jan-16 1:47 
Questionmethods Pin
outofcoolnames4-Feb-15 2:12
memberoutofcoolnames4-Feb-15 2:12 
GeneralMy vote of 4 Pin
fredatcodeproject30-Jan-15 5:37
memberfredatcodeproject30-Jan-15 5:37 
GeneralRe: My vote of 4 Pin
Flávio Henrique de Carvalho3-Feb-15 2:05
memberFlávio Henrique de Carvalho3-Feb-15 2:05 
GeneralRe: My vote of 4 Pin
fredatcodeproject3-Feb-15 2:29
memberfredatcodeproject3-Feb-15 2:29 
GeneralRe: My vote of 4 Pin
Gunaprasad Shetty3-Feb-15 5:34
memberGunaprasad Shetty3-Feb-15 5:34 
GeneralRe: My vote of 4 Pin
fredatcodeproject30-Jan-16 13:27
memberfredatcodeproject30-Jan-16 13:27 
GeneralMessage Closed Pin
18-Jan-16 2:17
memberMember 1089184818-Jan-16 2:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03-2016 | 2.8.180515.1 | Last Updated 7 Jun 2017
Article Copyright 2015 by Gunaprasad Shetty
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid