在WebService中使用RSA进行加密和解密操作时,出现的一种异常的解决。(转帖自微软社区)

"CSP for this implementation could not be acquired" CryptographicException error during instantiation

SYMPTOMS

If you create an instance of the .NET RSACryptoServiceProvider class or DSACryptoServiceProvider class either directly or indirectly through the SignedXml class, you may receive the following CryptographicException class exception:
System.Security.Cryptography.CryptographicException:
CryptoAPI cryptographic service provider (CSP) for
this implementation could not be acquired.
at System.Security.Cryptography.RSACryptoServiceProvider
..ctor(Int32 dwKeySize, CspParameters parameters,
Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider
..ctor(CspParameters parameters)
You may receive this CryptographicException error message when the .NET code is run in a Web service, a COM+ component, or an Active Server Pages (ASP) page.

CAUSE

Underlying base, enhanced, or strong cryptographic service provider (CSP) implementations create a key container for storing an RSA public/private asymmetric key pair. Key containers are stored in user profiles. For performance reasons, the user profile is not loaded by the system under a scenario where the .NET code runs in a Web service, ASP page, or COM+. If the user profile is not loaded, a key container cannot be opened or created. Because a key container is required for RSACryptoServiceProvider or DSACryptoServiceProvider, the .NET code (when run from a Web Service, ASP Page, or COM+) fails by throwing the exception described in the "Symptoms" section of this article. If the same .NET code is run from the context of the interactive logged-on user, where the user profile is loaded by Winlogon, a key container can be created and opened, and the code works under this scenario.

RESOLUTION

You have to instruct RSACryptoServiceProvider or DSACryptoServiceProvider to use machine key store (as in the following sample code) in scenarios such as a Web service, ASP Page, or COM+, where the user profile is not loaded by the system for performance reasons. You can use the CspParameters parameter in the RSACryptoServiceProvider() constructor, as follows.
CspParameters CSPParam = new CspParameters();
CSPParam.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(CSPParam);
				
The following C# sample code demonstrates how to use the machine key store when RSACryptoServiceProvider is used indirectly by the SignedXml class while signing an XML file or verifying a signed XML file. This sample code assumes that the XML file was signed by using RSA keys. The sample code signs an input XML file. The signed file is stored in EnvelopingSig.xml, which is then verified.
using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace XmlSample
{
    public class XmlDigitalSigning
    {
        public enum SigType
        {
            Detached = 1,
            Enveloping = 2,
            Enveloped = 3
        }

        public SignedXml Sign(String Uri, RSACryptoServiceProvider rsa, SigType type)
        {
            // Create the SignedXml message.
            SignedXml xmlSign = new SignedXml();
            // Set the RSA key for signing.
            xmlSign.SigningKey = rsa;

            // Create a Reference to point to the to-be-signed content.
            Reference reference = new Reference();

            if (type == SigType.Detached)
            {
                reference.Uri = Uri;
            }
            else if (type == SigType.Enveloping)
            {
                XmlDocument doc = new XmlDocument();
                DataObject obj = new DataObject();
                doc.Load(Uri);
                obj.Data = doc.ChildNodes;
                obj.Id = "MyObjectId";
                reference.Uri = "#" + "MyObjectId";
                xmlSign.AddObject(obj);
            }

            // Add the Reference to the SignedXml message.
            xmlSign.AddReference(reference);
            // Add a KeyInfo element to the SignedXml message.
            KeyInfo keyInfo = new KeyInfo();
            keyInfo.AddClause(new RSAKeyValue((RSA)rsa));
            xmlSign.KeyInfo = keyInfo;

            // Compute the XML Digital Signature.
            xmlSign.ComputeSignature();
            return xmlSign;
        }

        public bool Verify(String signedxmlFile)
        {
            bool bResult = false;

            FileStream inputStream = new FileStream(signedxmlFile, FileMode.Open);

            // Load the XML.
            XmlDocument doc = new XmlDocument();
            XmlTextReader xtr = new XmlTextReader(inputStream);
            doc.Load(xtr);

            // Get RSAKeyValue Element from the signed XML.
            SignedXml signedXml = new SignedXml();
            XmlNodeList rsaKeyValueNodes = doc.GetElementsByTagName("RSAKeyValue");
            XmlElement rsaKeyValueElement = (XmlElement) rsaKeyValueNodes.Item(0);
            String rsaKeyValueString = rsaKeyValueElement.OuterXml;

            // Remove the KeyInfo node from the SignedXml signature.
            XmlNodeList KeyInfoNode = doc.GetElementsByTagName("KeyInfo");
            XmlElement keyInfoElement = (XmlElement) KeyInfoNode.Item(0);
            XmlElement signatureElement = (XmlElement) keyInfoElement.ParentNode;
            // Console.WriteLine("****");
            // Console.WriteLine(keyInfoElement.OuterXml);
            // Console.WriteLine("****");
            // Console.WriteLine(signatureElement.OuterXml);
            // Console.WriteLine("****");
            signatureElement.RemoveChild(keyInfoElement);
            // Console.WriteLine(doc.DocumentElement.OuterXml);
            // Console.WriteLine("****");

            // Use machine key store.
            CspParameters cspParams = new CspParameters();
            cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
            rsaKey.FromXmlString(rsaKeyValueString);

            // Set the keyInfo.
            KeyInfo keyInfo = new KeyInfo();
            keyInfo.AddClause(new RSAKeyValue(rsaKey));
            signedXml.KeyInfo = keyInfo;

            // Load the signature.
            signedXml.LoadXml(doc.DocumentElement);

            AsymmetricAlgorithm key;
            if (signedXml.CheckSignatureReturningKey(out key))
            {
                bResult = true;
            }
            else
            {
                bResult = false;
            }

            return bResult;
        }
    }
    class XmlSampleCode
    {
        static void Main(string[] args)
        {
            int nArgs;

            // args[1] - XML file to be signed
            nArgs = args.Length;
            if (nArgs < 1)
            {
                Environment.Exit(-1);
            }
            for (int i = 0; i < nArgs; i++)
            {
                Console.WriteLine("Args[{0}] = {1}", i, args[i]);
            }
            try
            {
               CspParameters cspParams = new CspParameters();
               cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
               RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams);

                XmlDocument xmlOutput = new XmlDocument();
                XmlDigitalSigning digSign = new XmlDigitalSigning();
                SignedXml xmlSign;

                xmlSign = digSign.Sign(args[0], rsa, XmlDigitalSigning.SigType.Enveloping);
                XmlTextWriter xmltw = new XmlTextWriter("EnvelopingSig.xml", new UTF8Encoding(false));
                xmltw.Formatting = Formatting.Indented;
                xmlOutput.InnerXml = xmlSign.GetXml().OuterXml;
                xmlOutput.WriteTo(xmltw);
                xmltw.Flush();
                xmltw.Close();

                if (digSign.Verify("EnvelopingSig.xml"))
                {
                    Console.WriteLine("Signature has been verified successfully");
                }
                else
                {
                    Console.WriteLine("Signature verification failed");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("/nException Information : /n/n{0}", e.ToString());
            }
            return;
        }
    }
}
				

STATUS

This behavior is by design.

MORE INFORMATION

The exception described in the "Symptoms" section of this article also occurs if the application specifies the name of a machine key store in CspParameters, and the calling security context does not have the permissions to open it.

If the caller is running under the SYSTEM security context, CSP implementations automatically redirect to the machine key container.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值