首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在C#中生成数字签名的XML文档的.sig?

如何在C#中生成数字签名的XML文档的.sig?
EN

Stack Overflow用户
提问于 2017-07-01 12:57:51
回答 1查看 788关注 0票数 1

我有用数字签名签署xml文件的要求,用这个文件我需要生成数字签名的xml的.sig文件。我使用PKCS7算法来实现同样的效果。我能够成功地将签名放入xml中。但无法生成.sig文件。我的代码如下:

代码语言:javascript
复制
public static void SignXmlDocumentWithCertificate(XmlDocument doc, X509Certificate2 cert)
{
    SignedXml signedxml = new SignedXml(doc);
    signedxml.SigningKey = cert.PrivateKey;
    Reference reference = new Reference();
    reference.Uri = "";
    reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
    signedxml.AddReference(reference);

    KeyInfo keyinfo = new KeyInfo();
    keyinfo.AddClause(new KeyInfoX509Data(cert));

    signedxml.KeyInfo = keyinfo;
    signedxml.ComputeSignature();

    XmlElement xmlsig = signedxml.GetXml();
    doc.DocumentElement.AppendChild(doc.ImportNode(xmlsig, true));
    //Console.WriteLine(doc.ImportNode(xmlsig,true));
}

现在我生成的.sig文件如下:

代码语言:javascript
复制
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaParameters);

byte[] ciphertext = rsa.Encrypt(keyBytes, false);
string cipherresult = Convert.ToBase64String(ciphertext);
Console.WriteLine(cipherresult);

这将引发长度错误\r\n。我的xml经过数字签名后为:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<CATALOG>
 <PLANT>
    <COMMON>Grecian Windflower</COMMON>
    <BOTANICAL>Anemone blanda</BOTANICAL>
    <ZONE>6</ZONE>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>$9.16</PRICE>
    <AVAILABILITY>071099</AVAILABILITY>
</PLANT>
</CATALOG>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    <Reference URI="">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
     </Transforms>
     <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>

     <DigestValue>/VUzr4wRNv2e6SzE6TdHLM8c+/A=</DigestValue>

    </Reference>

    </SignedInfo>
    <SignatureValue>i3gGf2Q......8Q==</SignatureValue>
    <KeyInfo>
    <X509Data>
      <X509Certificate>MIID6D.......fFo=</X509Certificate>
    </X509Data>
    </KeyInfo>

</Signature>

</xml>

现在我知道我要么是做错了,要么是我错过了什么。我的问题是

  1. 有没有办法生成带有签名的.sig文件?
  2. 在PKCS7中是否可以处理大的xml文件?

我的要求是:

  1. 数字签名将作为PKCS7信封的一部分生成为普通字节。PKCS7信封将包含用于签名的证书以及数字签名本身。
  2. PKCS7信封将不使用base-64编码。它将不包含任何开始和结束标识符。将一个字节序列的明文PKCS7信封写入到.sig文件中,对报文摘要采用SHA-2(512bits)算法,加密算法采用

-2048(encryption

)生成数字签名

EN

回答 1

Stack Overflow用户

发布于 2017-07-01 19:31:10

