Showing the private key stored in a pfx file

G

Guest

Hi,

I already asked the following question in microsoft.public.dotnet.security
but I found out that that group isn't an MSDN Managed Newsgroup.

I show the public and private key stored in a pfx file. The public key
is the same every time I run the program, but the private key isn't.
Can someone explain to me why the private key isn't the same every time
I run the program?

I show the keyexponent and keymodulus of the public key, and the D
parameter of the private key, with the following C# code:

---------------
PfxOpen pfx = new PfxOpen();
String pfxFilename = @"E:\Prototype\Test\Release2\key.pfx";
String password = "geheim";
if(!pfx.LoadPfx(pfxFilename, ref password))
{
throw new Exception("Failed to load pfx");
}

CspParameters cspParameters = new CspParameters();
cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
cspParameters.KeyContainerName = pfx.container;
RSACryptoServiceProvider rsaCryptoServiceProvider =
new RSACryptoServiceProvider(cspParameters);
RSAParameters rsaParameters =
rsaCryptoServiceProvider.ExportParameters(true);

MessageBox.Show("container: " + pfx.container
+ "\n\n" + "keyexponent: " + ByteArrayToString(pfx.keyexponent)
+ "\n\n" + "keymodulus: " + ByteArrayToString(pfx.keymodulus)
+ "\n\n" + "D: " + ByteArrayToString(rsaParameters.D)
);
---------------

I'm using PfxOpen.cs and win32.cs from
http://msdn.microsoft.com/library/en-us/dncapi/html/pkcs12.asp and I'm
using .NET framework version 1.1.

Cheers,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Thanks for your post!

Based on my knowledge, the container name will be different every time you
import the PFX, but the private key should be the same each time.

I recommend you to use certutil.exe to dump the raw private key:
certutil -p "geheim" -v -privatekey e:\Prototype\Test\Release2\key.pfx
The output won't be as nice as the RSA C# class allows, in that the key is
merely dumped as a hex blob.

If the above command shows the same private key content each time, then
there may be an issue with the C# classes you are using, or the code that
calls them.

I look forward to your further test result. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Bob,

After performing some further review on your code snippet, I think I found
the problem:

When you call
RSACryptoServiceProvider rsaCryptoServiceProvider = new
RSACryptoServiceProvider(cspParameters);

It generates a new RSA key pair. While your code displays the public key in
the pfx, and displays the private piece of the key you have just generated,
so the new generated private key will certainly be different from the
public key in the pfx.

You should consider displaying the private key in the PFX, not of the key
in the container you just generated. If you have problem of achieve this
task, please feel free to tell me, thanks!

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey,

Thanks a lot for your help.
Based on my knowledge, the container name will be different every time you
import the PFX, but the private key should be the same each time.

That is what I expected, but both are different every time.
I recommend you to use certutil.exe to dump the raw private key:

It isn't on my machine and I sent a request to our service desk.
When you call
RSACryptoServiceProvider rsaCryptoServiceProvider = new
RSACryptoServiceProvider(cspParameters);

It generates a new RSA key pair.

According to help item "Generating Keys for Encryption and Decryption" a key
pair is generated when you use the DEFAULT constructor of
RSACryptoServiceProvider.
While your code displays the public key in
the pfx, and displays the private piece of the key you have just generated,

Let's assume that a new key pair is generated. In that case I still wonder
why the public key of the pfx file is used and the new private key is used
instead of the private key from the pfx file.
You should consider displaying the private key in the PFX, not of the key
in the container you just generated. If you have problem of achieve this
task, please feel free to tell me, thanks!

Yes, please tell me how to do that.

In fact the code I showed is only to help me find a solution to the real
problem I have. The real problem is that when I try to decrypt encrypted
data, an exception is raised. In Dutch the exception is "Ongeldige gegevens",
which translates to "Bad data".

The code I use looks like:

byte[] encryptedData = ...
CspParameters cspParameters = new CspParameters();
cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
cspParameters.KeyContainerName = pfx.container;
RSACryptoServiceProvider rsaCryptoServiceProvider =
new RSACryptoServiceProvider(cspParameters);
byte[] decryptedData = rsaCryptoServiceProvider(encryptedData, false);

The exception is raised in rsaCryptoServiceProvider(encryptedData, false).

Because I'm pretty sure the right data is used, I tried to find out whether
the right private key is used to decrypt the data.

Cheers,

Bob
 
