Import RSA public key from XML using RSACryptoServiceProvider sets PublicOnly property to false

I am creating a tool for managing RSA key pairs on Windows, because there are no built-in functions for this, and we widely use RSA encryption functions 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 functions that work separately from importing only public keys for encryption operations. When key pairs are initially created on the servers, both public and public / private export is done in xml using aspnet_regiis.exe .

I try to provide the ability to encrypt configuration files on other machines to prevent the distribution of private keys, if absolutely necessary.

Each time I import a public key from an exported previoulsy XML block, the PublicOnly property for RSACryptoServiceProvider set to false, indicating that the key pair has a public and private key. I have confirmed that xml does not contain secret key information, so the problem is not in the xml file.

The problem occurs when using the CspParameters object and defining the flags as CspProviderFlags.UseMachineKeyStore . If you build RSACryptoServiceProvider without specifying any Csp parameters and then import the key from xml, the PublicOnly property will be 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 tell it the container key so that it can be used later for encryption operations, I have to use the CspParameters object when building the RSACryptoServiceProvider , since there is no other way to name the container key.

 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 tried various versions of this code, however the problem remains. I note that there are similar questions, such as the RSA Encryption public key not returned from the container? However, I believe that this problem is different, and a satisfactory answer was not provided.

The question is, how can I import the RSA public key from XML and give the key container a name, while in the container there is only a pair of public keys?

EDIT

Further research in this area also shows a problem when importing a full key from xml, as well as setting flags to export the key.

 CspProviderFlags.UseArchivableKey; 

When this flag is specified in the CSP parameter object, an exception of type "Invalid flags" is csp.FromXmlString(xmlText) in the line csp.FromXmlString(xmlText) ;

I really can't explain it. The key was created and previously exported to XML, of course, if the key was previously exported, could it be imported and allowed to be exported again?

I have done a lot of research on this, but I just don’t see an answer to any of these problems.

I tried changing the csp provider type from PROV_RSA_FULL to PROV_RSA_AES, since I believe that this is now the default value, and I believed that the keys were originally created using this instead of PROV_RSA_FULL, but that didn’t make any difference.

+5
source share
1 answer

When importing key parameters (either from XML or from RSAParameters), RSACryptoServiceProvider will disconnect from the current key if public parameters are provided; it replaces only the contents of the key in the key container if private parameters are imported.

http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs,b027f6909aa0a6d1

ImportCspBlob takes a different path, but ultimately draws the same conclusion: if a public blob is imported, it is separated from the ephemeral key. http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/utils.cs,754f1f4055bba611

The underlying Windows Cryptography APIs do not seem to allow public keys to be stored (unless they are stored with their private keys).

CNG documentation at https://msdn.microsoft.com/en-us/library/windows/desktop/bb427412(v=vs.85).aspx says

For BCryptExportKey, to create a pair of stored keys, the BLOB input key must contain the private key. Public keys are not saved.

They are supposed to mean BCryptImportKey, but “Public Keys Are Not Saved” feel authoritative.

For CAPI, I cannot find anything as simple.

The best I can find is the CAPI definition of "key container" ( https://msdn.microsoft.com/en-us/library/windows/desktop/ms721590(v=vs.85).aspx#_security_key_container_gly ):

container

The part of the key database that contains all key pairs (exchange and signature key pairs) that belong to a specific user. Each container has a unique name, which is used when calling the CryptAcquireContext function to get a handle to the container.

This definition refers only to “key pairs,” suggesting that “public keys” may be rejected by the storage tier. Given the behavior of RSACryptoServiceProvider, this seems pretty likely.

0
source

Source: https://habr.com/ru/post/1210257/


All Articles