2017-04-09 25 views
2

我想在两台服务器上使用两个Web服务签名PDF文档。但它在Adobe Reader中显示“文档已被更改或损坏”。任何人都可以提出下面的代码有什么问题。PDF签名 - 嵌入独立签名散列

程序 1.服务器A上的Web服务(WS),从PDF生成哈希并发送到服务器B上的WS进行签名。 2.服务器B上的WS签名散列。 3.服务器A上的WS接收签名散列并嵌入到PDF文档中。

CODE

GENERATE HASH

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(); 
    } 
+0

你的所作所为六角+ base64编码的第一步(为什么有的话),而我无法找到在SND步decodeing任何的base64? –

+0

十六进制编码仅在散列上完成。 Base64编码是在PDF内容和证书内容上完成的。上面没有包含64位的文件解码,因为问题在散列签名部分。 – Matt

+0

在'generateHash'中,您使用'SHA256Managed'来计算散列值,但是在'Page_Load'中,您可以使用从'PrivateKeySignature'中检索到的散列算法实例化'PdfPKCS7',并用'SHA1''初始化。你确定比赛吗? – mkl

回答

3

对于那些有兴趣谁我张贴的答案。 我结束了使用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(); 

    } 
+0

感谢您花时间分享代码。你能分享完整的代码以便更好的理解吗? –