Return to HomePage



Generate RSA Keys and Store in the Registry Using DPAPI (C#)


Applies to

* .NET Framework 2.0
* C#

Summary

The purpose of this code snippet is to illustrate how to generate and securely store a public key pair in .NET using RSA and the DPAPI.


Objectives

* Create a encryption key that can be publicly distributed without fearing that encrypted messages could become compromised
* Securely store the private key material without needing to implement additional encryption operations or relying on file system on database security


Scenarios

* Distributed client-server architecture where clients need to send confidential encrypted messages to the server but don't need to ever read those messages
* Application does not want to maintain a dedicated key store for encryption purposes

Solution Example

// Define some useful globals
public int RSAKEYSIZE = 2048;
public RSACryptoServiceProvider myRSA;

public void GenerateAndStoreRSAKeys()
{
		    	///// Generate RSA Key Public and Private Pairs /////
	

		    	// The RSA CSP class automatically generates public and private key material
		    	// during constructions using the provided key size (or 1024bits if blank)
		    	myRSA = new RSACryptoServiceProvider(RSA_KEY_SIZE);
	

		    	///// Store in the registry using DPAPI and a Registry ACL /////
	

		    	// Serialize the RSA key pair as an XML string for registry storage
		    	string [keyPairXml] = [myRSA.ToXmlString(true);]
	

		    	// Convert the RSA key pair to a byte array and encrypt the data by using 
		    	// the DPAPI [ProtectedData] class. We're using the [CurrentUser] scope instead 
		    	// of the [MachineKey] scope so that other, potentially malicious applications 
		    	// cannot access this key in the registry and decrypt. This provides additional
		    	// security but sacrifices interoperability with other applications. Consider
		    	// using the [MachineKey] scope if you have a need to share keys between 
		    	// applications.
		    	byte[] [encryptedKeyPair] = [ProtectedData.Protect(]
		                    [UnicodeEncoding.ASCII.GetBytes(keyPairXml),] 
		                    null, 
		                    [DataProtectionScope.CurrentUser);]
	

		    	// Create a security context for a new key that we will use to store 
		    	// our RSA key pair. The security context will restrict access to only 
		    	// our user.
		    	string user = [Environment.UserDomainName] + "\\" + [Environment.UserName;]
		    	[RegistrySecurity] security = new [RegistrySecurity();]
		    	[RegistryAccessRule] rule = new [RegistryAccessRule(user,]
		                    [RegistryRights.FullControl,]
		                    [InheritanceFlags.ContainerInherit,]
		                    [PropagationFlags.None,]
		                    [AccessControlType.Allow);]
		    	[security.AddAccessRule(rule);]
	

		    	// Actually create the new registry key and apply the security context 
		    	// we just came up with.
		    	Registry.CurrentUser.CreateSubKey("RSAKeyPair", 
		        	[RegistryKeyPermissionCheck.ReadWriteSubTree,] 
		        	security);
	

		    	// Write the encrypted connection string into the registry
		    	Registry.SetValue(@"HKEY_CURRENT_USER\RSAKeyPair", 
		        	"KeyData",
		        	[encryptedKeyPair);]
	
}


Problem Example

The following example demonstrates the generation of an RSA key pair and storage of those keys on the file system.

// The RSA CSP class automatically generates public and private key material
// during construction
myRSA = new RSACryptoServiceProvider();

///// Store in the registry using DPAPI and a Registry ACL /////
// Convert the RSA public key to an xml string (passing "true" retrieves
// both the private and public key data
string keyPairXml = myRSA.ToXmlString(true);

// Open up the key pair file and read into a string
StreamWriter keyWriter = new StreamWriter(@"C:\temp\rsakeypair.xml");
keyWriter.Write(keyPairXml);
keyWriter.Close();

* If the file system is compromised the private key may be exposed and the encrypted messages can be compromised.
* Default key size provides degraded strength and diminishes security


Test Case

The following classes must be included in any project making use of the
sample code provided above:

using System.IO;
using System.Security;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;

Execute the following code and then open "regedit" and look in the registry under the key "HKEYCURRENTUSER\RSAKeyPair" to see the RSA key pair data encrypted in the registry.

static void Main(string[] args)
{
		    		// Generate an RSA key pair and store using the DPAPI
		    		[GenerateAndStoreRSAKeys();]
	
}


Expected Result

The RSA key is encrypted using DPAPI and stored in the registry key.



More Information

RSA is an algorithm for public key (also knows as asymmetric) cryptography in which distinct public and private keys are created. Encryption operations makes use of the public key while decryption requires the private key. This offers an advantage over symmetric cryptography because the secret key used to decrypt a message does not need to be shared in order to support encryption of messages to a recipient.

The RSA private key must be securely stored in order to maintain the confidentiality of data encrypted using an individual's public RSA key. However, the public key can be freely distributed by the owner of the key pair to anyone who wishes to send an encrypted message to that owner.


Additional Resources

* RSACryptoServiceProvider (.NET): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecuritycryptographyrsacryptoserviceproviderclassctortopic.asp
* Cryptography (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_cryptography


Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Cryptography
* Author: Jonathan Bailey



Return to HomePage
Microsoft Communities