在生产环境中测试,无水印。
随时随地满足您的需求。
获得30天的全功能产品。
几分钟内就能启动并运行。
在您的产品试用期间,全面访问我们的支持工程团队。
在当今快节奏的数字化世界中,实体文件正迅速被电子文档所取代。 无论是签署合同、批准发票还是提交政府表格,数字化文档已经成为新常态。 但便利性带来一个新的问题:如何确保这些数字文件的真实性和完整性?
输入电子签名。 数字签名远不止是在触摸屏上的涂鸦,它使用密码技术来验证签名者的身份,并保证文件内容未被更改。 对于C#开发人员来说,将此级别的安全性集成到PDF工作流中比以往任何时候都更容易,尤其是使用IronPDF和iTextSharp这样的工具。 在本文中,我们将讲解数字签名PDF的过程,对比库,提供最佳实践,并帮助您为下一个项目选择合适的解决方案。
数字签名是一种用于验证数字消息或文档的真实性和完整性的加密技术。 与简单的基于图像的签名或打字的名字不同,数字签名使用私钥对文档的哈希进行加密。 然后,任何人都可以使用签名者的公钥来验证此加密哈希。
这为什么重要? 因为它确保了两件事:
身份验证 – 该签名用于验证来自所述发送者的PDF文档。
完整性 – 文件自签署以来未被更改。 即使是微小的更改也会使签名无效。
数字签名在许多司法管辖区具有法律约束力,对于金融、医疗、法律和政府等行业来说至关重要。
PDF 是分发专业文档的标准格式,从法律合同到官方报告。 向PDF添加数字签名具有几个关键目的:
信任:客户和合作伙伴可以自信地验证文档的来源和完整性。
简而言之,数字签名为您的文档工作流程带来信任和效率。
在 C# 中实现数字签名时,两个库经常脱颖而出:iTextSharp 和 IronPDF。 两者都是强大的工具,但它们适用于不同类型的开发者和项目需求。 让我们分析一下它们在实际使用中的比较。
iTextSharp 是PDF处理领域中一个知名的名字。 它是更广泛的iText 7生态系统的一部分,提供对低级PDF操作的广泛支持,包括加密数字签名。
需要对签名外观、哈希算法、证书链和自定义验证工作流程进行细粒度控制的开发人员会发现iTextSharp非常有能力。 它具有高度的可扩展性,并针对复杂的企业需求进行设计。
然而,这种灵活性是有代价的。学习曲线陡峭。简单的任务,如添加可见签名,通常需要多个类、流和配置步骤。 对于新用户来说,这可能令人生畏。
此外,iTextSharp 根据 AGPL 获得许可,要求您的应用程序是开放源代码的,除非您购买商业许可证——这对许多闭源或专有项目来说是一个障碍。
IronPDF,相反,采取了一种现代的、开发人员优先的方法。 其API旨在处理常见的PDF任务——如数字签名、生成、合并和编辑——且设置简单。在iTextSharp中可能需要十几个步骤,而在IronPDF中通常只需一两行代码。 这使其成为一个用于 .NET 框架项目的强大 PDF 库。
例如,在IronPDF中签署PDF不需要直接处理流或加密设置。 您只需加载PDF,调用.SignPdf(),并传入您的证书。 它甚至支持额外的元数据,如签署者的位置、原因和联系信息——所有这些都在一次方法调用中完成。
另一个关键优势是许可。 IronPDF 提供商业友好许可,没有 AGPL 限制,非常适合专业和企业级应用程序。 虽然这是一个付费产品,但慷慨的免费试用使得在购买前可以轻松评估。
功能 iTextSharp IronPDF
易用性 陡峭的学习曲线 初学者友好,代码简洁
许可证 AGPL(或付费商业授权) 商业许可证,无开源要求
签名定制 高度可定制并具有加密控制 简化的 API 带有可选的元数据字段
文档 详细但稠密 清晰的示例与面向开发者的文档
最佳适用对象 具备深度自定义功能的企业应用程序 需要快速实施和支持的团队
在深入研究数字签名实现之前,了解如何使用每个库进行开发启动是至关重要的。 无论您是在构建企业级解决方案还是快速制作内部工具,正确的设置都能产生重要影响。
iTextSharp 是强大的基于Java的iText PDF库的.NET移植版本。 要开始,您需要通过NuGet安装它并在您的项目中引用正确的命名空间。
您可以通过NuGet包管理器控制台轻松地将iTextSharp库安装到您的项目中。 您需要做的就是运行以下命令:
Install-Package iTextSharp
Install-Package iTextSharp
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package iTextSharp
这种简单的安装确保了该库在您的C#项目中的快速实施。
安装完成后,您可以在项目中开始使用iTextSharp命名空间:
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
Imports iTextSharp.text.pdf
Imports iTextSharp.text.pdf.security
请记住,iTextSharp 是模块化的。 如果您打算使用高级加密功能或时间戳,您可能需要额外的包,如BouncyCastle.Cryptography。 这可以像安装iTextSharp一样安装,只需运行以下命令:
Install-Package BouncyCastle.Cryptography
Install-Package BouncyCastle.Cryptography
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package BouncyCastle.Cryptography
关注事项
学习曲线:即使是基础的签名也涉及理解 PdfSigner、IExternalSignature 和各种加密提供者。
如果您熟悉配置这些构件并需要对签名过程进行全面控制(例如,设置外观、验证级别或时间戳服务器),那么iTextSharp是一个不错的选择。
IronPDF 是一个商业PDF库,旨在提升开发者的生产力。 它专为想要以最少麻烦生成、编辑和签署PDF的.NET开发人员设计。 IronPDF 提供了更加流畅的入门体验,特别适合那些重视简洁 API 和快速结果的人。
通过NuGet安装最新的IronPDF包:
Install-Package IronPdf
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package IronPdf
或者使用 .NET CLI:
dotnet add package IronPdf
dotnet add package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'dotnet add package IronPdf
首先,导入主要的 IronPDF 命名空间:
using IronPdf;
using IronPdf;
Imports IronPdf
就这样——您已准备好加载 PDF 并开始添加数字签名。
IronPDF在内部管理所有内容:证书加载、可见签名定位、元数据和最终导出。 您无需手动管理PDF流或加密算法,这对于快速开发来说是一个巨大的优势。
初学者的重要优势
您需要一个.pfx数字证书文件和一个密码。 这些用于生成数字签名。 您可以从受信任的证书颁发机构 (CA) 获取证书,或使用诸如 OpenSSL 之类的工具生成用于内部使用的证书。
包含必要的命名空间
首先,我们需要确保在代码顶部使用正确的using语句,以便访问使用iTextSharp对PDF进行数字签名所需的各种类和方法。
using System;
using System.IO;
using System.Linq;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using System;
using System.IO;
using System.Linq;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
Imports System
Imports System.IO
Imports System.Linq
Imports iTextSharp.text.pdf
Imports iTextSharp.text.pdf.security
Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.Pkcs
定义输入 PDF 并将其加载到 PdfReader 中
我们指定现有PDF的路径,并将其加载到PdfReader中。 我们还将分配一些字符串变量,这些变量将在代码中稍后使用。
// Path to the unsigned PDF you want to sign
string filename = "example.pdf";
// Load the existing PDF into a reader
PdfReader pdfReader = new PdfReader(filename);
string reason = "Digital Signature Reason";
string location = "Digital Signature Location";
// Path to the unsigned PDF you want to sign
string filename = "example.pdf";
// Load the existing PDF into a reader
PdfReader pdfReader = new PdfReader(filename);
string reason = "Digital Signature Reason";
string location = "Digital Signature Location";
' Path to the unsigned PDF you want to sign
Dim filename As String = "example.pdf"
' Load the existing PDF into a reader
Dim pdfReader As New PdfReader(filename)
Dim reason As String = "Digital Signature Reason"
Dim location As String = "Digital Signature Location"
定义证书路径和密码
接下来,我们指向 .pfx 证书文件,并提供用于保护它的密码。
// Path to your .pfx certificate file (must contain private key)
string pfxFilePath = "certificate-file.pfx";
// Password for the certificate (make sure to protect this securely!)
string pfxPassword = "Password";
// Path to your .pfx certificate file (must contain private key)
string pfxFilePath = "certificate-file.pfx";
// Password for the certificate (make sure to protect this securely!)
string pfxPassword = "Password";
' Path to your .pfx certificate file (must contain private key)
Dim pfxFilePath As String = "certificate-file.pfx"
' Password for the certificate (make sure to protect this securely!)
Dim pfxPassword As String = "Password"
使用Pkcs12Store加载.PFX证书
我们使用BouncyCastle将证书和私钥加载到安全存储中。
// Initialize a new PKCS#12 key store (used for handling the PFX certificate)
Pkcs12StoreBuilder Pkcs12StoreBuilder = new Pkcs12StoreBuilder();
Pkcs12Store pfxKeyStore = Pkcs12StoreBuilder.Build();
// Load the certificate and private key from the PFX file
using (FileStream pfxStream = new FileStream(pfxFilePath, FileMode.Open, FileAccess.Read))
{
// Load into the key store using the provided password
pfxKeyStore.Load(pfxStream, pfxPassword.ToCharArray());
}
// Initialize a new PKCS#12 key store (used for handling the PFX certificate)
Pkcs12StoreBuilder Pkcs12StoreBuilder = new Pkcs12StoreBuilder();
Pkcs12Store pfxKeyStore = Pkcs12StoreBuilder.Build();
// Load the certificate and private key from the PFX file
using (FileStream pfxStream = new FileStream(pfxFilePath, FileMode.Open, FileAccess.Read))
{
// Load into the key store using the provided password
pfxKeyStore.Load(pfxStream, pfxPassword.ToCharArray());
}
' Initialize a new PKCS#12 key store (used for handling the PFX certificate)
Dim Pkcs12StoreBuilder As New Pkcs12StoreBuilder()
Dim pfxKeyStore As Pkcs12Store = Pkcs12StoreBuilder.Build()
' Load the certificate and private key from the PFX file
Using pfxStream As New FileStream(pfxFilePath, FileMode.Open, FileAccess.Read)
' Load into the key store using the provided password
pfxKeyStore.Load(pfxStream, pfxPassword.ToCharArray())
End Using
准备 PdfStamper 以添加签名
PdfStamper 允许我们在保留原始内容的同时应用数字签名。
// Create a PdfStamper that enables signing and appends the signature to the document
PdfStamper pdfStamper = PdfStamper.CreateSignature(
pdfReader,
new FileStream("MyPDF_Signed.pdf", FileMode.Create), // Output path
'\0', // PDF version (unchanged)
null, // Temp file path (optional)
true // Append mode (preserves original content)
);
// Create a PdfStamper that enables signing and appends the signature to the document
PdfStamper pdfStamper = PdfStamper.CreateSignature(
pdfReader,
new FileStream("MyPDF_Signed.pdf", FileMode.Create), // Output path
'\0', // PDF version (unchanged)
null, // Temp file path (optional)
true // Append mode (preserves original content)
);
Imports Microsoft.VisualBasic
' Create a PdfStamper that enables signing and appends the signature to the document
Dim pdfStamper As PdfStamper = PdfStamper.CreateSignature(pdfReader, New FileStream("MyPDF_Signed.pdf", FileMode.Create), ControlChars.NullChar, Nothing, True)
自定义签名外观
现在我们定义签名在文档中视觉上显示的方式和位置。
// Access the signature appearance settings
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
// Add optional metadata (shows up in PDF signature details)
signatureAppearance.Reason = reason;
signatureAppearance.Location = location;
// Position the visible signature on the page (x, y, width, height in points)
float x = 360;
float y = 130;
signatureAppearance.Acro6Layers = false; // Use compact signature appearance
signatureAppearance.Layer4Text = PdfSignatureAppearance.questionMark; // Custom label text
signatureAppearance.SetVisibleSignature(
new iTextSharp.text.Rectangle(x, y, x + 150, y + 50), // Rectangle position
1, // Page number
"signature" // Field name
);
// Access the signature appearance settings
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
// Add optional metadata (shows up in PDF signature details)
signatureAppearance.Reason = reason;
signatureAppearance.Location = location;
// Position the visible signature on the page (x, y, width, height in points)
float x = 360;
float y = 130;
signatureAppearance.Acro6Layers = false; // Use compact signature appearance
signatureAppearance.Layer4Text = PdfSignatureAppearance.questionMark; // Custom label text
signatureAppearance.SetVisibleSignature(
new iTextSharp.text.Rectangle(x, y, x + 150, y + 50), // Rectangle position
1, // Page number
"signature" // Field name
);
' Access the signature appearance settings
Dim signatureAppearance As PdfSignatureAppearance = pdfStamper.SignatureAppearance
' Add optional metadata (shows up in PDF signature details)
signatureAppearance.Reason = reason
signatureAppearance.Location = location
' Position the visible signature on the page (x, y, width, height in points)
Dim x As Single = 360
Dim y As Single = 130
signatureAppearance.Acro6Layers = False ' Use compact signature appearance
signatureAppearance.Layer4Text = PdfSignatureAppearance.questionMark ' Custom label text
signatureAppearance.SetVisibleSignature(New iTextSharp.text.Rectangle(x, y, x + 150, y + 50), 1, "signature")
提取私钥并签署PDF
我们检索包含私钥的证书条目的别名(名称)。 如果别名存在,我们继续使用 SHA-256 生成并嵌入数字签名。
// Find the first alias in the PFX that has a private key entry
string alias = pfxKeyStore.Aliases.Cast<string>().FirstOrDefault(
entryAlias => pfxKeyStore.IsKeyEntry(entryAlias)
);
// Ensure a valid alias (certificate) was found
if (alias != null)
{
// Retrieve the private key for signing
ICipherParameters privateKey = pfxKeyStore.GetKey(alias).Key;
// Create a signer using SHA-256 and the private key
IExternalSignature pks = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA256);
// Perform the digital signing operation using CMS format
MakeSignature.SignDetached(
signatureAppearance, // Signature appearance
pks, // External signature handler
new Org.BouncyCastle.X509.X509Certificate[] {
pfxKeyStore.GetCertificate(alias).Certificate
}, // Certificate chain (basic single-cert example)
null, null, null, // Optional CRL, OCSP, TSA
0, // Estimated size for the signature (0 = auto)
CryptoStandard.CMS // Signature standard (CMS vs CAdES)
);
}
else
{
Console.WriteLine("Private key not found in the PFX certificate.");
}
// Find the first alias in the PFX that has a private key entry
string alias = pfxKeyStore.Aliases.Cast<string>().FirstOrDefault(
entryAlias => pfxKeyStore.IsKeyEntry(entryAlias)
);
// Ensure a valid alias (certificate) was found
if (alias != null)
{
// Retrieve the private key for signing
ICipherParameters privateKey = pfxKeyStore.GetKey(alias).Key;
// Create a signer using SHA-256 and the private key
IExternalSignature pks = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA256);
// Perform the digital signing operation using CMS format
MakeSignature.SignDetached(
signatureAppearance, // Signature appearance
pks, // External signature handler
new Org.BouncyCastle.X509.X509Certificate[] {
pfxKeyStore.GetCertificate(alias).Certificate
}, // Certificate chain (basic single-cert example)
null, null, null, // Optional CRL, OCSP, TSA
0, // Estimated size for the signature (0 = auto)
CryptoStandard.CMS // Signature standard (CMS vs CAdES)
);
}
else
{
Console.WriteLine("Private key not found in the PFX certificate.");
}
' Find the first alias in the PFX that has a private key entry
Dim [alias] As String = pfxKeyStore.Aliases.Cast(Of String)().FirstOrDefault(Function(entryAlias) pfxKeyStore.IsKeyEntry(entryAlias))
' Ensure a valid alias (certificate) was found
If [alias] IsNot Nothing Then
' Retrieve the private key for signing
Dim privateKey As ICipherParameters = pfxKeyStore.GetKey([alias]).Key
' Create a signer using SHA-256 and the private key
Dim pks As IExternalSignature = New PrivateKeySignature(privateKey, DigestAlgorithms.SHA256)
' Perform the digital signing operation using CMS format
MakeSignature.SignDetached(signatureAppearance, pks, New Org.BouncyCastle.X509.X509Certificate() { pfxKeyStore.GetCertificate([alias]).Certificate }, Nothing, Nothing, Nothing, 0, CryptoStandard.CMS)
Else
Console.WriteLine("Private key not found in the PFX certificate.")
End If
最终确定文件
最后,我们关闭签名器以完成签名过程,并将已签名的PDF写入磁盘。
// Close the stamper to save and finalize the signed PDF
pdfStamper.Close();
// Close the stamper to save and finalize the signed PDF
pdfStamper.Close();
' Close the stamper to save and finalize the signed PDF
pdfStamper.Close()
包含必要的命名空间
我们首先导入用于处理PDF签名、证书处理和图像定位的必要命名空间。
using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using System.Security.Cryptography.X509Certificates;
using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using System.Security.Cryptography.X509Certificates;
Imports IronPdf
Imports IronPdf.Signing
Imports IronSoftware.Drawing
Imports System.Security.Cryptography.X509Certificates
加载您想要签署的PDF
我们使用IronPDF的简单PdfDocument API从磁盘加载现有的PDF文件。 您还可以为此任务创建一个新的PDF文档。
var pdf = PdfDocument.FromFile("example.pdf");
var pdf = PdfDocument.FromFile("example.pdf");
Dim pdf = PdfDocument.FromFile("example.pdf")
加载用于签名的PFX证书
我们加载包含私钥的.pfx证书。 导出标志是必需的,以便可以访问签名密钥。
X509Certificate2 cert = new X509Certificate2(
"IronSoftware.pfx",
"Password",
X509KeyStorageFlags.Exportable
);
X509Certificate2 cert = new X509Certificate2(
"IronSoftware.pfx",
"Password",
X509KeyStorageFlags.Exportable
);
Dim cert As New X509Certificate2("IronSoftware.pfx", "Password", X509KeyStorageFlags.Exportable)
使用证书创建新的PdfSignature
我们从加载的证书中创建一个新的PdfSignature对象。
var sig = new PdfSignature(cert);
var sig = new PdfSignature(cert);
Dim sig = New PdfSignature(cert)
应用签名并保存输出
我们对PDF进行数字签名,并将签名的PDF文档保存为一个新文件。
pdf.Sign(sig);
pdf.SaveAs("signed.pdf");
pdf.Sign(sig);
pdf.SaveAs("signed.pdf");
pdf.Sign(sig)
pdf.SaveAs("signed.pdf")
输出
iTextSharp 提供了更多的控制权,但需要通过哈希算法、流和证书链进行详细的设置。
总结:通过几行代码,IronPDF 可以非常轻松地使用标准 .pfx 证书应用数字签名——无需底层加密技术。 这使得与iTextSharp等库所需的更长代码相比,实现起来更加容易处理相同的任务。
为充分利用您的数字签名实施:
在当今注重安全的数字环境中,为PDF文档添加数字签名不再是一种奢侈,而是一种必需。 无论您是在保护合同、发票、报告还是法律文件,拥有一个由可信证书支持的防篡改签名可以确保您的文件保持其真实性和完整性。
在本文中,我们探讨了在 C# 中对 PDF 签名的两种强大方法:
IronPDF 提供了一个现代化的高级 API,使应用安全签名的过程变得无缝且对开发者友好。
这两种工具均支持安全的 .pfx 证书,但 IronPDF 显然简化了工作流程,非常适合希望减少处理加密原语时间并更多专注于提供业务价值的 .NET 开发人员。
如果您还没有,请考虑下载免费的 IronPDF 试用版,并尝试用几行代码签署您自己的 PDF。 仅生产力的提升就值得转换,尤其是在处理时间紧迫的项目时。