Login


Generating a <machineKey> Element

By Jonathan Wood on 4/26/2011
Language: C#
Technology: .NETASP.NET
Platform: Windows
License: CPOL
Views: 20,431
Web Development » ASP.NET » General » Generating a <machineKey> Element

Test Project Screenshot

Download Source Code Download Source Code

Introduction

ASP.NET takes care of a number of security concerns during normal processing of web pages. Forms authentication tickets must be tamper-proof and encrypted, and ASP.NET must be able to detect any modifications or corruption to ViewState data. It accomplishes this through the use of a hashed message authentication code (HMAC), which is generated from the ViewState data.

The <machineKey> element can placed in the <system.web> section of your application's web.config file. This element configures the keys and algorithms ASP.NET uses to generate the HMAC.

Although <machineKey> attributes all have default values, you should manually set these attributes to specific and unique values. This is particularly true if your website is running on a web farm to ensure the same keys and algorithms are always used.

Due to the nature of these keys, generating them is a perfect task for the computer. So in this article I'll present code that will generate a valid <machineKey> element with unique key attributes that you can use in your own web.config file.

A MachineKey Generator Class

Listing 1 shows my MachineKey class. This class has only one public method, Generate(), which is static. This method will generate a random <machineKey> element suitable for pasting into the <system.web> section of your web.config file.

The Generate() method takes a single argument: A MachineKeyVersion enum that indicates the version of ASP.NET being targeted. There are some variations in the <machineKey> element between ASP.NET version 1.1 and version 2.0. Specify MachineKeyVersion.Net1 to target ASP.NET version 1.1, or MachineKeyVersion.Net2 to target ASP.NET version 2.0 and later.

The Generate() method starts by calling the GenerateKey() method to generate a string of random values of the specified length. It then formats the final <machineKey> element according to the specified target version of ASP.NET.

Listing 1: The MachineKey Class

/// <summary>
/// Version arguments to MachineKey.Generate() method.
/// </summary>
public enum MachineKeyVersion
{
    /// <summary>
    /// .NET version 1.1.
    /// </summary>
    Net1,

    /// <summary>
    /// .NET version 2.0 and up.
    /// </summary>
    Net2,
}

public class MachineKey
{
    /// <summary>
    /// Generates the contents of a machineKey element suitable for use in
    /// an ASP.NET web.config file.
    /// </summary>
    /// <param name="version">Indicates if keys should be generated for
    /// ASP.NET 1.1 or 2.0 and later.</param>
    public static string Generate(MachineKeyVersion version)
    {
        // Generate keys
        string validationKey = GenerateKey(64);
        string decryptionKey;
        if (version == MachineKeyVersion.Net1)
            decryptionKey = GenerateKey(24);
        else
            decryptionKey = GenerateKey(32);

        // Construct <machineKey> tag
        StringBuilder builder = new StringBuilder();
        builder.Append("<machineKey");
        builder.AppendFormat(" validationKey=\"{0}\"", validationKey);
        builder.AppendFormat(" decryptionKey=\"{0}\"", decryptionKey);
        builder.Append(" validation=\"SHA1\"");
        if (version == MachineKeyVersion.Net2)
            builder.Append(" decryption=\"AES\"");
        builder.Append(" />");
        return builder.ToString();
    }

    /// <summary>
    /// Generates a string of random hex digits of the specified
    /// number of bytes.
    /// </summary>
    /// <param name="length">Number of bytes to generate</param>
    protected static string GenerateKey(int length)
    {
        RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
        byte[] buff = new byte[length];
        rngCsp.GetBytes(buff);
        StringBuilder sb = new StringBuilder(buff.Length * 2);
        for (int i = 0; i < buff.Length; i++)
            sb.Append(string.Format("{0:X2}", buff[i]));
        return sb.ToString();
    }
}

Using the Code

Using the MachineKey class is very straight forward. Since the Generate() method is static, no class instance is required. Simply call this method to have it return a valid <machineKey> element.

Listing 2 shows sample code that uses the MachineKey class. The code tests the value of two radio buttons to determine the correct version of ASP.NET to be targeted.

Listing 2: Calling the MachineKey.Generate() Method

private void btnGenerate_Click(object sender, EventArgs e)
{
    MachineKeyVersion version;

    if (radNet1.Checked)
        version = MachineKeyVersion.Net1;
    else
        version = MachineKeyVersion.Net2;

    txtMachineKey.Text = MachineKey.Generate(version);
}

Conclusion

And that's about all there is to it. Of course, there is a lot more that can be learned about the <machineKey> element in the web.config file. For more information, check out the machineKey Element on MSDN.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.