我要求使用数字签名签署xml文档,并且需要生成该文档,我需要生成数字签名xml的.sig文件。我正在使用PKCS7算法。我能够成功地将签名放入xml中。但是无法生成.sig文件。我的代码如下:
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>
现在我知道我要么以错误的方式做,要么我错过了一些东西。我的问题是
我的要求是:
答案 0 :(得分:0)
尝试以下代码。我将您的代码与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;
}
}
}