In this blog I am going to describe my journey towards building a utility called SAFE that helps in managing Key Containers. I’ll go through the case study, how and why I felt the need for such a utility and where I began.
Case Study
A client requested that connection string information in a config file be encrypted.
A config file or a configuration file is a text file with .config extension. This file saves all types of information that is specific to an application, such as, app settings, connections to Databases, security configurations, etc. Biggest advantage of such a file is during deployment. When an application is moved from Test to Production, all that is needed to is modify the configuration settings and point them to production server.
This file usually resides on Application Servers which are believed to be secured, and internal users are not expected to fiddle with it. Still it is just a text file, and nothing can stop users from opening it in Notepad and peeking through. Here is how a typical database connection to SQL server using SQL Server authentication is saved inside a config file.
<add name =”DBConnect”
connectionString=”
Server=myServerName\myInstanceName;
Database=myDataBase;
User Id=myUsername;
Password=myPassword;”/>
Since the password it out there in plain text for everyone to see, anyone can open SQL Server Management Studio and connect to the database using these credentials. This can be avoided by using Integrated Security or Trusted_Connection. But there are situations where you must use User credentials stored in config file.
So, the client’s request to encrypt the password is genuine.
Solution:
If you haven’t guessed it already, the solution is simple and straight forward – Encryption.
Now you can encrypt the entire file or sections of it. ASP.Net 2.0 introduced a feature called ‘Protected Configuration’ that lets you encrypt the sections of config file, although specifically built for Web app, this can also be used for Windows applications. So, the connection string section would look something like this after encryption.
<connectionStrings configProtectionProvider=”DataProtectionConfigurationProvider”>
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAH2… </CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
This is less desired to me personally, as the whole section is encrypted and the only way to look at the decrypted text is inside the code. If I were asked to provide support and debug production let’s say after a year, I would not remember what SQL server the application is pointed to or what authentication is used just by looking at the config file. It makes more sense to me, if only the password is encrypted not the whole section.
I would then pick an encryption algorithm to encrypt just the password. Since we are not working with large stream of data and we wish to encrypt just passwords, the encryption type that we would use is Asymmetric Encryption. You can read more on Encryption in my previous blog here. This type of encryption works with a pair of key, Public and Private. Information is encrypted using Public Key and decrypted using Private Key. The .NET Framework has support for asymmetric encryption under classes RSACryptoServiceProvider and DSACryptoServiceProvider.
So figuratively, I should be able to:
- Write code to generate a Key pair, Public and Private
- Encrypt the password using Public Key
- Copy that Encrypted password and put it in Config file
- Write code to decrypt password using the Private key generated in step 1.
Step 1, Step 2 and Step 3 will be called only once while setting the configurations.
Step 4 will be called every time the application is run, just before a user is authenticated. For Step4, I would need the key generated in step 1 which was executed when the application was deployed. This could be very well-done months ago. So, I need a safe place where I can go look for the Private key every time Step 4 is executed. I cannot save this in a database since user is not connected to the database at this point, in fact we are decrypting credentials to the dataset connection 😉 I can choose to save this in the code itself, like “hard code” it, there I said it! But what means is, every time there is a change to the password, code needs to be changed and re-deployed. Urgh!
Light bulb moment! We can save the keys in Key Containers.
Key Containers
Key Containers are not fancy looking as shown in the picture here; they are simple FOLDERS! In Windows OS, there are two locations where the keys are stored, one is at the machine level and another is at user level.
Machine Level RSA Key Container path is C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
User-Level RSA Key Container path is C:\Users\mwad\AppData\Roaming\Microsoft\Crypto\RSA\
If you open one of the file in the container then you will see that it is encrypted.
Big Problem!!!
As you can see the Key Containers are very cryptic, the name of the container is a GUID!! … so very not descriptive. If you look carefully, after opening the file in notepad, the Container name is saved inside in plain text at 38th character in most cases. If I want to know if my Application server has the Private key that my code is looking for then I need to open each file and look for the Container name. And how exactly I copy this from Test to Production? Is it as simple as copy paste? I was sincerely hoping that there would be a Utility which would allow me to manage my Key Containers, but there isn’t anything out there, So I decided to write my own.
SAFE Utility – to the rescue
At the very core of it, SAFE Utility would allow the following functions – Create and Retrieve Containers by name, Delete Containers, Encrypt data, Decrypt data, Import and Export Keys.
How to use SAFE?
SAFE is a Desktop Application that can run on any machine. SAFE also has a library that can be used inside your code. This ensures that the encryption and decryption process is compatible and using the same code base.
Step 1: Install SAFE on the Application server
Step 2: Pick a Container Name (something that describes your Application). It is a good idea to save this in the config file as well.
Step 3: Use SAFE to Create a Key Pair. Keys are saved in the Machine Level RSA Key Container folder (figure 2)
Step 4: Using SAFE, Encrypt the password and update the config file on the Application server.
Step 5: Modify code, add reference to SAFE dlls. Use this library to decrypt the password.
Step 5: Use the Container Name saved in config file in Step 2 and retrieve the Private key for it from the Machine level RSA Key Container folder.
Step 6: Decrypt the password using Private key retrieved in Step 5 and use it to authenticate a user and make a connection to the database.
What will happen if credentials change in the future?
Perform Step 4, simply encrypt the password using the same Container and update config file.
What if the Application is running on local computers?
This may be the case for Desktop applications. Use SAFE to Export the Private key from Application server and Import it on the Local Computer.
What about security?
SAFE has role-based security based on your Windows login. Assign a Role in Active Directory to be able to access SAFE Application.
If you have any questions about SAFE Utility or just want to discuss what we can offer to make your Applications secure, contact us at KTL Solutions, 301-360-0001.