Introduction
I didn't want plain text configuration files for my production SQL server, I
wanted those blocks encrypted with TripleDES. So, what I decided to do was
create a class that could read and write configuration files with both plain and
encrypted text. (For use in an ASP.NET app).
Updates
2/29/04:
A security hole has been patched where you could see the
Private key code using a reflection utility. Now, you can still see the variable
decleration but you can not see its value. The source code and demo projects
have been updated.
3/1/04:
A security fix to the file names extention was made to
prevent the settings.config file from being downloaded. I have also included
batch files for commandline compileing.
Problems with security
The only drawback (or good point, depending how you look at it) is that to
change the private key the source code has to be changed and recompiled. All the
encrypted items that are written out by the program have their own unique public
key for maximum security. Lets look at a file:
<appSettings>
<add key="ownersName" value="Matthew" />
<add key="emailServer" value="FRAGPDC" />
<add key="sqlServer" value="FRAGPDC" />
<add key="sqlUser" encode="90lIn5/qBsY=" value="Dk3fxrNRfvM=" />
<add key="sqlPassword" encode="YRG9vvfk9m0="
value="SrczFf67nLlL0XgJjfm3gQ==" />
</appSettings>
As you can see not every line is encrypted only the ones that require extra
security are encrypted TripleDES. On the lines that are encrypted the [encode]
attribute is the public key for that item. The private key is safely tucked away
in the compiled DLL.
Reading the data
It is very easy to Read or Display the data using the getSetting
method.
Configure.getSetting(key);
key is the name of the key you want from the settings file. If there is no
key by that name in the settings file then an empty string will be returned.
Writing the data
Its just as easy to write the data, all you need to do is use the
writeSetting
method.
Write an encrypted string:
Configure.writeSetting(thisKey, Request.Form[thisKey], true);
Write a text string:
Configure.writeSetting(thisKey, Request.Form[thisKey], false);
thisKey
is the name of the key,
Request.Form[thisKey]
is the value of the key and the
true
or false
is if you want encryption.
Changing the private key
I have included a program that when run will generate a new random key. Here
is some sample output:
Next you need to change this line in the source code:
Code
The code in the keyGeneration app is very much similar to the code in the DLL
so lets take a look at it. First we have to tell the app what classes we want to
use. The System.Text
class will provide character encoding services
and System.Security.Cryptography
is where the algorithms for the
encryption are stored.
using System;
using System.Text;
using System.Security.Cryptography;
class MainClass
{
public static TripleDESCryptoServiceProvider des =
new TripleDESCryptoServiceProvider();
Tto encode and decode the string we have two functions:
private static string encode(string thisEncode)
{
string encrypted;
byte[] Code = ASCIIEncoding.ASCII.GetBytes(thisEncode);
encrypted = Convert.ToBase64String(
des.CreateEncryptor().TransformFinalBlock(Code, 0,
Code.Length)
);
return encrypted;
}
private static string decode(string thisDecode)
{
string decrypted;
byte[] Code = Convert.FromBase64String(thisDecode);
decrypted = ASCIIEncoding.ASCII.GetString(
des.CreateDecryptor().TransformFinalBlock(Code, 0,
Code.Length)
);
return decrypted;
}
Here is the main block of code to tie it together:
public static void Main(string[] args)
{
des.GenerateIV();
des.GenerateKey();
Console.WriteLine("New Key");
Console.WriteLine("You only need to cut and paste the private key " +
"into the source");
Console.WriteLine();
Console.WriteLine(" Public: {0}", Convert.ToBase64String(des.IV));
Console.WriteLine("Private: {0}", Convert.ToBase64String(des.Key));
Console.WriteLine();
string encoded = encode("[Triple DES] This is an encoded string");
Console.WriteLine("Encoded: {0}", encoded);
Console.WriteLine("Decoded: {0}", decode(encoded));
Console.WriteLine();
Console.Write("Press return to exit...");
Console.ReadLine();
}
The web Page
Basically this is just a standard aspx web page that imports the namespace of
the dll and gathers its information on the PostBack
event.
<%@ Page language="c#" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="appSettings.Settings" %>
<script runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
if (this.IsPostBack)
{
foreach (string thisKey in Request.Form.AllKeys)
{
if (thisKey != "__VIEWSTATE")
if ((thisKey == "databasePassword") ||
(thisKey == "databaseUser"))
{
Configure.writeSetting(thisKey,
Request.Form[thisKey], true);
}
else
{
Configure.writeSetting(thisKey,
Request.Form[thisKey], false);
}
}
}
}
</script>
<HTML>
<HEAD>
<title>Setup</title>
<link rel="stylesheet" type="text/css" href="setup.css" />
</HEAD>
<body>
<form id="appSettings" method="post" runat="server">
<div id="content">
<div class="title">Database Server Settings<hr></div>
<div class="smallTab" id="text">Database Server:</div>
<div class="bigTab"><input type=text name="databaseServer"
value="<%= Configure.getSetting("databaseServer") %>"
size=30></div>
<div class="smallTab" id="text">Database User:</div>
<div class="bigTab"><input type=text name="databaseUser"
value="<%= Configure.getSetting("databaseUser") %>"
size=30></div>
<div class="smallTab" id="text">Database Name:</div>
<div class="bigTab"><input type=text name="databaseName"
value="<%= Configure.getSetting("databaseName") %>"
size=30></div>
<div class="smallTab" id="text">Database Password:</div>
<div class="bigTab"><input type=password name="databasePassword"
value="<%= Configure.getSetting("databasePassword") %>"
size=30></div>
<div align="center"><input type="submit" value=" Update Database
Settings "></div>
</div>
</form>
</body>
</HTML>
To install the web page just uncompress the configure_demo.zip into an
empty directory under the wwwroot tree.
IMPORTANT: Don't forget to go
into the internet control panel and set this directory as an application
otherwise the DLL won't be found!
Permissions
For security reasons I didn't write this to the web.config
file,
its written to settings.config
. Now if the ASPNET service (Who your
webserver runs as) creates this file the permissions will be fine. But if you
create this file you will need to give the ASPNET user access to write to the
file. Also if you go in and edit the file later by hand you will need to reset
the permissions. You have been warned :-)