<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Decrypt my World : CryptAcquireContext</title><link>http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx</link><description>Tags: CryptAcquireContext</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>"Invalid provider type specified" error when accessing X509Certificate2.PrivateKey on CNG certificates</title><link>http://blogs.msdn.com/alejacma/archive/2009/12/22/invalid-provider-type-specified-error-when-accessing-x509certificate2-privatekey.aspx</link><pubDate>Tue, 22 Dec 2009 09:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9940002</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9940002.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9940002</wfw:commentRss><description>&lt;P&gt;Hi all,&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You may get the following &lt;STRONG&gt;exception&lt;/STRONG&gt; when trying to access &lt;A href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.privatekey.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.privatekey.aspx"&gt;X509Certificate2&lt;SPAN class=nu&gt;.&lt;/SPAN&gt;PrivateKey&lt;/A&gt; on a &lt;STRONG&gt;.NET 3.5&lt;/STRONG&gt; (or older) app:&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;System.Security.Cryptography.&lt;STRONG&gt;CryptographicException&lt;/STRONG&gt;: &lt;STRONG&gt;Invalid provider type specified&lt;/STRONG&gt;.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)&lt;BR&gt;at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle&amp;amp; safeProvHandle, SafeKeyHandle&amp;amp; safeKeyHandle)&lt;BR&gt;at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()&lt;BR&gt;at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)&lt;BR&gt;at System.Security.Cryptography.X509Certificates.&lt;STRONG&gt;X509Certificate2.get_PrivateKey&lt;/STRONG&gt;()&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;When this happened to me, I used my &lt;A href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer&lt;/A&gt; on the problematic app to find out which CryptoAPI was failing&amp;nbsp;and causing that exception. This was the one:&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;CryptAcquireContextA&lt;/STRONG&gt; (0x448)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;IN&lt;BR&gt;pszContainer&lt;BR&gt;0078a948 "anycontainername"&lt;BR&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;pszProvider&lt;BR&gt;00773fb8 "&lt;STRONG&gt;Microsoft Software Key Storage P&lt;/STRONG&gt;"&lt;BR&gt;00773fd8 "&lt;STRONG&gt;rovider&lt;/STRONG&gt;"&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;dwProvType&lt;BR&gt;0&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;dwFlags&lt;BR&gt;0&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;OUT&lt;BR&gt;hProv&lt;BR&gt;NULL&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;RESULT&lt;BR&gt;CryptAcquireContextA (0x448) FAILED&lt;BR&gt;&lt;STRONG&gt;LastErrorValue&lt;/STRONG&gt;: (HRESULT) &lt;STRONG&gt;0x80090014&lt;/STRONG&gt; (2148073492) - &lt;STRONG&gt;Invalid provider type specified&lt;/STRONG&gt;.&lt;BR&gt;LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;So the &lt;STRONG&gt;certificate&lt;/STRONG&gt; I was using was associated to &lt;STRONG&gt;Microsoft Software Key Storage Provider&lt;/STRONG&gt;, which&amp;nbsp;is not a &lt;STRONG&gt;CSP&lt;/STRONG&gt; but a &lt;STRONG&gt;KSP&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/bb931355(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb931355(VS.85).aspx"&gt;CNG Key Storage Providers&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;Unlike Cryptography API (CryptoAPI), &lt;STRONG&gt;Cryptography API: Next Generation (CNG)&lt;/STRONG&gt; separates cryptographic providers from &lt;STRONG&gt;key storage providers (KSPs)&lt;/STRONG&gt;. KSPs can be used to create, delete, export, import, open and store keys. Depending on implementation, they can also be used for asymmetric encryption, secret agreement, and signing. Microsoft installs the following KSPs &lt;STRONG&gt;beginning with Windows Vista and Windows Server 2008&lt;/STRONG&gt;.&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;This is a &lt;STRONG&gt;CNG certificate&lt;/STRONG&gt;! This is what &lt;STRONG&gt;CertUtil.exe&lt;/STRONG&gt; returns on the private key of that certificate:&lt;/P&gt;
&lt;P&gt;"&lt;BR&gt;&lt;EM&gt;Key Container = ...&lt;BR&gt;Unique container name: ...&lt;BR&gt;&lt;STRONG&gt;Provider&lt;/STRONG&gt; = &lt;STRONG&gt;Microsoft Software Key Storage Provider&lt;/STRONG&gt;&lt;BR&gt;Private key is NOT exportable&lt;BR&gt;Encryption test passed&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;So certutil.exe knows how to deal with this kind of CNG certificates. I used my CryptoAPI Tracer on CertUtil, and this tool is using &lt;STRONG&gt;CryptAcquireCertificatePrivateKey&lt;/STRONG&gt; &lt;STRONG&gt;instead of CryptAcquireContext&lt;/STRONG&gt; to access the keys of the cert. CryptAcquireCertificatePrivateKey has specific &lt;STRONG&gt;flags&lt;/STRONG&gt; to deal with &lt;STRONG&gt;CNG&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx"&gt;CryptAcquireCertificatePrivateKey Function&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG&lt;/STRONG&gt;&lt;BR&gt;This function will attempt to obtain the key by using CryptoAPI. If that fails, this function will attempt to obtain the key by using the Cryptography API: Next Generation (CNG).&lt;BR&gt;The pdwKeySpec variable receives the CERT_NCRYPT_KEY_SPEC flag if CNG is used to obtain the key.&lt;BR&gt;...&lt;BR&gt;pdwKeySpec [out] &lt;BR&gt;CERT_NCRYPT_KEY_SPEC&lt;BR&gt;The key is a CNG key.&lt;/EM&gt;&lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;.NET is not CNG aware yet (at least up to version 3.5 SP1)&lt;/STRONG&gt;. It uses CryptAcquireContext instead of CryptAcquireCertificatePrivateKey and CryptAcquireContext has no flags to deal with CNG. &lt;/P&gt;
&lt;P&gt;A possible &lt;STRONG&gt;workaround&lt;/STRONG&gt; to this may be to &lt;STRONG&gt;use CryptoAPI/CNG API directly&lt;/STRONG&gt; to deal with CNG keys. That is what certutil.exe does. But if&amp;nbsp;we want&amp;nbsp;an easier and&amp;nbsp;&lt;STRONG&gt;pure .NET solution&lt;/STRONG&gt; which understands CNG, this will help to implement it:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.codeplex.com/clrsecurity" mce_href="http://www.codeplex.com/clrsecurity"&gt;CLR Security&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;Security.Cryptography.dll&lt;/STRONG&gt; provides a new set of algorithm implementations to augment the built in .NET framework supported algorithms. It also provides some APIs to extend the existing framework cryptography APIs. Within this project you will find:&lt;BR&gt;§ A CNG implementation of the AES, RSA, and TripleDES encryption algorithms &lt;BR&gt;§ A CNG implementation of a random number generator &lt;BR&gt;§ A class that allows dynamically creating algorithms both from this library as well as all of the algorithms that ship with .NET 3.5 &lt;BR&gt;§ An enumerator over all of the installed CNG providers on the current machine &lt;BR&gt;§ Extension methods that allow access to all of the keys installed in a CNG provider, as well as all of the algorithms the provider supports&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;If you want to use CNG with this dll, you have to do the following:&lt;/P&gt;
&lt;P&gt;1) Change .NET version to 3.5. As far as I know the dll requires us to move at least to that version.&lt;/P&gt;
&lt;P&gt;2) Reference Security.Cryptography.dll in your project.&lt;/P&gt;
&lt;P&gt;3) Include "using Security.Cryptography.X509Certificates;" statement (in C#, of course)&amp;nbsp;to &lt;STRONG&gt;activate CNG extensions&lt;/STRONG&gt; for standard &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt; class.&lt;/P&gt;
&lt;P&gt;Then you may check whether the cert has a CNG key using the extension&lt;STRONG&gt; .HasCngKey()&lt;/STRONG&gt; for X509Certificate2. If you have a CNG key, you can then instantiate an &lt;STRONG&gt;RSACng&lt;/STRONG&gt; object using the extension &lt;STRONG&gt;.GetCngPrivateKey()&lt;/STRONG&gt; for X509Certificate2. You can then i.e. decrypt with &lt;STRONG&gt;RSACng.DecryptValue()&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9940002" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CNG/default.aspx">CNG</category></item><item><title>CryptographicException: Unable to open the access token of the current thread</title><link>http://blogs.msdn.com/alejacma/archive/2008/07/30/cryptographicexception-unable-to-open-the-access-token-of-the-current-thread.aspx</link><pubDate>Wed, 30 Jul 2008 10:41:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8791188</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8791188.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8791188</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;When working with &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt;, we may get an exception like the following:&lt;/P&gt;&lt;PRE&gt;System.Security.Cryptography.&lt;STRONG&gt;CryptographicException&lt;/STRONG&gt;: &lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;
   at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
   at System.Security.Cryptography.Utils._GetKeyParameter(SafeKeyHandle hKey, UInt32 paramID)
   at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle&amp;amp; safeProvHandle, SafeKeyHandle&amp;amp; safeKeyHandle)
   at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
