PDF签名 - 嵌入分离签名的哈希

时间:2017-04-09 07:18:30

标签: c# pdf hash digital-signature

我正在尝试使用两台服务器中的两个Web服务签署PDF文档。但它显示"文件自签署后已被更改或损坏"在Adobe Reader中。任何人都可以在下面的代码中提出错误。

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

CODE

生成哈希

 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;
    }

SIGN HASH

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

1 个答案:

答案 0 :(得分:4)

对于那些感兴趣的人我会发布答案。 我最终使用了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();

    }