G

Guest

I said:
byte[] decryptedData = rsaCryptoServiceProvider(encryptedData, false);

The exception is raised in rsaCryptoServiceProvider(encryptedData, false).

Please read:

byte[] decryptedData = rsaCryptoServiceProvider.Decrypt(encryptedData, false);

The exception is raised in rsaCryptoServiceProvider.Decrypt(encryptedData,
false).

Cheers,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Thanks for your feedback!

If you use Reflector to view RSACryptoServiceProvider class constructors,
you will find that both public RSACryptoServiceProvider(CspParameters
parameters) and default constructor pass the actual work to the following
constructor, which generates a new key paire internally:
internal RSACryptoServiceProvider(int dwKeySize, CspParameters parameters,
bool useDefaultKeySize)

To display the private key of PFX file, .Net2.0 has the build-in support.
You may use X509Certificate2.PrivateKey to get it:

AsymmetricAlgorithm privateKey = new X509Certificate2(pfxFile,
password).PrivateKey;

Note: pfxFile can be either the path of the file, or a byte array
containing its contents.

Hope this helps!

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey,

Thanks again for your help.
both public RSACryptoServiceProvider(CspParameters
parameters) and default constructor pass the actual work to the following
constructor, which generates a new key paire internally:
internal RSACryptoServiceProvider(int dwKeySize, CspParameters parameters,
bool useDefaultKeySize)

I suppose cspParameters.KeyContainerName will be used by that constructor.
Right?
If yes, I still wonder why the public key of the pfx file is used and the
new private key is used instead of the private key from the pfx file.

I want rsaCryptoServiceProvider to use the private key from the pfx file.
What do I have to do?
To display the private key of PFX file, .Net2.0 has the build-in support.

Unfortunately we use .NET 1.1

Cheers,

Bob
 
G

Guest

I said:
If yes, I still wonder why the public key of the pfx file is used and the
new private key is used instead of the private key from the pfx file.

Forget this one, because pfx.keymodulus is different from
rsaParameters.Modulus every time.

So the only question which remains is:

I want rsaCryptoServiceProvider to use the private key from the pfx file.
What do I have to do? Note that we use .NET 1.1.

Cheers,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Thanks for your feedback!

I am out of office last friday, so sorry for the late response.

Oh, I see, since the .Net2.0 CLR implements the X509Certificate2
internally, I will perform some research regarding how to achieve the same
task in .Net1.1. I will get back to you ASAP. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Scott,

Sorry for letting you wait.

There is no build-in support in .Net1.1, you have to p/invoke CryptoAPI to
get this done, below is the steps:

You'll need to P/Invoke to PFXImportCertStore to open the PFX file which
will give you a certificate store that can be enumerated with
CertEnumCertificatesInStore. You can use CertGetCertificateContextProperty
to get information on the key container the private key is stored in, and
then create an RSACryptoServiceProvider for that.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey,

Thanks again for your help.
You'll need to P/Invoke to PFXImportCertStore to open the PFX file which
will give you a certificate store that can be enumerated with
CertEnumCertificatesInStore. You can use CertGetCertificateContextProperty
to get information on the key container the private key is stored in,

I'm using PfxOpen.cs and win32.cs from
http://msdn.microsoft.com/library/en-us/dncapi/html/pkcs12.asp
That code uses PFXImportCertStore, CertEnumCertificatesInStore and
CertGetCertificateContextProperty. The PfxOpen class has a 'container'
property which I use.
and then create an RSACryptoServiceProvider for that.

I use:
CspParameters cspParameters = new CspParameters();
cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
cspParameters.KeyContainerName = pfx.container;
RSACryptoServiceProvider rsaCryptoServiceProvider =
new RSACryptoServiceProvider(cspParameters);

When I have a look at the public and private key with:

RSAParameters rsaParameters =
rsaCryptoServiceProvider.ExportParameters(true);
MessageBox.Show("container: " + pfx.container
+ "\n\n" + "Modulus: " + ByteArrayToString(rsaParameters.Modulus)
+ "\n\n" + "D: " + ByteArrayToString(rsaParameters.D)
);

every time I run this code it shows a different Modulus and D, not the ones
from the pfx file.
I have to use the private key (D parameter) from the pfx file to be able to
decrypt some data.
An idea what's wrong?

Cheers,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Sorry for the late response. I am sick at home yesterday.