&lt;/PRE&gt;
&lt;P&gt;I've seen this exception i.e. when signing an XML with a certificate associated to a specific Cryptographic Service Provider (CSP).&lt;/P&gt;
&lt;P&gt;Let's use my &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt;&amp;nbsp;to get all &lt;STRONG&gt;CryptoAPI calls&lt;/STRONG&gt; that .NET is making &lt;STRONG&gt;behind the scenes&lt;/STRONG&gt;. This will help us to know exactly what's going on.&lt;/P&gt;
&lt;P&gt;We can see in the logs generated by the script the call to &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; we make to get the &lt;STRONG&gt;key container&lt;/STRONG&gt; of the certificate. We can&amp;nbsp;also see the &lt;STRONG&gt;CSP&lt;/STRONG&gt; associated to the certificate:&lt;/P&gt;&lt;PRE&gt;&lt;STRONG&gt;CryptAcquireContextA&lt;/STRONG&gt; (0xd8c)

IN
pszContainer
00228620  "2e065b6c-027a-4746-bdf3-901a9980"
00228640  "66ea"

pszProvider
00205e60  "&lt;STRONG&gt;Third-party CSP&lt;/STRONG&gt;"

dwProvType
PROV_RSA_FULL

dwFlags
0

OUT
hProv
0x228248

RESULT
CryptAcquireContextA (0xd8c) SUCCEEDED
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;Note: I won't use the real name of the third-party CSP where I detected this issue. This post is for illustration purposes only. I don't prettend to blame anyone in particular.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Then .NET makes the following call to &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa379949.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa379949.aspx"&gt;CryptGetKeyParam&lt;/A&gt; to find out the &lt;STRONG&gt;size of a buffer&lt;/STRONG&gt; which will hold the value of the &lt;STRONG&gt;algorithm&lt;/STRONG&gt; &lt;STRONG&gt;of the key&lt;/STRONG&gt;:&lt;/P&gt;&lt;PRE&gt;&lt;STRONG&gt;CryptGetKeyParam&lt;/STRONG&gt; (0xd8c)

&lt;STRONG&gt;IN&lt;/STRONG&gt;
hKey
0x230058

&lt;STRONG&gt;dwParam&lt;/STRONG&gt;
&lt;STRONG&gt;KP_ALGID&lt;/STRONG&gt;

&lt;STRONG&gt;pbData&lt;/STRONG&gt;
&lt;STRONG&gt;NULL&lt;/STRONG&gt; 

&lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;
&lt;STRONG&gt;0&lt;/STRONG&gt;

dwFlags
0

&lt;STRONG&gt;OUT&lt;/STRONG&gt;
&lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;
&lt;STRONG&gt;4&lt;/STRONG&gt;

