Monday, 18 July 2011

Use MD5 to Encrypt Passwords with ASP.NET 4.0 and C#


This tutorial will demonstrate how to use MD5 to encrypt passwords in your database using ASP.NET 4.0 and C#.

MD5 is a one way encryption technique, which means that once the password is encrypted we will not be able to decrypt it. We use this for scenarios similar to a user's password because we don't want anyone to determine a user's password from the database. When a given password is encrypted with MD5, that password will always generate the same array of 16 bytes. This means that there is actually no need to decrypt user passwords, instead we simply need to encrypt their password and then verify if the array of bytes returned by the MD5 encryption matches the array of bytes stored in the database. This allows us to keep their passwords safe because we don't need to send the user's password over the internet to and from the database, instead we use the encrypted form of it that cannot be decrypted.

Need help with cloud hosting? Try Server Intellect. We used them for our cloud hosting services and we are very happy with the results!

Adding the Database
For this example, we will need to create a simple web site with a database that we will use to encrypt some data. Our database will need to store a user id, user name, and password. At this point, I have created a new ASP.NET Empty Web Site. To begin:
  1. Right click the project in your solution explorer.
  2. Select add ASP.NET folder.
  3. Select App_Data.
  4. Right click the App_Data folder.
  5. Select add new item...
  6. Select a SQL Database.
  7. Name it 'Database.mdf'.
  8. Click add.
Next, we need to add in a table to the database that we will use to store our user data. To do this:
  1. Expand the Database.mdf folder in your server/database explorer.
  2. Right click the Tables folder.
  3. Select add new table.
  4. Add the following columns with their respective types to the table:
    Column Name  Data Type 
    UserId  int 
    UserName  nvarchar(50) 
    Password  binary(16) 
  5. Right click the UserId column and select set primary key.
  6. Change the IsIdentity property of the UserId column to 'Yes'.
  7. Save the table as 'Users'.
This has setup a simple table for us to store our user data. Notice that the password is a binary data type, this is because the MD5 encryption will return to us a byte array of size 16.

Adding the ConnectionString
Next, we need to setup a connection string to the database we have added. To do this, open up the Web.Config file for editing and add in the following code between the <configuration> and <system.web> tags:
<connectionStrings>
<add name="ConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient"/>
</connectionStrings>

I just signed up at Server Intellect and couldn't be more pleased with my fully scalable & redundant cloud hosting! Check it out and see for yourself.

Adding the Default.aspx Page
To test this out, we will need to create a simple web form with two textboxes, two buttons, and a label so that we can collect data from the user and then store and retrieve that data from our database. To setup our form:
  1. Right click the project in your solution explorer.
  2. Select add new item...
  3. Select a web form.
  4. Name it 'Default.aspx'.
  5. Click add.
  6. Open Default.aspx up to design mode.
  7. From the top menu, select Table -> Insert Table.
  8. Add a table with 3 rows, 2 columns, and an unsepcified width.
  9. In the top left cell, type in 'UserName: '.
  10. Beneath this cell, type in 'Password: '.
  11. In the top right cell, drag and drop a textbox.
  12. Change the ID property of the textbox to 'txtUserName'.
  13. Beneath this cell, drag and drop a textbox.
  14. Change the ID propety of the textbox to 'txtPassword'.
  15. Change the TextMode property of the textbox to 'Password'.
  16. Select the two cells from the bottom row and merge them.
  17. Set the alignment of the bottom row to center.
  18. Drag and drop a button into the bottom row.
  19. Change the ID property of the button to 'btnCreate'.
  20. Change the Text propert of the button to 'Create Account'.
  21. Add a break line underneath the table.
  22. Drag and drop a button after the break line.
  23. Change the ID property of the button to 'btnCheck'.
  24. Change the Text property of the button to 'Check Data'.
  25. Drag and drop a label next to btnCheck.
  26. Change the Text property of the label to an empty string. 
You should now have a simple form that looks like this:


Encrypting the Password
Now that we have our form all setup, we need to add in some functionality to accept input from the user, encrypt the data, and then store it in our database. Then, we will add some functionality to check the encrypted password in the database and ensure that it is being stored properly. To begin, open Default.aspx up to design mode and double click btnCreate to generate the click event method for that button. Then, at the top of the Default.aspx.cs class add in the following using statements:
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Security.Cryptography;
using System.Text;