Ok, I will spend some time on reviewing your logic, and I may discuss this
issue with some other experts. I will get back to you ASAP.

Thanks for your patient.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Sorry for letting you wait.

Based on the discuss with other security experts, we want to know:

Are you importing the certificate into the local machine store?
The following line assumes that you have imported the certificate in the
local machine store. More specifically, that you imported the private key
into a machine container.

cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;

If you imported the certificate in the current user's store, then your code
is creating the machine key container and generating a new private key each
time. The container then gets deleted at garbage collection.

Please give this a check and let me know the result. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey,
Sorry for letting you wait.

No problem, I'm happy you can help me.
Are you importing the certificate into the local machine store?

I'm not sure. I'm using PfxOpen.cs and win32.cs from
http://msdn.microsoft.com/library/en-us/dncapi/html/pkcs12.asp
At that page it says:
"we attempt to import the PFX certificates into a transient CryptoAPI memory
store, with the associated private keys placed in a newly created key
container using Win32.PFXImportCertStore()"
The following line assumes that you have imported the certificate in the
local machine store. More specifically, that you imported the private key
into a machine container.

cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;

If I don't use that line I get the following error message on my W2k machine
when I try to instantiate the RSACryptoServiceProvider:
"CryptoAPI cryptographic service provider (CSP) for this implementation
could not be acquired"
If you imported the certificate in the current user's store, then your code
is creating the machine key container and generating a new private key each
time. The container then gets deleted at garbage collection.

Sounds like this could be the problem. How can I change PfxOpen from
http://msdn.microsoft.com/library/en-us/dncapi/html/pkcs12.asp to make it
use a machine keystore. Or is there another way to fix this?

Cheers,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Based on my review to the technical article, PfxOpen.cs calls:

Win32.PFXImportCertStore(ref ppfx, pswd, CRYPT_USER_KEYSET)

this imports the RSA key into current user key container of the calling
user account.

Whereas the .NET code later uses machine key container flag as below:

CspProviderFlags.UseMachineKeyStore

So, your .NET code is basically not using the key imported by PfxOpen.cs
and hence you are getting the symptom where the keys are different
everytime.

If the intention of the application is to import keys from PFX into machine
location, you would need to call PfxImportCertStore with
CRYPT_MACHINE_KEYSET flag.

Please note that if a named machine key container was initially created by
a User Account A, that named machine key container is accessible only to
that User Account A and "Local System" account. In addition to the
protection of the key container data through DPAPI, the key container file
is protected by a DACL.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey,
If the intention of the application is to import keys from PFX into machine
location,

I don't care where to store the key. But if I don't use the line
"cspParameters.Flags = CspProviderFlags.UseMachineKeyStore;" I get the
following error message on my W2k machine when I try to instantiate the
RSACryptoServiceProvider:
"CryptoAPI cryptographic service provider (CSP) for this implementation
could not be acquired"
you would need to call PfxImportCertStore with
CRYPT_MACHINE_KEYSET flag.

That did the trick. Thanks a lot.
I have to use "CRYPT_MACHINE_KEYSET | CRYPT_EXPORTABLE" to be able to
execute rsaCryptoServiceProvider.ExportParameters(true).
Hope this helps.

Sure it did.
I'm on holiday at this moment and I went back to work today to check whether
the decryption software runs when I use CRYPT_MACHINE_KEYSET.
Unfortunately an exception was raised. It was (something like) "CryptoAPI
cryptographic service provider (CSP) for this implementation
could not be acquired" again. At the end of the month I will have a look at
that, and I hope I can get your help again if necessary.

Thanks again for your help,

Bob
 
J

Jeffrey Tan[MSFT]

Hi Bob,

Based on my experience, this error message is generated from native
CryptAcquireContext API, which is wrapped in RSACryptoServiceProvider
constructor. This API will acquire a corresponding CSP and key container
regarding key pairs.

Normally, this exception is generated when the RSACryptoServiceProvider is
trying to acquire the key container associated certain user profile, which
is unavailable the code context. If you are using machine store(set
RSACryptoServiceProvider.UseMachineKeyStore = true), you should can
workaround this user profile issue, please refer to the KB below:
""CSP for this implementation could not be acquired" CryptographicException
error during instantiation"
http://support.microsoft.com/default.aspx?scid=KB;EN-US;322371

Anyway, once you have time to check this issue at the end of the month,
please feel free to post, I will work with you. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Ok, I will work with you at that time. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top