I am creating an tool to manage RSA Key Pairs on Windows since there is no built-in functionality for this and we make extensive use of the RSA encryption features in .NET.
The tool provides various functions such as listing existing RSA key pairs, creating new keys, deleting keys, exporting keys and importing keys from a previously created XML export (exported using ASPNet_RegIIS.exe).
I have all the functionality working apart from importing only the public keys for encryption operations only. When the key pairs are originally created on the servers, both public and public/private exports are made to xml using aspnet_regiis.exe
.
I am keen to provide the option to encrypt config files on other machines to prevent the private keys from being distributed unless absolutely necessary.
Each time I import the public key from a previoulsy exported XML block the PublicOnly
property of the RSACryptoServiceProvider
is set to false indicating that the key pair has a public and private key. I have confirmed the xml does not contain the private key information therefore the problem is not within the xml file.
The problem seems to occur when using the CspParameters
object and specifying the Flags as CspProviderFlags.UseMachineKeyStore
. If you construct the RSACryptoServiceProvider
without specifying any Csp parameters and then import the key from xml, the PublicOnly
property is correctly set to false.
String xmlText = File.ReadAllText(filePath);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(xmlText);
//csp.PublicOnly equals true;
However since I need to give it the key container a name so it can be used later for encryption operations I am forced to use the CspParameters
object when constructing a RSACryptoServiceProvider
as there is no other way to name the key container.
String xmlText = File.ReadAllText(filePath);
CspParameters cspParams = new CspParameters();
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.KeyContainerName = keyContainerName;
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(cspParams);
csp.PersistKeyInCsp = true;
csp.FromXmlString(xmlText);
//csp.PublicOnly equals false;
I have tried a variety of versions of this code however the problem remains. I note there are similar questions such as RSA Encryption public key not returned from container? however I believe this issue is different and no satisfactory answer has ever been given.
The question is therefore how can I import an RSA public key from XML and give the key container a name whilst ensuring only a public key pair exists in the container?
EDIT
Further research around this area also shows a problem when importing the full key from xml and also setting the flags to allow exporting of the key.
CspProviderFlags.UseArchivableKey;
When this flag is specified on the CSP Parameter object an exception of type "Invalid flags specified" is thrown at the line csp.FromXmlString(xmlText)
;
I really cannot explain this. The key was created and previously exported to XML, surely if the key has been previously exported it should be possible to import it AND allow it to be exported again?
I have done a lot of research on this but just cannot see the answer to either of these problems.
I have tried changing the csp provider type from PROV_RSA_FULL to PROV_RSA_AES as I believe this is now the default and I considered the keys may have originally been created using this instead of PROV_RSA_FULL but this has made no difference.