security
.NET RSA Encryption Class
The following class is the class I created to RSA encrypt database passwords. The implementation is a case study of need for this at a former client.
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Xml;
namespace Utility
{
public class RSAEncryption
{
private XmlDocument publicKey = null;
private XmlDocument privateKey = null;
private System.Security.Cryptography.RSACryptoServiceProvider rsa;
public RSAEncryption(XmlDocument publicKey) : this(publicKey, null)
{
;
}
public RSAEncryption(XmlDocument publicKey, XmlDocument privateKey)
{
this.publicKey = publicKey;
this.privateKey = privateKey;
RSACryptoServiceProvider.UseMachineKeyStore = true;
this.rsa = new RSACryptoServiceProvider();
}
public string EncryptData(string data2Encrypt)
{
byte[] cipherbytes = null;
try
{
rsa.FromXmlString(this.publicKey.OuterXml);
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
cipherbytes = rsa.Encrypt(plainbytes, false);
}
catch (Exception ex)
{
Logger.LogException(ex, this);
throw ex;
}
return Convert.ToBase64String(cipherbytes);
}
public string DecryptData(string data2Decrypt)
{
byte[] plain = null;
try
{
byte[] getpassword = Convert.FromBase64String(data2Decrypt);
rsa.FromXmlString(this.privateKey.OuterXml);
plain = rsa.Decrypt(getpassword, false);
}
catch (Exception ex)
{
Logger.LogException(ex, this);
throw ex;
}
return System.Text.Encoding.UTF8.GetString(plain);
}
public static void CreateNewKeys(string publicKeyPath, string privateKeyPath)
{
try
{
Logger.LogInfo("Creating new keys", new object());
Logger.LogInfo("Creating RSA Crypto Service Provider", new object());
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
Logger.LogInfo(string.Format("Deleting private key: {0}", privateKeyPath), new object());
if (File.Exists(privateKeyPath)) File.Delete(privateKeyPath);
XmlDocument publicPrivateKeyXML = new XmlDocument();
publicPrivateKeyXML.LoadXml(rsa.ToXmlString(true));
Logger.LogInfo(string.Format("Creating private key: {0}", privateKeyPath), new object());
publicPrivateKeyXML.Save(privateKeyPath);
Logger.LogInfo(String.Format("Deleting public key: {0}", publicKeyPath), new object());
if (File.Exists(publicKeyPath)) File.Delete(publicKeyPath);
XmlDocument publicOnlyKeyXML = new XmlDocument();
publicOnlyKeyXML.LoadXml(rsa.ToXmlString(false));
Logger.LogInfo(String.Format("Creating public key: {0}", publicKeyPath), new object());
publicOnlyKeyXML.Save(publicKeyPath);
}
catch (Exception ex)
{
Logger.LogException(ex, new object());
throw ex;
}
}
}
}
This class is designed to use public & private key pairs that are stored on a file system in xml using RSA encryption. The production implementation of this is for decrypting database passwords at runtime in a web application. My database connection strings are stored in the web.config for the application and the passwords are embedded in these connection strings. Normally these passwords could be stored in clear on the server since no one other than the administrator can access the box. However, this thought fell apart once we put in an application to schedule releases. This application allowed us to schedule when a release was happening, what date, who it affects, etc. The other thing the application allowed for was the attachment of the change to go into production. This application release schedule is an internal application and since all the code is compiled, placing the code changes in this list was great for our needs because it tied the code change directly to the request so that if we had a historical question about anything we could always look back in the application release schedule.
The one problem with this though had to do with the connection strings. In many cases the release would cause a change to the web.config. Since this web.config has production database passwords, we didn’t want to attach it to the request in clear, as it was the one glaring item that someone who wished to be malicious could do something with. So our solution was to encrypt the password. We could have encrypted the whole connection string, but personally I like to be able to see information about the connection in clear as it makes for easier debugging in my opinion. Plus, if the user doesn’t have the password they can’t do too much with the other information.
Thus was born the class listing above. This class is a generic RSA Encryption class that can generate a new public/private key pair to xml stored on the file system and can encrypt and decrypt from keys passed to it retrieved from the file system (or anywhere else for that matter). I chose to use RSA encryption for a couple of reasons. One is that since the password is stored and retrieved from the web.config, a one way hash wouldn’t do much for us. I could have used a symmetric key algorithm, but then all of the developers would have to have access to the one key that would encrypt and decrypt the password. RSA, or any asymmetric algorithm, allowed me to give the developers a key to encrypt with while protecting the one key that can decrypt.
I keep referring to the keys being stored on the file system because the production implementation works like this…
We generate the public/private key pair to be used in production. One trusted developer or an admin has permissions to do this (I created a utility to generate the key/pairs so a non-programmer can be assigned the task of managing the keys). Once the keys are generated, the public key is stored in source control. This way all the developers have access to the public key for encrypting passwords to go into a connection string. The admin then takes the private key and installs it to a secure directory on the server that the application user account has access to. So at this point, the public key is…erm…public, and the private key is secured so that only the server admin and the application user have access. What this does is minimize who can decrypt a password. Sure anyone could encrypt and insert a new password and that password would be decryped properly at runtime, it’s pretty much useless unless that change has been done on the database as well. In the scenario presented in this post, one developer will have permissions to modify the database password, thus this individual is responsible for encrypting the password. With this policy in place, no one other than this point person knows the production db password, and that’s the way I want it. Getting back to the decryption part, we have stored the private key in a secure directory that the application user has access to. At runtime, when the database connection is created, the application is configured to pull the private key from this secure directory, pass it into the above listed class so that the decrypt method can be called. Since all of this is happening in memory, there should be no easy way for an attacker to view the password in clear.
As for how this works in development, the developer can pretty much do whatever he wants regarding this. The data access layer can still work just fine with non-encrypted strings, so in development the programmer can enter whatever the password is for his local database. The encryption utility is also stored in source control so any developer can create his own custom keys and use those to encrypt/decrypt in his local environment. Everyone just needs to be sure that the production config always go out the door with its password encrypted using the production public key.
For more information on RSA Encryption in .NET, here are some good references:
http://www.codeproject.com/KB/security/SimpleEncryption.aspx