数字签名和 PDF 文档





5.00/5 (1投票)
2007年4月30日
3分钟阅读

93389
PDFKit.NET 2.0 是一个 100% .NET (可验证) 组件,用于创建和操作 PDF 文档。在本文中,我将重点介绍其数字签名功能。数字签名可用于验证 PDF 文档的来源,并提供 PDF 文档的完整性。
PDFKit.NET 2.0 是一个 100% .NET (可验证) 组件,用于创建和操作 PDF 文档。在本文中,我将重点介绍其数字签名功能。数字签名可用于验证 PDF 文档的来源(谁签署了它?)以及提供 PDF 文档的完整性(文档在签名后是否被更改过?)。在本文中,我将展示如何应用一个或多个数字签名以及如何验证数字签名。
- 访问PDFKit.NET 2.0 产品页面以获取更多信息和下载。
- 下方所有示例代码均包含在PDFKit.NET 2.0 评估下载中(请参阅示例 SignVerifyAndUpdates)。
目录
签名
考虑以下表单
图 1:带有字段和两个空签名字段的 PDF 表单
此表单有两个部分表单字段;一个用于学生,一个用于教师。通常,学生会先填写他/她的部分并签署文档。这可以通过编程方式实现,如下所示:
using (FileStream sourceFile = new FileStream(@"form.pdf", FileMode.Open,
FileAccess.Read))
{
// open the form
Document document = new Document(sourceFile);
// file out the data fields
TextField projectNr = document.Fields["projectNumber"] as TextField;
projectNr.Value = "FF-235";
TextField sName = document.Fields["studentName"] as TextField;
sName.Value = "Bob Stapleton";
TextField sDate = document.Fields["studentDate"] as TextField;
sDate.Value = "April 18, 2007";
// retrieve the signature field
SignatureField sigField = document.Fields["studentSignature"] as
SignatureField;
// open certicate store
Pkcs12Store store = null;
using (FileStream storeFile = new FileStream(@"ChrisSharp.pfx",
FileMode.Open, FileAccess.Read))
{
store = new Pkcs12Store(storeFile, "Sample");
}
// let the factory decide which type should be used
SignatureHandler handler = StandardSignatureHandler.Create(store);
// associate the handler with the signature field
sigField.SignatureHandler = handler;
// set optional info
sigField.ContactInfo = "+31 (0)77 4748677";
sigField.Location = "The Netherlands";
sigField.Reason = "I hereby declare!";
// save the signed document - while saving, the handler
// will be called to sign the saved content
using (FileStream outFile = new FileStream(@"signedByStudent.pdf",
FileMode.Create, FileAccess.ReadWrite))
{
document.Write(outFile);
}
}
执行上述代码并在 PDF 阅读器中打开 PDF 文档后,文档的外观如下:
图 2:应用第一个签名后
请注意 PDF 阅读器显示的问号。这意味着证书尚未被客户端计算机信任。这只需将证书添加到信任存储即可。
接下来,教师将审查学生的数据,然后填写最终字段并签名。这可以通过编程方式实现,如下所示:
using (FileStream sourceFile = new FileStream(@"..\..\signedByStudent.pdf",
FileMode.Open, FileAccess.Read))
{
// open the form
Document document = new Document(sourceFile);
// file out the data fields
TextField tName = document.Fields["teacherName"] as TextField;
tName.Value = "Max Boulton";
TextField tDate = document.Fields["teacherDate"] as TextField;
tDate.Value = "April 18, 2007";
// retrieve the signature field
SignatureField sigField = document.Fields["teacherSignature"] as
SignatureField;
// open certicate store.
Pkcs12Store store = null;
using (FileStream storeFile = new FileStream(@"..\..\MaxBoulton.pfx",
FileMode.Open, FileAccess.Read))
{
store = new Pkcs12Store(storeFile, "teacherpassword");
}
// let the factory decide which type should be used.
SignatureHandler handler = StandardSignatureHandler.Create(store);
// associate the handler with the signature field
sigField.SignatureHandler = handler;
// set optional info.
sigField.ContactInfo = "+31 (0)77 4748677";
sigField.Location = "The Netherlands";
sigField.Reason = "I hereby declare!";
// save the signed document - while saving, the handler
// will be called to sign the saved content
using (FileStream outFile = new FileStream(@"..\..\signedByTeacher.pdf",
FileMode.Create, FileAccess.ReadWrite))
{
document.Write(outFile, DocumentWriteMode.AppendUpdate);
}
}
如果您查看代码,它与前面的代码示例几乎相同。唯一的显著区别是我向 Document.Write
方法传递了一个额外的参数:DocumentWriteMode.AppendUpdate
。这告诉PDFKit.NET 2.0将所有更改保存为所谓的“更新”。我将在下一节讨论这一点。
执行上述代码并在 PDF 阅读器中打开 PDF 文档后,文档的外观如下:
图 3:应用第二个签名后
请注意,第一个签名的图标已更改为警告标志。这表明“文档自签名以来已被更新”。确实如此。
更新
请注意,当我们保存第二个签名时,我们向 Document.Write
传递了一个额外的参数,即 DocumentWriteMode.AppendUpdate
。这指示PDFKit.NET将新字段数据和签名保存为“更新”。这意味着原始 PDF 数据完全保持不变,而更改被连接起来。下图说明了这一点。
图 4:PDF 更新
因此,第一个签名仍然有效,因为签名时的数据并未更改;我们只是添加了一个更新。
所以,在保存更新后,实际上有两个版本的文档;一个由学生签名,一个由教师签名。检索已应用特定签名的确切文档非常有用。显然,签名者只对该版本负责,而不对之后创建的版本负责。
给定一个文档,您可以枚举所有更新或版本的文档,并像这样将其保存到磁盘:
using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf",
FileMode.Open, FileAccess.Read))
{
// open the PDF document
Document document = new Document(sourceFile);
// count the number of updates
Console.WriteLine("This document has {0} updates.",document.Updates.Count );
// save each update as a new PDF document
foreach (Update update in document.Updates)
{
string name = string.Format( @"..\..\signedByTeacher_{0}.pdf",
update.Index );
using (FileStream updateFile = new FileStream(name, FileMode.Create,
FileAccess.Write))
{
update.Write(updateFile);
}
}
}
但也许更有趣的是,您可以打开一个已签名的文档,并按签名字段检索已签名的更新。以下代码示例枚举所有签名字段并保存已签名的更新。
using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf",
FileMode.Open, FileAccess.Read))
{
// open the form
Document document = new Document(sourceFile);
foreach (Field field in document.Fields)
{
// is this a signature field?
SignatureField sigField = field as SignatureField;
if (null != sigField)
{
// has it been signed?
if (sigField.IsSigned)
{
// save the update and name it after the field
string name = string.Format(@"..\..\{0}.pdf", sigField.FullName);
using (FileStream updateFile = new FileStream(name,
FileMode.Create, FileAccess.Write))
{
sigField.SignedUpdate.Write(updateFile);
}
}
}
}
}
执行此代码后,将保存两个新的 PDF 文档:studentSignature.pdf 和 teacherSignature.pdf。每个文档都显示了由相应字段签名的版本。
验证
到目前为止,我们讨论了文档签名。验证留给了 PDF 阅读器应用程序。但是PDFKit.NET也允许您以编程方式验证签名。这非常简单,如下一个代码示例所示。该示例打开了由学生和教师签名的 PDF 文档,并枚举签名字段。对于每个签名,有关签名状态的信息将被写入控制台。
using (FileStream inFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)) { // open form Document document = new Document(inFile); foreach (Field field in document.Fields) { // is this a signature field? SignatureField sigField = field as SignatureField; if (null != sigField) { Console.WriteLine("Field '{0}'", sigField.FullName); // has it been signed? if (sigField.IsSigned) { // verify, based on the default handlers. bool verified = sigField.Verify(); Console.WriteLine(" -- {0}", verified ? "Verified" : "Not verified"); if (verified) { // has the document been modified after signing? bool modified = sigField.DocumentModifiedAfterSigning; Console.WriteLine(" -- {0}", modified ? "Modified after signing" : "Not modified after signing"); } } else { Console.WriteLine(" -- Not signed", sigField.FullName); } } } }
执行上述代码后,将向控制台写入以下内容: