如何在C#中生成数字签名XML文档的.sig XML?
我需要使用数字签名对xml文档进行签名,并使用该文档生成数字签名xml的.sig文件。我正在使用PKCS7算法进行同样的操作。我能够成功地将签名放入xml中。但无法生成.sig文件。我的代码如下:如何在C#中生成数字签名XML文档的.sig XML?,c#,xml,digital-signature,pkcs#7,xml-signature,C#,Xml,Digital Signature,Pkcs#7,Xml Signature,我需要使用数字签名对xml文档进行签名,并使用该文档生成数字签名xml的.sig文件。我正在使用PKCS7算法进行同样的操作。我能够成功地将签名放入xml中。但无法生成.sig文件。我的代码如下: public static void SignXmlDocumentWithCertificate(XmlDocument doc, X509Certificate2 cert) { SignedXml signedxml = new SignedXml(doc); signedxml
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文件,如下所示:
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是:
<?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>
希腊风花
希腊银莲花
6.
大部分是阴凉的
$9.16
071099
/VUzr4wRNv2e6SzE6TdHLM8c+/A=
i3gGf2Q……8Q==
MIID6D………fFo=
现在我知道我不是做错了,就是错过了什么。我的问题是
试试下面的代码。我将您的代码与msdn中的示例合并。我还使用了PC上的默认用户证书:
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;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Xml;
使用系统安全;
使用System.Security.Cryptography;
使用System.Security.Cryptography.X509证书;
使用System.Security.Cryptography.Xml;
使用System.IO;
命名空间控制台应用程序1
{
班级计划
{
常量字符串文件名=@“c:\temp\test.xml”;
静态void Main(字符串[]参数)
{
XmlDocument doc=新的XmlDocument();
doc.Load(文件名);
字符串computerName=Environment.GetEnvironmentVariable(“computerName”);
字符串userName=Environment.GetEnvironmentVariable(“用户名”);
X509Certificate2 cert=GetCertificateFromStore(“CN=”+computerName+“\\”+用户名);
签署XmlDocumentWithCertificate(文件、证书);
rsacyptoserviceprovider publicKey=(rsacyptoserviceprovider)cert.publicKey.Key;
byte[]unencryptedData=Encoding.UTF8.GetBytes(doc.OuterXml);
流=加密文件(未加密数据,公钥);
Console.ReadLine();
}
公共静态无效签名XmlDocumentWithCertificate(XmlDocument文档,X509Certificate2证书)
{
SignedXml SignedXml=新的SignedXml(doc);
signedxml.SigningKey=cert.PrivateKey;
引用=新引用();
reference.Uri=“”;
AddTransform(新的XMLDSIGenveledSignatureTransform());
signedxml.AddReference(参考);
KeyInfo KeyInfo=新的KeyInfo();
keyinfo.AddClause(新的KeyInfoX509Data(cert));
signedxml.KeyInfo=KeyInfo;
signedxml.ComputeSignature();
xmlement xmlsig=signedxml.GetXml();
doc.DocumentElement.AppendChild(doc.ImportNode(xmlsig,true));
//Console.WriteLine(doc.ImportNode(xmlsig,true));
}
私有静态X509Certificate2 GetCertificateFromStore(字符串certName)
{
//获取当前用户的证书存储。
X509Store=新的X509Store(StoreLocation.CurrentUser);
尝试
{
打开(OpenFlags.ReadOnly);
//将所有证书放置在X509Certificate2Collection对象中。
X509Certificate2Collection certCollection=store.Certificates;
//如果使用具有受信任根的证书,则不需要FindByTimeValid,而是:
//currentCerts.Find(X509FindType.FindBySubjectDifferentizedName,certName,true);
X509Certificate2Collection currentCerts=certCollection.Find(X509FindType.FindByTimeValid,DateTime.Now,false);
X509Certificate2Collection signingCert=currentCerts.Find(X509FindType.FindBySubjectDifferentizedName,certName,false);
如果(signingCert.Count==0)
返回null;
//返回集合中的第一个证书,该证书具有正确的名称且为当前证书。
返回签名证书[0];
}
最后
{
store.Close();
}
}
//使用公钥加密文件。
私有静态内存流加密文件(字节[]未加密数据,RSACryptServiceProvider RSAPPublicKey)
{
MemoryStream stream=null;
使用(AesManaged AesManaged=新AesManaged())
{
//为创建托管的AES实例
//数据的对称加密。
aesManaged.KeySize=256;
AES.BlockSize=128;
aes.Mode=CipherMode.CBC;
使用(ICryptoTransform transform=aesManaged.CreateEncryptor())
{
RSAPKCS1KeyExchangeFormatter keyFormatter=新的RSAPKCS1KeyExchangeFormatter(rsaPublicKey);
byte[]keyEncrypted=keyFormatter.CreateKeyExchange(aesManaged.Key,aesManaged.GetType());
//创建要包含的字节数组
//键和IV的长度值。
字节[]LenK=新字节[4];
字节[]LenIV=新字节[4];
int lKey=密钥加密的.Length;
LenK=比特变换器