使用 iTextSharp 将数字签名添加到 PDF
Adding a Digital signature to a PDF with iTextSharp
背景
我使用 iTextSharp 已经有一段时间了。我创建了一个带有两个可签名 PdfFormFields 的 pdf 文档。如果我打开 pdf 文档,我可以手动在每个字段上签名。我希望通过 iTextSharp 完成此操作。
我目前正在从 X509Store 检索证书。直到现在,我才明白。
问题
谁能告诉我如何使用这个 X509Certificate2
签署一个已经存在的签名 AcroField。
参考资料
访问了以下参考资料,但找不到我要找的答案。
Signing a pdf document
这个 link 让我相信最接近,但是使用的几行无效,我不知道我是否可以通过包含一些其他库来修复它。
https://www.dotnetportal.cz/blogy/15/Null-Reference-Exception/5250/Digitalni-podepisovani-PDF-souboru-v-C-cast-2
你需要的一切:
appearance.SetVisibleSignature("---> ExistSignatureName <-----");
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);
完整代码:
private static void SignPdf(string filename, string folderPdf, string pathToNewSignFile, string pathToCerts, string nameCert, string passCert)
{
var pathToCert = GetFullNameFile(pathToCerts, nameCert); //Oh.. I did not know about the Path.Combine function.
if (!File.Exists(pathToCert))
{
logger.Error("Certificate not exist " + pathToCert);
return;
}
var pass = passCert.ToCharArray();
FileStream fs;
try
{
fs = new FileStream(pathToCert, FileMode.Open);
}
catch (Exception ex)
{
logger.Error(ex, "Could not open cert" + pathToCert);
return;
}
var store = new Pkcs12Store(fs, pass);
fs.Close();
var alias = "";
// searching for private key
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) {
alias = al;
break;
}
var pk = store.GetKey(alias);
ICollection<X509Certificate> chain = store.GetCertificateChain(alias).Select(c => c.Certificate).ToList();
var parameters = pk.Key as RsaPrivateCrtKeyParameters;
var pathPdf = GetFullNameFile(folderPdf, filename); //Oh.. I did not know about the Path.Combine function.
var pathToSigPdf = GetFullNameFile(pathToNewSignFile, filename);
if (!File.Exists(pathPdf))
{
logger.Error("Could not open file" + pathPdf + " File not exist");
return;
}
var reader = new PdfReader(pathPdf);
FileStream fileStreamSigPdf;
try
{
fileStreamSigPdf = new FileStream(pathToSigPdf, FileMode.Create);
}
catch (Exception ex)
{
logger.Error(ex, "Could not create file" + pathToSigPdf);
return;
}
var stamper = PdfStamper.CreateSignature(reader, fileStreamSigPdf, '[=11=]', null, true);
var appearance = stamper.SignatureAppearance;
appearance.Reason = "Утверждено";
appearance.SetVisibleSignature("---> ExistSignatureName <-----");
IExternalSignature pks = new PrivateKeySignature(parameters, DigestAlgorithms.SHA256);
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);
fileStreamSigPdf.Close();
reader.Close();
stamper.Close();
logger.Info("Signed successfully " + filename);
}
我们公司有一个网络服务器。
1.获取哈希字段
2. 在加密插件的帮助下,我们对哈希进行签名
3. 在字段中插入签名
步骤 1.
public string PrepareSignatureAndGetHash()
{
var hash = string.Empty;
using (var reader = new PdfReader("PathTemplate"))
{
using (var fileStream = File.OpenWrite("PathToTemp"))
{
using (var stamper = PdfStamper.CreateSignature(reader, fileStream, '0', null, true))
{
var signatureAppearance = stamper.SignatureAppearance;
signatureAppearance.SetVisibleSignature("ExistSignatureName");
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
signatureAppearance.Reason = "Sig";
signatureAppearance.Layer2Text = "Super SIG";
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
MakeSignature.SignExternalContainer(signatureAppearance, external, 8192);
using (var contentStream = signatureAppearance.GetRangeStream())
{
hash = string.Join(string.Empty, SHA1.Create().ComputeHash(contentStream).Select(x => x.ToString("X2")));
}
}
}
}
return hash;
}
第 2 步
public void SigSignature(string base64String)
{
using (var reader = new PdfReader("PathToTemp"))
{
using (var fileStream = File.OpenWrite("PathToSig"))
{
var byteSig = Convert.FromBase64String(base64String);
IExternalSignatureContainer external = new MfuaExternalSignatureContainer(byteSig);
MakeSignature.SignDeferred(reader, "ExistSignatureName", fileStream, external);
}
}
}
private class MfuaExternalSignatureContainer : IExternalSignatureContainer
{
private readonly byte[] _signedBytes;
public MfuaExternalSignatureContainer(byte[] signedBytes)
{
_signedBytes = signedBytes;
}
public byte[] Sign(Stream data)
{
return _signedBytes;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
}
}
背景
我使用 iTextSharp 已经有一段时间了。我创建了一个带有两个可签名 PdfFormFields 的 pdf 文档。如果我打开 pdf 文档,我可以手动在每个字段上签名。我希望通过 iTextSharp 完成此操作。
我目前正在从 X509Store 检索证书。直到现在,我才明白。
问题
谁能告诉我如何使用这个 X509Certificate2 签署一个已经存在的签名 AcroField。
参考资料
访问了以下参考资料,但找不到我要找的答案。 Signing a pdf document
这个 link 让我相信最接近,但是使用的几行无效,我不知道我是否可以通过包含一些其他库来修复它。 https://www.dotnetportal.cz/blogy/15/Null-Reference-Exception/5250/Digitalni-podepisovani-PDF-souboru-v-C-cast-2
你需要的一切:
appearance.SetVisibleSignature("---> ExistSignatureName <-----");
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);
完整代码:
private static void SignPdf(string filename, string folderPdf, string pathToNewSignFile, string pathToCerts, string nameCert, string passCert)
{
var pathToCert = GetFullNameFile(pathToCerts, nameCert); //Oh.. I did not know about the Path.Combine function.
if (!File.Exists(pathToCert))
{
logger.Error("Certificate not exist " + pathToCert);
return;
}
var pass = passCert.ToCharArray();
FileStream fs;
try
{
fs = new FileStream(pathToCert, FileMode.Open);
}
catch (Exception ex)
{
logger.Error(ex, "Could not open cert" + pathToCert);
return;
}
var store = new Pkcs12Store(fs, pass);
fs.Close();
var alias = "";
// searching for private key
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) {
alias = al;
break;
}
var pk = store.GetKey(alias);
ICollection<X509Certificate> chain = store.GetCertificateChain(alias).Select(c => c.Certificate).ToList();
var parameters = pk.Key as RsaPrivateCrtKeyParameters;
var pathPdf = GetFullNameFile(folderPdf, filename); //Oh.. I did not know about the Path.Combine function.
var pathToSigPdf = GetFullNameFile(pathToNewSignFile, filename);
if (!File.Exists(pathPdf))
{
logger.Error("Could not open file" + pathPdf + " File not exist");
return;
}
var reader = new PdfReader(pathPdf);
FileStream fileStreamSigPdf;
try
{
fileStreamSigPdf = new FileStream(pathToSigPdf, FileMode.Create);
}
catch (Exception ex)
{
logger.Error(ex, "Could not create file" + pathToSigPdf);
return;
}
var stamper = PdfStamper.CreateSignature(reader, fileStreamSigPdf, '[=11=]', null, true);
var appearance = stamper.SignatureAppearance;
appearance.Reason = "Утверждено";
appearance.SetVisibleSignature("---> ExistSignatureName <-----");
IExternalSignature pks = new PrivateKeySignature(parameters, DigestAlgorithms.SHA256);
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);
fileStreamSigPdf.Close();
reader.Close();
stamper.Close();
logger.Info("Signed successfully " + filename);
}
我们公司有一个网络服务器。 1.获取哈希字段 2. 在加密插件的帮助下,我们对哈希进行签名 3. 在字段中插入签名
步骤 1.
public string PrepareSignatureAndGetHash()
{
var hash = string.Empty;
using (var reader = new PdfReader("PathTemplate"))
{
using (var fileStream = File.OpenWrite("PathToTemp"))
{
using (var stamper = PdfStamper.CreateSignature(reader, fileStream, '0', null, true))
{
var signatureAppearance = stamper.SignatureAppearance;
signatureAppearance.SetVisibleSignature("ExistSignatureName");
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
signatureAppearance.Reason = "Sig";
signatureAppearance.Layer2Text = "Super SIG";
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
MakeSignature.SignExternalContainer(signatureAppearance, external, 8192);
using (var contentStream = signatureAppearance.GetRangeStream())
{
hash = string.Join(string.Empty, SHA1.Create().ComputeHash(contentStream).Select(x => x.ToString("X2")));
}
}
}
}
return hash;
}
第 2 步
public void SigSignature(string base64String)
{
using (var reader = new PdfReader("PathToTemp"))
{
using (var fileStream = File.OpenWrite("PathToSig"))
{
var byteSig = Convert.FromBase64String(base64String);
IExternalSignatureContainer external = new MfuaExternalSignatureContainer(byteSig);
MakeSignature.SignDeferred(reader, "ExistSignatureName", fileStream, external);
}
}
}
private class MfuaExternalSignatureContainer : IExternalSignatureContainer
{
private readonly byte[] _signedBytes;
public MfuaExternalSignatureContainer(byte[] signedBytes)
{
_signedBytes = signedBytes;
}
public byte[] Sign(Stream data)
{
return _signedBytes;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
}
}