c# - PDF 签名 - 嵌入单独签名的哈希

标签 c# pdf hash digital-signature

我正在尝试使用两个服务器中的两个 Web 服务来签署 PDF 文档。但它在 Adob​​e 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();

    }

关于c# - PDF 签名 - 嵌入单独签名的哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43304062/

相关文章:

c# - 在打印文档时设置打印选项

c# - 如何为此类编写哈希码生成器?

C++:关于字符串序列的散列函数的建议,其中字符串的顺序无关紧要

c# - Mono.Simd Vector3( float )丢失了吗?

java - 拆分/合并时某些 PDF 的间接对象出现错误

c# - 在 ASP.NET WebAPI 中使用 HttpContext.Current

javascript - 为什么从 PDF 复制时缺少格式

java - 元素存在但 `Set.contains(element)` 返回 false

c# - 如何在不使用 foreach 的情况下获得字典中嵌套列表的计数总和?

c# - 从 F# 代码使用 C# 中定义的扩展方法