C#-PDF签名-嵌入分开签名的哈希
作者:互联网
我正在尝试在两个服务器中使用两个Web服务来签署PDF文档.但是它显示Adobe Reader中的“自签名以来,文档已被更改或损坏”.任何人都可以在以下代码中提出错误的建议.
程序
1.服务器A上的Web服务(WS),从PDF生成哈希,然后发送到服务器B上的WS进行签名.
2.服务器B上的WS签名哈希.
3.服务器A上的WS接收签名的哈希并嵌入PDF文档中.
码
产生哈希
private PDFHashData generateHash(byte[] content, string userName)
{
PdfReader reader = new PdfReader(content);
MemoryStream ms = new MemoryStream();
PdfStamper stamper = PdfStamper.CreateSignature(reader, ms, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SetVisibleSignature(new Rectangle(500, 150, 400, 200), 1, signatureFieldName);
appearance.SignDate = DateTime.Now;
appearance.Reason = Reason;
appearance.Location = Location;
appearance.Contact = Contact;
StringBuilder buf = new StringBuilder();
buf.Append("Digitally signed by");
buf.Append("\n");
buf.Append(userName);
buf.Append("\n");
buf.Append("Date: " + appearance.SignDate);
appearance.Layer2Text = buf.ToString();
appearance.Acro6Layers = true;
appearance.CertificationLevel = 0;
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
byte[] hash = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());
StringBuilder hex = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
hex.AppendFormat("{0:x2}", b);
PDFHashData phData= new PDFHashData();
phData.Hash = hex.ToString();
phData.Content = Convert.ToBase64String(ms.ToArray());
return phData;
}
签名哈希
byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
private Stream getCertificate()
{
// Base 64 byte - PFX file with private key
return new MemoryStream(Convert.FromBase64String("..................................AgIEAA=="));
}
protected void Page_Load(object sender, EventArgs e)
{
Stream stream = Request.InputStream;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
byte[] hash = StringToByteArray(Encoding.UTF8.GetString(buffer));
Pkcs12Store store = new Pkcs12Store(getCertificate(), "*******".ToCharArray());
String alias = "";
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
X509CertificateEntry[] chain = store.GetCertificateChain(alias);
List<Org.BouncyCastle.X509.X509Certificate> c = new List<Org.BouncyCastle.X509.X509Certificate>();
foreach (X509CertificateEntry en in chain)
{
c.Add(en.Certificate);
}
PrivateKeySignature signature = new PrivateKeySignature(pk.Key, "SHA1");
String hashAlgorithm = signature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, c, hashAlgorithm, false);
DateTime signingTime = DateTime.Now;
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
Response.Write(Convert.ToBase64String(sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS)));
}
嵌入PDF签名
private byte[] signPDF(byte[] content, string userName, byte[] pk)
{
PdfReader reader = new PdfReader(content);
MemoryStream os = new MemoryStream();
IExternalSignatureContainer external = new MyExternalSignatureContainer(pk);
MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
return os.ToArray();
}
解决方法:
对于那些有兴趣的人,我正在发布答案.
我最终使用了itextsharp 5.5.10.代码如下
初始化PDF对象
public PDFSigning(byte[] Content, string UserName)
{
content = Content;
reader = new PdfReader(content);
ms = new MemoryStream();
stamper = PdfStamper.CreateSignature(reader, ms, '\0');
appearance = stamper.SignatureAppearance;
userName = UserName;
}
private Stream getCertificate()
{
return new MemoryStream(Convert.FromBase64String("************************=="));
}
产生杂凑
private string generateHash()
{
appearance.SetVisibleSignature(new Rectangle(500, 150, 400, 200), 1, signatureFieldName);
appearance.SignDate = DateTime.Now;
appearance.Reason = Reason;
appearance.Location = Location;
appearance.Contact = Contact;
StringBuilder buf = new StringBuilder();
buf.Append("Digitally signed by");
buf.Append("\n");
buf.Append(userName);
buf.Append("\n");
buf.Append("Date: " + appearance.SignDate);
appearance.Layer2Text = buf.ToString();
appearance.Acro6Layers = true;
appearance.CertificationLevel = 0;
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
{
Date = new PdfDate(appearance.SignDate),
Name = userName
};
dic.Reason = appearance.Reason;
dic.Location = appearance.Location;
dic.Contact = appearance.Contact;
appearance.CryptoDictionary = dic;
Dictionary<PdfName, int> exclusionSizes = new Dictionary<PdfName, int>();
exclusionSizes.Add(PdfName.CONTENTS, (csize * 2) + 2);
appearance.PreClose(exclusionSizes);
HashAlgorithm sha = new SHA256CryptoServiceProvider();
Stream s = appearance.GetRangeStream();
int read = 0;
byte[] buff = new byte[0x2000];
while ((read = s.Read(buff, 0, 0x2000)) > 0)
{
sha.TransformBlock(buff, 0, read, buff, 0);
}
sha.TransformFinalBlock(buff, 0, 0);
StringBuilder hex = new StringBuilder(sha.Hash.Length * 2);
foreach (byte b in sha.Hash)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
签名哈希
public byte[] SignMsg(string hexhash)
{
byte[] hash = hexToByteArray(hexhash);
Pkcs12Store store = new Pkcs12Store(getCertificate(), "*********".ToCharArray());
String alias = "";
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
X509CertificateEntry[] chain = store.GetCertificateChain(alias);
List<Org.BouncyCastle.X509.X509Certificate> c = new List<Org.BouncyCastle.X509.X509Certificate>();
foreach (X509CertificateEntry en in chain)
{
c.Add(en.Certificate);
}
PrivateKeySignature signature = new PrivateKeySignature(pk.Key, "SHA256");
String hashAlgorithm = signature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, c, hashAlgorithm, false);
DateTime signingTime = DateTime.Now;
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
return sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
}
签名PDF
private byte[] signPDF(byte[] pk)
{
byte[] paddedSig = new byte[csize];
System.Array.Copy(pk, 0, paddedSig, 0, pk.Length);
PdfDictionary dic2 = new PdfDictionary();
dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
appearance.Close(dic2);
//System.IO.File.WriteAllBytes(System.Web.HttpContext.Current.Server.MapPath("~/temp.pdf"), ms.ToArray());
return ms.ToArray();
}
标签:pdf,digital-signature,hash,c 来源: https://codeday.me/bug/20191026/1933793.html