RESULT
CryptGetKeyParam (0xd8c) FAILED
LastErrorValue: (HRESULT) &lt;STRONG&gt;0x80010125&lt;/STRONG&gt; (2147549477) - &lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;
LastStatusValue: (NTSTATUS) 0xc0000034 - Object Name not found.
&lt;/PRE&gt;
&lt;P&gt;Note on &lt;STRONG&gt;IN parameters&lt;/STRONG&gt;: &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;hKey&lt;/STRONG&gt; value is the key handle. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;dwParam&lt;/STRONG&gt; value indicates that we want the algorithm of the key. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;pbData&lt;/STRONG&gt; value indicates that there is no buffer available yet. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;pdwDataLen&lt;/STRONG&gt; value is 0 because we want to find out the size that we need for the pbData buffer. &lt;/P&gt;
&lt;P&gt;- &lt;STRONG&gt;dwFlags&lt;/STRONG&gt; should always be 0. &lt;/P&gt;
&lt;P&gt;This call is returning 4 in &lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;, which is correct as the &lt;STRONG&gt;ALGID&lt;/STRONG&gt; will be 4 bytes long. But the API is also returning the error &lt;STRONG&gt;0x80010125&lt;/STRONG&gt; (2147549477) - "&lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;". CryptoAPI just passes the parameters to the CSP and returns the results. The&amp;nbsp;call to the API is 100% correct, but the CSP is not honoring it. This is &lt;STRONG&gt;not a bug in .NET or CryptoAPI&lt;/STRONG&gt;. This is a &lt;STRONG&gt;bug on the CSP&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;If you are facing this issue please &lt;STRONG&gt;contact the CSP&amp;nbsp;provider&lt;/STRONG&gt;. At least in&amp;nbsp;the case of the third-party CSP where we found the issue they were already aware of it. They immediately sent an upgrade to our customers which fixed this issue.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8791188" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugger+scripts/default.aspx">Debugger scripts</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>Threading issues with RSACryptoServiceProvider</title><link>http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-RSACryptoServiceProvider-.aspx</link><pubDate>Mon, 30 Jun 2008 16:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8671346</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8671346.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8671346</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;When using &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt; in i.e.&amp;nbsp;&lt;STRONG&gt;ASP.NET&lt;/STRONG&gt;&amp;nbsp;you may get the following exception under a heavy load scenario:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;"System.Security.Cryptography.CryptographicException: CryptoAPI cryptographic service provider (CSP) for this implementation could not be acquired".&lt;/STRONG&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;We've seen in past posts (&lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx"&gt;sample&lt;/A&gt;) how we can use my &lt;A class="" title="CryptoAPI Tracer script" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;&lt;FONT color=#006ff7&gt;CryptoAPI Tracer script&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;to take a look to the &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt;&amp;nbsp;calls that&amp;nbsp;RSACryptoServiceProvider makes behind the scenes. &lt;/P&gt;
&lt;P&gt;In this case we can see that RSACryptoServiceProvider constructor calls &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; API. The first call to CryptAcquireContext API fails with error &lt;STRONG&gt;NTE_BAD_KEYSET&lt;/STRONG&gt; ("&lt;STRONG&gt;Keyset does not exist&lt;/STRONG&gt;"). Then a second call is attempted to create the key set, but it fails with error &lt;STRONG&gt;NTE_EXISTS&lt;/STRONG&gt; ("&lt;STRONG&gt;Object already exists&lt;/STRONG&gt;"). So it seems the keyset is there, but it can't be accessed. Concurrency issues? Maybe. Check this article first to verify that we don't get these errors for another reason: &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx"&gt;CryptAcquireContext fails with NTE_BAD_KEYSET&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;So we are having concurrency issues.&amp;nbsp;Consider the application performs the following sequence in two steps:&lt;BR&gt;1) Open a given named machine key container.&lt;BR&gt;2) If open fails, create that named machine key container.&lt;/P&gt;
&lt;P&gt;This sequence is not an automatic operation. If multiple threads are attempting to do the same sequence and assume 2 threads attempt to create the same named machine key container, the second call will fail with "key container already exists". &lt;/P&gt;
&lt;P&gt;As we've seen this is what RSACryptoServiceProvider constructor&amp;nbsp;does similar to any application calling CryptAcquireContext API&amp;nbsp;twice.&lt;/P&gt;
&lt;P&gt;If the application is always working with the same RSA key in a named key container, key containers must be acquired only once in the process using CryptAcquireContext. When multiple threads are using the same RSA instance for encryption/decryption, the instance methods are &lt;STRONG&gt;not&lt;/STRONG&gt; &lt;STRONG&gt;thread safe&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;At the &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; level we've already seen &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-CryptoAPI.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-CryptoAPI.aspx"&gt;threading issues&lt;/A&gt; when dealing with key handles in applications. When calling CryptoAPI directly we have a lot more control when the key handle is obtained, the type of handle, how it is used and whether it is thread safe. e.g. After a RSA key handle has been obtained by using the &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380199(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380199(VS.85).aspx"&gt;CryptGetUserKey &lt;/A&gt;function, RSA operations are thread safe.&lt;/P&gt;
&lt;P&gt;There is not much control when using RSACryptoServiceProvider as it doesn’t expose key handles.&lt;/P&gt;
&lt;P&gt;These are some &lt;STRONG&gt;suggestions&lt;/STRONG&gt; to minimize threading issues in ASP.NET:&lt;/P&gt;
&lt;P&gt;1) Set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.keycontainername.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.keycontainername.aspx"&gt;CspParameters.KeyContainer&lt;/A&gt; name when creating an RSACryptoServiceProvider object. Never use the default one, NEVER! This is prone to store corruption. We talked about &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/05/28/don-t-use-default-key-containers-if-possible.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/05/28/don-t-use-default-key-containers-if-possible.aspx"&gt;this&lt;/A&gt; already.&lt;/P&gt;
&lt;P&gt;2) Explicitely call &lt;STRONG&gt;Dispose&lt;/STRONG&gt; on the RSACrytpoServiceProvider object when possible. This way, we don't rely on the Garbage Collector to "eventually" release the CSP.&lt;/P&gt;
&lt;P&gt;3) Set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspproviderflags.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspproviderflags.aspx"&gt;UseMachineKeyStore&lt;/A&gt; in &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.flags.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.flags.aspx"&gt;CspParameters.Flags&lt;/A&gt;&amp;nbsp;when creating an RSACryptoServiceProvider. This flag tells RSACryptoServiceProvider to use "machine location" for storing RSA public/private key pair instead of the "current user" location. This is equivalent to calling CryptAcquireContext API with &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt;. Make sure all the threads using the RSA instance are running under the same account.&lt;/P&gt;
&lt;P&gt;4) Don't set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.persistkeyincsp.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.persistkeyincsp.aspx"&gt;RSACryptoServiceProvider.PersistKeyInCSP&lt;/A&gt; to False. This will cause the key container to be deleted when RSA instance is released or garbage collected. If multiple threads are trying to access the same named key container, the state of that named key container could be in a temporary cleaned up state and it cannot be acquired.&lt;/P&gt;
&lt;P&gt;5) Another option would be for us to instantiate RSACryptoServiceProvider once as part of Web Application initialization and then use that same instance for encryption or decryption under a &lt;STRONG&gt;critical section&lt;/STRONG&gt; like lock (i.e. Mutex). This would also avoid reacquiring key container multiple times from the same process.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8671346" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>CryptAcquireContext fails with NTE_BAD_KEYSET</title><link>http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx</link><pubDate>Tue, 27 May 2008 11:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8531786</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8531786.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8531786</wfw:commentRss><description>&lt;P&gt;Hi all, &lt;/P&gt;
&lt;P&gt;When we try to access a key container, &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; may return &lt;STRONG&gt;NTE_BAD_KEYSET&lt;/STRONG&gt; (or error # &lt;STRONG&gt;0x80090016 &lt;/STRONG&gt;or &lt;STRONG&gt;-2146893802 &lt;/STRONG&gt;or "Keyset does not exist") for the following two reasons:&lt;/P&gt;
&lt;P&gt;1) &lt;STRONG&gt;key container doesn't exist&lt;/STRONG&gt;. You may repeat the call to CryptAcquireContext, but this time using &lt;STRONG&gt;CRYPT_NEWKEYSET&lt;/STRONG&gt; flag to create a new key container. &lt;/P&gt;
&lt;P&gt;2) &lt;STRONG&gt;user doesn't have&lt;/STRONG&gt; &lt;STRONG&gt;permission&lt;/STRONG&gt; to open the key container. If you need to find out where the key container is in order to set additional permissions, this post may help: &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/12/13/key-containers-basics.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/12/13/key-containers-basics.aspx"&gt;Key Containers: Basics&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Let's imagine for a sec that we are already calling CryptAcquireContext with CRYPT_NEWKEYSET&amp;nbsp;flag after the first call to CryptAcquireContext fails with error NTE_BAD_KEYSET, and this second call fails with error &lt;STRONG&gt;NTE_EXISTS&lt;/STRONG&gt; (or error # &lt;STRONG&gt;0x8009000F&lt;/STRONG&gt; or &lt;STRONG&gt;-2146893809&lt;/STRONG&gt; or "Object already exists").&amp;nbsp;First we try to open the container and we fail, then we try to create it and it already exists. NTE_BAD_KEYSET means in this case&amp;nbsp;that the user doesn't have permissions to open the key container, and not that it doesn't exist.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8531786" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>CryptAcquireContext fails with ERROR_FILE_NOT_FOUND</title><link>http://blogs.msdn.com/alejacma/archive/2008/05/22/cryptacquirecontext-fails-with-error-file-not-found.aspx</link><pubDate>Thu, 22 May 2008 15:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8531692</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8531692.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8531692</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; API will fail with &lt;STRONG&gt;error #2&lt;/STRONG&gt; or &lt;STRONG&gt;ERROR_FILE_NOT_FOUND&lt;/STRONG&gt; if:&lt;/P&gt;
&lt;P mce_keep="true"&gt;1) the &lt;STRONG&gt;user's profile&lt;/STRONG&gt; is not loaded, as we saw in my post &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx"&gt;RSACryptoServiceProvider fails when used with ASP.NET&lt;/A&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;2) &lt;STRONG&gt;AppData&lt;/STRONG&gt; registry value in the following registry key is not present or is misconfigured:&lt;/P&gt;&lt;PRE&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders&lt;/PRE&gt;
&lt;P&gt;As we saw in the other post I mentioned above, private keys are protected by &lt;STRONG&gt;DPAPI&lt;/STRONG&gt; (Data Protection API).&amp;nbsp;DPAPI needs to find the &lt;STRONG&gt;Application Data &lt;/STRONG&gt;directory where the &lt;STRONG&gt;Master Key &lt;/STRONG&gt;is stored. DPAPI will&amp;nbsp;read the directory from AppData value and will use the Master Key to protect CryptoAPI private keys or EFS private keys, for instance.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Note that similar errors may occur for the same reasons:&lt;/P&gt;
&lt;P&gt;1. &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380261.aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380261.aspx"&gt;CryptProtectData&lt;/A&gt; API fails with ERROR_FILE_NOT_FOUND.&lt;/P&gt;
&lt;P&gt;2. Encrypting a file/folder with &lt;STRONG&gt;EFS&lt;/STRONG&gt; via Windows Explorer fails with &lt;STRONG&gt;"The system cannot find the file file specified"&lt;/STRONG&gt;.&lt;BR&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Note that &lt;STRONG&gt;Security Bulletin MS04-011&lt;/STRONG&gt; changed the registry key where the path could be found. Previous one was in here:&lt;/P&gt;&lt;PRE&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8531692" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>How to select which Smart Card reader to perform actions on</title><link>http://blogs.msdn.com/alejacma/archive/2008/03/03/how-to-select-which-smart-card-reader-to-perform-actions-on.aspx</link><pubDate>Mon, 03 Mar 2008 14:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8000547</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8000547.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8000547</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;Most of the time we only have a smart card reader in our machine, and we only use one smart card to perform crypto operations. But what if we have &lt;STRONG&gt;several readers and cards&lt;/STRONG&gt;, and those cards share the &lt;STRONG&gt;same CSP&lt;/STRONG&gt; (Cryptographic Service Provider)? Can we select the one we want to use when working with &lt;STRONG&gt;CryptoAPI/XEnroll/CertEnroll&lt;/STRONG&gt;?&lt;/P&gt;
&lt;P&gt;Let's take a look to &lt;STRONG&gt;XEnroll&lt;/STRONG&gt;, for instance: We can set &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en"&gt;WriteCertToCSP&lt;/A&gt; Property of the &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en"&gt;ICEnroll4 Interface&lt;/A&gt; to TRUE so the certificates will be written to the smart card in addition to being written to "MY" store when calling i.e. &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en"&gt;acceptPKCS7&lt;/A&gt; method (Note: WriteCertToCSP is TRUE by default). But apparently we can't specify which card we want to write the cert to. So what happens if we have two cards with same CSP inserted at the same time? Well, in this case the CSP itself will be responsible of giving the user the possibility to choose the card it wants. When we enroll the cert, the CSP should show a dialog so we can choose&amp;nbsp;the appropiate&amp;nbsp;card.&lt;/P&gt;
&lt;P&gt;As you sure know, XEnroll won’t work on &lt;STRONG&gt;Vista&lt;/STRONG&gt;. Vista now uses the new certificate enrollment component &lt;STRONG&gt;CertEnroll&lt;/STRONG&gt; (see &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en"&gt;Certificate Enrollment API&lt;/A&gt; for more info). But my comments still apply here: the CSP should help us to choose the card.&lt;/P&gt;
&lt;P&gt;And what if we want to do the selection programmatically? Can that be done? Yes, we may be able to do it. If we want to select the card for the CSP then we should figure out which &lt;STRONG&gt;reader&lt;/STRONG&gt; the card is in, and then use the "&lt;STRONG&gt;\\.\&amp;lt;Reader Name&amp;gt;\&lt;/STRONG&gt;" format for the &lt;STRONG&gt;container name&lt;/STRONG&gt; when calling &lt;STRONG&gt;CryptAcquireContext&lt;/STRONG&gt; API, for instance. If we also know the container name we can use "&lt;STRONG&gt;\\.\&amp;lt;Reader Name&amp;gt;\&amp;lt;Container Name&amp;gt;\&lt;/STRONG&gt;" (See the &lt;A class="" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ac201438-3317-44d3-9638-07625fe397b9&amp;amp;displaylang=en"&gt;smart card white paper&lt;/A&gt; for more details on our &lt;STRONG&gt;MS Base CSP&lt;/STRONG&gt;). The CSP should be able to work with the right card. &lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;BR&gt;Cheers,&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8000547" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Smart+Card/default.aspx">Smart Card</category></item><item><title>RSACryptoServiceProvider fails when used with ASP.NET</title><link>http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx</link><pubDate>Mon, 03 Dec 2007 12:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6596423</guid><dc:creator>alejacma</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/6596423.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=6596423</wfw:commentRss><description>&lt;P&gt;Hi, welcome back,&lt;/P&gt;
&lt;P&gt;I will talk today about a very common issue we face when we try to use .NET's &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt; class in &lt;STRONG&gt;ASP.NET&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;When we try to create a new RSACryptoServiceProvider object in this scenario, we may&amp;nbsp;get the following exception: &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;"System.Security.Cryptography.CryptographicException: The system cannot find the file specified".&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;By using my &lt;A class="" title="CryptoAPI Tracer script" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt;&amp;nbsp;we can take a look to the &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; calls that .NET is making behind the scenes. Thanks to this script we will be able to see the exact API that is failing and the exact error (which most of the time .NET masks).&lt;/P&gt;
&lt;P mce_keep="true"&gt;In our case, the API that fails is &lt;STRONG&gt;CryptAcquireContext&lt;/STRONG&gt;, and it fails with error &lt;STRONG&gt;#2&lt;/STRONG&gt;&amp;nbsp;(&lt;STRONG&gt;ERROR_FILE_NOT_FOUND&lt;/STRONG&gt;). According to &lt;A class="" title=CryptAcquireContext href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx"&gt;CryptAcquireContext&lt;/A&gt; documentation, this error means the following:&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;The profile of the user is not loaded and cannot be found. This happens when the application impersonates a user, for example, the IUSR_ComputerName account.&lt;/EM&gt;&lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;By default, ASP.NET won't load the user profile. Take a look to the parameters of the problematic&amp;nbsp;&lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx"&gt;CryptAcquireContext&lt;/A&gt; call as being shown in the log file that my script generated. If this API is not being called with CRYPT_MACHINE_KEYSET (to use the machine profile) or CRYPT_VERIFYCONTEXT (to use temporary key stores), it will try to access the key stores in the user profile, and it will fail because its not loaded.&lt;/P&gt;
&lt;P&gt;Which options do we have here then?&lt;/P&gt;
&lt;P&gt;1) If we need each user running your ASP.NET app to use their own key stores, we will have to load their user profile. We can do it with &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa374341.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa374341.aspx"&gt;LoadUserProfile&lt;/A&gt; API. The only problem is that the privileges needed to execute this API are quite powerful for a standard user.&lt;/P&gt;
&lt;P&gt;2) If we still need the user profile and don't want to give users enough privileges to run LoadUserProfile, there is a trick we can use: &lt;STRONG&gt;Service Control Manager &lt;/STRONG&gt;(&lt;STRONG&gt;SCM&lt;/STRONG&gt;) will automatically load the profile of the user that a Windows service uses to run. So we may create a dummy Windows service which runs with our user's credentials. This service won't need to do anything special, just stay alive. SCM will load the user profile for us and ASP.NET will be able to use it automatically once it gets loaded.&lt;/P&gt;
&lt;P&gt;3)&amp;nbsp;We may also use machine key stores instead of user's. We just have to pass &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt; flag to CryptAcquireContext. In order to do that in .NET, we may use a code like this:&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;CspParameters RSAParams = new CspParameters();&lt;BR&gt;RSAParams.Flags = CspProviderFlags.&lt;STRONG&gt;UseMachineKeyStore&lt;/STRONG&gt;;&lt;BR&gt;RSACryptoServiceProvider sp = new RSACryptoServiceProvider(1024, RSAParams);
&lt;/PRE&gt;
&lt;P&gt;Note. When we use machine key stores, any user in that machine may have access to those keys.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;U&gt;&lt;FONT color=#0066cc&gt;&lt;/FONT&gt;&lt;/U&gt;I hope this helps.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Alex&amp;nbsp;(Alejandro Campos Magencio)&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6596423" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugger+scripts/default.aspx">Debugger scripts</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>How to trace CryptoAPI calls (2)</title><link>http://blogs.msdn.com/alejacma/archive/2007/11/08/how-to-trace-cryptoapi-calls-2.aspx</link><pubDate>Fri, 09 Nov 2007 01:46:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5999992</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/5999992.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=5999992</wfw:commentRss><description>&lt;P&gt;Hi, welcome back,&lt;/P&gt;
&lt;P&gt;Let's try to understand a bit better what's going on my&amp;nbsp;&lt;A class="" title="CryptoAPI Tracer script" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Let's take a look to one of the most important breakpoints I set on a &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; function:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;bm Advapi32!CryptAcquireContextW ".printf \"\\n&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;\\n\\nCryptAcquireContextW (%#x)\\n\", @$tid;&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo IN;&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo pszContainer; .if(poi(@esp+8)=0) {.echo NULL} .else {du poi(@esp+8)};&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo pszProvider; .if(poi(@esp+c)=0) {.echo NULL} .else {du poi(@esp+c)};&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo dwProvType; .if(poi(@esp+10)=1) {.echo PROV_RSA_FULL} .elsif(poi(@esp+10)=0x18) {.echo PROV_RSA_AES} .else {.printf \"%d\\n\", poi(@esp+10)};&amp;nbsp;&amp;nbsp;&amp;nbsp; .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); .if((poi(@esp+14)&amp;amp;0x0`F0000000)=0x0`F0000000) {.echo CRYPT_VERIFYCONTEXT(0xf0000000)}; .if((poi(@esp+14)&amp;amp;0x0`00000008)=0x0`00000008){.echo CRYPT_NEWKEYSET(0x8)}; .if((poi(@esp+14)&amp;amp;0x0`00000010)=0x0`00000010) {.echo CRYPT_DELETEKEYSET(0x10)}; .if((poi(@esp+14)&amp;amp;0x0`00000020)=0x0`00000020) {.echo CRYPT_MACHINE_KEYSET(0x20)}; .if((poi(@esp+14)&amp;amp;0x0`00000040)=0x0`00000040) {.echo CRYPT_SILENT(0x40)};&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; bp /t @$thread poi(@esp) \"&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo OUT;&amp;nbsp;&amp;nbsp;&amp;nbsp; .if(poi(@esp-14)=0) {.echo phProv;.echo NULL} .else {.echo hProv; .if(poi(poi(@esp-14))=0) {.echo NULL} .else {.printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))} };&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo RESULT;&amp;nbsp;&amp;nbsp;&amp;nbsp; .if(@eax=1) {.printf \\\"CryptAcquireContextW (%#x) SUCCEEDED\\\\n\\\", @$tid} .else {.printf \\\"CryptAcquireContextW (%#x) FAILED\\\\n\\\", @$tid;!gle};&amp;nbsp;&amp;nbsp;&amp;nbsp; .echo;.echo &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;;&amp;nbsp;&amp;nbsp;&amp;nbsp; G;\";&amp;nbsp;&amp;nbsp;&amp;nbsp; G;";&lt;BR&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;It looks a bit complex, but it's not so much. Some of the basics where already explained &lt;A class="" title=here href="http://blogs.msdn.com/alejacma/archive/2007/10/29/how-to-trace-cryptoapi-calls.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/29/how-to-trace-cryptoapi-calls.aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Imagine we have the following API declaration in C:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;int __stdcall myFunction(int a, int b, int c);&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;If I set a &lt;STRONG&gt;breakpoint&lt;/STRONG&gt; on &lt;EM&gt;myFunction&lt;/EM&gt;, and because we use &lt;A class="" title=__stdcall href="http://msdn2.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx"&gt;__stdcall&lt;/A&gt; calling convention (the same as Win32 API/CryptoAPI functions), the &lt;STRONG&gt;stack&lt;/STRONG&gt; will look this way just when we reach the breakpoint, before we run any code on &lt;EM&gt;myFunction&lt;/EM&gt;:&lt;/P&gt;&lt;PRE&gt;return address &amp;lt;-- esp
a              &amp;lt;-- esp+4
b              &amp;lt;-- esp+8
c              &amp;lt;-- esp+c
xxxxxxxx
yyyyyyyy
zzzzzzzz
&lt;/PRE&gt;
&lt;P&gt;"&lt;STRONG&gt;esp&lt;/STRONG&gt;" (stack pointer) register will be pointing to the address where we'll return after finishing executing &lt;EM&gt;myFunction&lt;/EM&gt;. If we want to i.e. access the second parameter of the function, we can use the address esp+8.&lt;/P&gt;
&lt;P&gt;When we finish executing &lt;EM&gt;myFunction&lt;/EM&gt;&amp;nbsp;and we return from it&lt;EM&gt;,&lt;/EM&gt; "&lt;STRONG&gt;eax&lt;/STRONG&gt;" register will&amp;nbsp;contain the return value of the API and the stack will look like this:&lt;/P&gt;&lt;PRE&gt;xxxxxxxx       &amp;lt;-- esp
yyyyyyyy
zzzzzzzz
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;Now, if we want to access one of the parameters of the API we just called (i.e. because it's an out parameter), we have to remember that the information of the stack is not cleaned. So even if "esp" register points to "xxxxxxxx" now, the parameters of the API are still on the stack:&lt;/P&gt;&lt;PRE&gt;a              &amp;lt;-- esp-c
b              &amp;lt;-- esp-8
c              &amp;lt;-- esp-4
xxxxxxxx       &amp;lt;-- esp
yyyyyyyy
zzzzzzzz
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;So if we want to i.e.&amp;nbsp;access the first parameter of the API we can use esp-c address.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Having said this, let's write the breakpoint above in a different way:&lt;/P&gt;&lt;PRE&gt;000 bm Advapi32!CryptAcquireContextW 
001 "
002     .printf \"\\n&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;\\n\\nCryptAcquireContextW (%#x)\\n\", @$tid;
003
004     .echo;
005     .echo IN;
006
007     .echo pszContainer;
008     .if(poi(@esp+8)=0)
009     {
010         .echo NULL
011     }
012     .else
013     {
014         du poi(@esp+8)
015     };
016
017     .echo;
018     .echo pszProvider;
019     .if(poi(@esp+c)=0)
020     {
021         .echo NULL
022     }
023     .else 
024     {
025         du poi(@esp+c)
026     };
027
028     .echo;
029     .echo dwProvType;
030     .if(poi(@esp+10)=1) 
031     {
032         .echo PROV_RSA_FULL
033     }
034     .elsif(poi(@esp+10)=0x18) 
035     {
036         .echo PROV_RSA_AES
037     }
038     .else
039     {
040         .printf \"%d\\n\", poi(@esp+10)
041     };
042
043     .printf \"\\ndwFlags\\n%#x\\n\", poi(@esp+14); 
044     .if((poi(@esp+14)&amp;amp;0x0`F0000000)=0x0`F0000000) 
045     {
046         .echo CRYPT_VERIFYCONTEXT(0xf0000000)
047     }; 
048     .if((poi(@esp+14)&amp;amp;0x0`00000008)=0x0`00000008)
049     {
050         .echo CRYPT_NEWKEYSET(0x8)
051     };
052     .if((poi(@esp+14)&amp;amp;0x0`00000010)=0x0`00000010)
053     {
054         .echo CRYPT_DELETEKEYSET(0x10)
055     };
056     .if((poi(@esp+14)&amp;amp;0x0`00000020)=0x0`00000020)
057     {
058         .echo CRYPT_MACHINE_KEYSET(0x20)
059     };
060     .if((poi(@esp+14)&amp;amp;0x0`00000040)=0x0`00000040)
061     {
062         .echo CRYPT_SILENT(0x40)
063     };
064
065     bp /t @$thread poi(@esp)
066     \"
067         .echo;
068         .echo OUT;
069
070         .if(poi(@esp-14)=0)
071         {
072             .echo phProv;
073             .echo NULL
074         }
075         .else
076         {
077             .echo hProv;
078             .if(poi(poi(@esp-14))=0)
079             {
080                 .echo NULL
081             }
082             .else
083             {
084                 .printf \\\"%#x\\\\n\\\", poi(poi(@esp-14))
085             }
086         };
087
088         .echo;
089         .echo RESULT;
090
091         .if(@eax=1)
092         {
093             .printf \\\"CryptAcquireContextW (%#x) SUCCEEDED\\\\n\\\", @$tid
094         }
095         .else
096         {
097             .printf \\\"CryptAcquireContextW (%#x) FAILED\\\\n\\\", @$tid;!gle
098         };
099
100         .echo;
101         .echo &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;;
102
103         G;
104     \";
105
106     G;
107 ";
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;000) We set a breakpoint on the UNICODE version of &lt;A class="" title=CryptAcquireContext href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx"&gt;CryptAcquireContext&lt;/A&gt; API. This is the declaration of the API:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;EM&gt;BOOL WINAPI CryptAcquireContext(__out HCRYPTPROV* phProv,&amp;nbsp;__in LPCTSTR pszContainer, __in LPCTSTR pszProvider, __in DWORD dwProvType, __in DWORD dwFlags);&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;The following commands will be executed when the application calls this API and we reach the breakpoint:&lt;/P&gt;
&lt;P mce_keep="true"&gt;002) We print the name of the API and the id of the thread which calls it.&lt;/P&gt;
&lt;P mce_keep="true"&gt;005) We print the string "IN", and after that we'll print the values of the __in parameters of the API.&lt;/P&gt;
&lt;P mce_keep="true"&gt;007-015) We print &lt;EM&gt;pszContainer&lt;/EM&gt; parameter as a string of Unicode chars,&amp;nbsp;after checking if it's NULL or not.&lt;/P&gt;
&lt;P mce_keep="true"&gt;018-026) We print &lt;EM&gt;pszProvider&lt;/EM&gt; parameter as a string of Unicode chars, after checking if it's NULL or not.&lt;/P&gt;
&lt;P mce_keep="true"&gt;029-041) We print &lt;EM&gt;dwProvType&lt;/EM&gt; parameter. If we know the type we print it in clear text, otherwise we just print its numeric value.&lt;/P&gt;
&lt;P mce_keep="true"&gt;043-063) We print &lt;EM&gt;dwFlags&lt;/EM&gt; parameter in Hexadecimal. If we know the values of those flags, we print them in clear text.&lt;/P&gt;
&lt;P mce_keep="true"&gt;065) Now we want to know what happened after the API finished executing. We set a breakpoint at the return address where we will return after calling the API. If we don't want weird things to happen on multi-threaded applications, we have to specify on which thread ("$thread" pseudo-register) we are setting that breakpoint. &lt;/P&gt;
&lt;P mce_keep="true"&gt;106) Once we've set the breakpoint at 065, we can continue the execution of the application.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Now, let see what happens when we stop on breakpoint set at 065:&lt;/P&gt;
&lt;P mce_keep="true"&gt;068) We print the string "OUT", and after that we'll print the values of the __out parameters of the API.&lt;/P&gt;
&lt;P mce_keep="true"&gt;070-086) We print&amp;nbsp;&lt;EM&gt;phProv&lt;/EM&gt; parameter. This is a pointer to &lt;EM&gt;hProv&lt;/EM&gt;. If the pointer is not NULL, we print the Hexadecimal value of &lt;EM&gt;hProv&lt;/EM&gt;, after checking if&amp;nbsp;this value is&amp;nbsp;NULL or not.&lt;/P&gt;
&lt;P mce_keep="true"&gt;089) We print the string "RESULT", and after that we'll print the return value of the API, and the error if there was one.&lt;/P&gt;
&lt;P mce_keep="true"&gt;091-098) We show if the API succeeded or not. If not, we also show the error value that the API returned.&lt;/P&gt;
&lt;P mce_keep="true"&gt;103) Now that we know the result of calling the API, we can continue the execution of the application and trace more APIs.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5999992" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/WinDbg/default.aspx">WinDbg</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Cdb/default.aspx">Cdb</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugger+scripts/default.aspx">Debugger scripts</category></item><item><title>RSACryptoServiceProvider fails when used with mandatory profiles</title><link>http://blogs.msdn.com/alejacma/archive/2007/10/23/rsacryptoserviceprovider-fails-when-used-with-mandatory-profiles.aspx</link><pubDate>Tue, 23 Oct 2007 13:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5622514</guid><dc:creator>alejacma</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/5622514.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=5622514</wfw:commentRss><description>&lt;P&gt;Hi, welcome back,&lt;/P&gt;
&lt;P&gt;I will talk today about a very common issue we face when we try to use .NET's &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt; (&lt;A href="http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx"&gt;http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx&lt;/A&gt;)&amp;nbsp;class with &lt;STRONG&gt;mandatory profiles&lt;/STRONG&gt; (i.e. Citrix environment). &lt;/P&gt;
&lt;P&gt;When we try to create a new RSACryptoServiceProvider object in this scenario, we get the following exception: &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;"&lt;/EM&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;EM&gt;System.Security.Cryptography.CryptographicException: Cryptographic Service Provider (CSP) for this implementation could not be acquired&lt;/EM&gt;&lt;/STRONG&gt;&lt;STRONG&gt;&lt;EM&gt;".&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This behavior is by design for security protection.&lt;/P&gt;
&lt;P&gt;RSACryptoServiceProvider calls &lt;STRONG&gt;CryptAcquireContext&lt;/STRONG&gt; API (&lt;A href="http://msdn2.microsoft.com/en-us/library/aa379886.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa379886.aspx&lt;/A&gt;) behind the scenes to get a handle to a key container within a CSP (Cryptographic Service Provider). CryptAcquireContext will fail with &lt;STRONG&gt;NTE_TEMPORARY_PROFILE&lt;/STRONG&gt; error when called from a mandatory profile. &lt;/P&gt;
&lt;P&gt;Mandatory profiles are read-only user profiles. Since changes to the mandatory profile cannot be saved, PKI design doesn't allow this operation, and CryptAcquireContext prevents this scenario by failing.&lt;/P&gt;
&lt;P&gt;Private keys are protected by &lt;STRONG&gt;DPAPI&lt;/STRONG&gt; (Data Protection API) component of Windows. DPAPI component regularly creates new Master Keys in the profile to protect confidential information such as private keys. For security reasons, Master Keys will expire, which means that after a period of time, the hard-coded value being three months, a new Master Key is generated and protected in the same manner. This expiration prevents an attacker from compromising a single Master Key and accessing all of a user's protected data.&lt;/P&gt;
&lt;P&gt;The Master Key regeneration is explained in the DPAPI white-paper at:&lt;/P&gt;
&lt;P&gt;Windows Data Protection&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/ms995355.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms995355.aspx&lt;/A&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/windataprotection-dpapi.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/windataprotection-dpapi.asp"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;So, higher level components that depend on DPAPI to protect confidential information cannot be protected securely with read-only profiles.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;More information about all this can be found here:&lt;/P&gt;
&lt;P&gt;Cryptographic Keys and Certificates Cannot Be Used with Mandatory Profiles&lt;BR&gt;&lt;A href="http://support.microsoft.com/default.aspx?scid=kb;en-us;264732" mce_href="http://support.microsoft.com/default.aspx?scid=kb;en-us;264732"&gt;http://support.microsoft.com/default.aspx?scid=kb;en-us;264732&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;How to troubleshoot the Data Protection API (DPAPI)&lt;BR&gt;"DPAPI and Mandatory Profiles"&lt;BR&gt;&lt;A href="http://support.microsoft.com/default.aspx?scid=kb;en-us;309408" mce_href="http://support.microsoft.com/default.aspx?scid=kb;en-us;309408"&gt;http://support.microsoft.com/default.aspx?scid=kb;en-us;309408&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Cannot Gain Access to Microsoft Encrypted File Systems&lt;BR&gt;&lt;A href="http://support.microsoft.com/kb/243850/en-us"&gt;http://support.microsoft.com/kb/243850/en-us&lt;/A&gt;&lt;A href="http://support.microsoft.com/support/kb/articles/Q243/8/50.asp" mce_href="http://support.microsoft.com/support/kb/articles/Q243/8/50.asp"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;There are three possible solutions to this issue:&lt;/P&gt;
&lt;P&gt;1)&amp;nbsp;If you need to access some user’s private keys (i.e. when signing data) and you want to prevent other users from using its keys, the only way is configuring the profile as non-mandatory.&lt;/P&gt;
&lt;P&gt;2)&amp;nbsp;If you need a persistent RSA private key, then the only solution is to use CryptAcquireContext with the &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt; flag (or RSACryptoServiceProvider with the &lt;STRONG&gt;CspProviderFlags.UseMachineKeyStore&lt;/STRONG&gt; flag) for private key storage in this configuration. But this is not protected based on the user's password hash, so any user with access to the machine may have access to those keys.&lt;/P&gt;
&lt;P&gt;3)&amp;nbsp;If you don’t need persistent RSA private keys (i.e. when verifying signatures), you could use CryptAcquireContext with the &lt;STRONG&gt;CRYPT_VERIFYCONTEXT&lt;/STRONG&gt; flag. This flag tells CryptoAPI to create the key container in memory and not in the user’s profile. And you won't need to worry about deleting the key container; you just release the handle with &lt;STRONG&gt;CryptReleaseContext&lt;/STRONG&gt; (&lt;A href="http://msdn2.microsoft.com/en-us/library/aa380268.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa380268.aspx&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;Additional info about CryptAcquireContext &amp;amp; CRYPT_VERIFYCONTEXT can be found here:&lt;/P&gt;
&lt;P&gt;238187 CryptAcquireContext() use and troubleshooting&lt;BR&gt;&lt;A href="http://support.microsoft.com/?id=238187" mce_href="http://support.microsoft.com/?id=238187"&gt;http://support.microsoft.com/?id=238187&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The problem is that, at the moment of this writing,&amp;nbsp;creating a &lt;STRONG&gt;temporary key container&lt;/STRONG&gt; with RSACryptoServiceProvider is not possible. We may think of using CryptAcquireContext&amp;nbsp;with CRYPT_VERIFYCONTEXT flag to get a handle to the key container within the CSP before using RSACryptoServiceProvider, but RSACryptoServiceProvider maintains its own cryptographic handle and it's not possible to give RSACryptoServiceProvider a handle to use. We have already requested .NET Framework developers to expose CRYPT_VERIFYCONTEXT for us, but I can't tell when we will get such a feature.&lt;/P&gt;
&lt;P&gt;The way to i.e. verify signatures using temporary keysets in .NET would be to use CryptoAPI directly through P/Invoke (Platform Invoke), instead of using RSACryptoServiceProvider.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;PS: In a near future I will post how we can easily see which CryptoAPI calls .NET is making behind the scenes. When a CryptoAPI call fails, .NET captures the error and it returns its own exception, which is not always self-explanatory as we've seen today. We will be able to see the failing CryptoAPI, and which error is actually returning. This way, if we see a "Cryptographic Service Provider (CSP) for this implementation could not be acquired" error, we will be able to see for instance&amp;nbsp;that CryptAcquireContext is failing with NTE_TEMPORARY_PROFILE and that will give us some clues about what's going on there.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5622514" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category></item></channel></rss>