We used over 10 web hosting companies before we found Server Intellect. Our cloud hosting,was set up in less than 24 hours. We were able to confirm our order over the phone. They responded to our inquiries within an hour. Server Intellect's customer support and assistance are the best we've ever experienced.

Next, add in the following code to the btnCreate_Click event method:
protected void btnCreate_Click(object sender, EventArgs e)
{
    //get the username
    string UserName = txtUserName.Text;

    //create the MD5CryptoServiceProvider object we will use to encrypt the password
    MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
    //create an array of bytes we will use to store the encrypted password
    Byte[] hashedBytes;
    //Create a UTF8Encoding object we will use to convert our password string to a byte array
    UTF8Encoding encoder = new UTF8Encoding();

    //encrypt the password and store it in the hashedBytes byte array
    hashedBytes = md5Hasher.ComputeHash(encoder.GetBytes(txtPassword.Text));

    //connect to our db
    SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

    //sql command to add the user and password to the database
    SqlCommand cmd = new SqlCommand("INSERT INTO Users(UserName, Password) VALUES (@UserName, @Password)", conn);
    cmd.CommandType = CommandType.Text;

    //add parameters to our sql query
    cmd.Parameters.AddWithValue("@UserName", UserName);
    cmd.Parameters.AddWithValue("@Password", hashedBytes);

    using (conn)
    {
        //open the connection
        conn.Open();
        //send the sql query to insert the data to our Users table
        cmd.ExecuteNonQuery();
    }

}

Let's review what this code is actually doing when the user clicks this button. First, we need to prepare the data before we store it in the database by grabbing the username and encrypting the password. Then, we simply use a SQL query to store the data in our database.

That's pretty much it for actually encrypting the password and storing it in the database, but in order to verify that we have actually stored the correct data we will add some functionality to btnCheck to display the encrypted password as a byte array. To do this, open Default.aspx to design mode and double click btnCheck. Then, add the following code to the btnCheck_Click event method:
protected void btnCheck_Click(object sender, EventArgs e)
{
    //clear the text of our label
    Label1.Text = ""

    //create an array of bytes to store the encrypted password in
    Byte[] password = new Byte[16];

    //connect to our db
    SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

    //sql command to add the user to the database
    SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserName=@UserName", conn);
    cmd.CommandType = CommandType.Text;

    //selected where UserName is the current username in txtUserName
    cmd.Parameters.AddWithValue("@UserName", txtUserName.Text);

    using (conn)
    {
        //open the connection
        conn.Open();
        //execute query and store results in a sqldatareader
        SqlDataReader rdr = cmd.ExecuteReader();
        //read the data we have selected
        if (rdr.Read())
        {
            //store the password from the db
            password = (Byte[])rdr["Password"];
        }
    }

    //output each byte individually to our label
    foreach (Byte b in password)
    {
        Label1.Text += b.ToString() + " ";
    }

}

This code simply selects the row of the database where the user name corresponds to the text in txtUserName and then stores the data from the password column in a byte array. Then, we output each of those bytes to our label seperated by spaces.

If you're looking for a really good web host, try Server Intellect - we found the setup procedure and their control panel, very easy to adapt to and their IT team is awesome!

Testing
To test this out, load up the web site. Input some data for the user name and password and click btnCreate. Then, click btnCheck to verify that you have 16 bytes of data. Here is my sample data and the results:
UserName: 'admin'
Password: 'default!'


The Default.aspx source looks like this:
<body>
    <form id="form1" runat="server">
    <div>
    
        <table>
            <tr>
                <td>
                    UserName:</td>
                <td>
                    <asp:TextBox ID="txtUserName" runat="server"></asp:TextBox></td>
            </tr>
            <tr>
                <td>
                    Password:</td>
                <td>
                    <asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <asp:Button ID="btnCreate" runat="server" Text="Create Account" 
                        onclick="btnCreate_Click" />
                </td>
            </tr>
        </table>
    
        <br />
        <asp:Button ID="btnCheck" runat="server" Text="Check Data" onclick="btnCheck_Click" />
        <asp:Label ID="Label1" runat="server"></asp:Label>

    </div>
    </form>
</body>

No comments:

Post a Comment