尝试下面的代码。我把你的代码和来自msdn的示例合并了。我还在PC上使用了默认的用户证书:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(FILENAME);
            string computerName = Environment.GetEnvironmentVariable("COMPUTERNAME");
            string userName = Environment.GetEnvironmentVariable("USERNAME");
            X509Certificate2 cert = GetCertificateFromStore("CN=" + computerName + "\\" + userName);

            SignXmlDocumentWithCertificate(doc, cert);
            RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;

            byte[] unencryptedData = Encoding.UTF8.GetBytes(doc.OuterXml); 
            Stream stream = EncryptFile(unencryptedData,publicKey);

            Console.ReadLine();

        }
        public static void SignXmlDocumentWithCertificate(XmlDocument doc, X509Certificate2 cert)
        {
            SignedXml signedxml = new SignedXml(doc);
            signedxml.SigningKey = cert.PrivateKey;
            Reference reference = new Reference();
            reference.Uri = "";
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            signedxml.AddReference(reference);

            KeyInfo keyinfo = new KeyInfo();
            keyinfo.AddClause(new KeyInfoX509Data(cert));

            signedxml.KeyInfo = keyinfo;
            signedxml.ComputeSignature();

            XmlElement xmlsig = signedxml.GetXml();
            doc.DocumentElement.AppendChild(doc.ImportNode(xmlsig, true));
            //Console.WriteLine(doc.ImportNode(xmlsig,true));

        }

        private static X509Certificate2 GetCertificateFromStore(string certName)
        {

            // Get the certificate store for the current user.
            X509Store store = new X509Store(StoreLocation.CurrentUser);
            try
            {
                store.Open(OpenFlags.ReadOnly);

                // Place all certificates in an X509Certificate2Collection object.
                X509Certificate2Collection certCollection = store.Certificates;
                // If using a certificate with a trusted root you do not need to FindByTimeValid, instead:
                // currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, true);
                X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
                X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, false);
                if (signingCert.Count == 0)
                    return null;
                // Return the first certificate in the collection, has the right name and is current.
                return signingCert[0];
            }
            finally
            {
                store.Close();
            }

        }
        // Encrypt a file using a public key.
        private static MemoryStream  EncryptFile(byte[] unencryptedData, RSACryptoServiceProvider rsaPublicKey)
        {
            MemoryStream stream = null;

            using (AesManaged aesManaged = new AesManaged())
            {
                // Create instance of AesManaged for
                // symetric encryption of the data.
                aesManaged.KeySize = 256;
                aesManaged.BlockSize = 128;
                aesManaged.Mode = CipherMode.CBC;
                using (ICryptoTransform transform = aesManaged.CreateEncryptor())
                {
                    RSAPKCS1KeyExchangeFormatter keyFormatter = new RSAPKCS1KeyExchangeFormatter(rsaPublicKey);
                    byte[] keyEncrypted = keyFormatter.CreateKeyExchange(aesManaged.Key, aesManaged.GetType());

                    // Create byte arrays to contain
                    // the length values of the key and IV.
                    byte[] LenK = new byte[4];
                    byte[] LenIV = new byte[4];

                    int lKey = keyEncrypted.Length;
                    LenK = BitConverter.GetBytes(lKey);
                    int lIV = aesManaged.IV.Length;
                    LenIV = BitConverter.GetBytes(lIV);

                    // Write the following to the FileStream
                    // for the encrypted file (outFs):
                    // - length of the key
                    // - length of the IV
                    // - ecrypted key
                    // - the IV
                    // - the encrypted cipher content


                    stream = new MemoryStream();
                    try
                    {

                        stream.Write(LenK, 0, 4);
                        stream.Write(LenIV, 0, 4);
                        stream.Write(keyEncrypted, 0, lKey);
                        stream.Write(aesManaged.IV, 0, lIV);

                        // Now write the cipher text using
                        // a CryptoStream for encrypting.
                        CryptoStream outStreamEncrypted = new CryptoStream(stream, transform, CryptoStreamMode.Write);
                        try
                        {

                            // By encrypting a chunk at
                            // a time, you can save memory
                            // and accommodate large files.
                            int count = 0;
                            int offset = 0;

                            // blockSizeBytes can be any arbitrary size.
                            int blockSizeBytes = aesManaged.BlockSize / 8;

                            do
                            {
                                if (offset + blockSizeBytes <= unencryptedData.Length)
                                {
                                    count = blockSizeBytes;
                                }
                                else
                                {
                                    count = unencryptedData.Length - offset;
                                }
                                outStreamEncrypted.Write(unencryptedData, offset, count);
                                offset += count;
                            }
                            while (offset < unencryptedData.Length);

                            outStreamEncrypted.FlushFinalBlock();
                        }
                        catch(Exception ex)
                        {
                            Console.WriteLine("Error : {0}", ex.Message);
                        }
                    }
                    catch(Exception ex)
                    {
                        Console.WriteLine("Error : {0}", ex.Message);
                    }
                    stream.Position = 0;
                }
            }
            return stream;
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44857481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档