Click here to Skip to main content
15,894,460 members
Articles / Web Development / ASP.NET

Central Key Management

Rate me:
Please Sign up or sign in to vote.
4.63/5 (18 votes)
8 Mar 200610 min read 64.2K   1.2K   49  
A central key manager for multiple web server clients in a web farm.
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Core.Cryptography
{
    public static class CryptHelper
    {
        private static readonly string _storageSlot = "__KeyManagerAsymmetricKeys";
        private static readonly object _storageLock = new object();

        static CryptHelper()
        {
            Dictionary<string, RSACryptoServiceProvider> list = new Dictionary<string, RSACryptoServiceProvider>();
            AppDomain.CurrentDomain.SetData(_storageSlot, list);
        }

        public static WrappedData AsymmetricEncrypt(RSACryptoServiceProvider csp, string plainText)
        {
            // Generate the temporary Session Key
            RijndaelManaged symmetric = new RijndaelManaged();
            symmetric.GenerateIV();
            symmetric.GenerateKey();

            // encrypt the data using the temporary session Key
            byte[] inputBuffer = Encoding.Unicode.GetBytes(plainText);
            byte[] encryptedData = symmetric.CreateEncryptor().TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);

            // encrypt the session key using the Asymmetric CSP
            byte[] encryptedKeyData = csp.Encrypt(symmetric.Key, true);

            // Create the wrapped data structure
            WrappedData wrappedData = new WrappedData();
            wrappedData.EncryptedData = Convert.ToBase64String(encryptedData);
            wrappedData.EncryptedKey = Convert.ToBase64String(encryptedKeyData);
            wrappedData.IV = Convert.ToBase64String(symmetric.IV);
            return wrappedData;
        }

        public static WrappedData AsymmetricEncrypt(string certificateThumb, string plainText)
        {
            RSACryptoServiceProvider csp = GetAsymmetricKey(certificateThumb, false);
            WrappedData wrappedData = AsymmetricEncrypt(csp, plainText);
            wrappedData.Certificate = certificateThumb;
            return wrappedData;

        }

        public static string AsymmetricDecrypt(WrappedData wrappedData)
        {
            // Get the Asymmetric key that matches the wrapped data certificate
            RSACryptoServiceProvider csp = GetAsymmetricKey(wrappedData.Certificate, true);

            // decrypt the temporary Symmetric Key
            byte[] clearKey = csp.Decrypt(Convert.FromBase64String(wrappedData.EncryptedKey), true);
            byte[] iv = Convert.FromBase64String(wrappedData.IV);
            byte[] encryptedData = Convert.FromBase64String(wrappedData.EncryptedData);

            // Setup the tetm
            RijndaelManaged symmetric = new RijndaelManaged();
            byte[] clearData = symmetric.CreateDecryptor(clearKey, iv).TransformFinalBlock(encryptedData, 0, encryptedData.Length);
            return Encoding.Unicode.GetString(clearData);
        }

        private static RSACryptoServiceProvider GetAsymmetricKey(string thumb, bool includePrivate )
        {
            Dictionary<string, RSACryptoServiceProvider> list =
                AppDomain.CurrentDomain.GetData(_storageSlot) as Dictionary<string, RSACryptoServiceProvider>;

            if (list == null)
            {
                throw new ApplicationException("Invalid State: The key storage is not setup");
            }

            RSACryptoServiceProvider csp = null;
            if (list.ContainsKey(thumb) == false)
            {
                lock (_storageLock)
                {
                    if (csp == null)
                    {
                        csp = LoadKey(thumb, includePrivate);
                        list[thumb] = csp;
                    }
                }
            }
            else
            {
                csp = list[thumb];
            }

            return csp;

        }

        public static string CreateSessionKeyString()
        {
            RijndaelManaged csp = new RijndaelManaged();
            csp.GenerateIV();
            csp.GenerateKey();

            String xml = string.Format( 
                "<RijndaelManagedKey format='B64'><Key>{0}</Key><IV>{1}</IV></RijndaelManagedKey>", 
                System.Convert.ToBase64String( csp.Key ), 
                System.Convert.ToBase64String( csp.IV ) );

            return xml;
        }

        public static RijndaelManaged GetSessionKey(string sessionKeyString)
        {
            System.Xml.XmlDocument document = new System.Xml.XmlDocument();
            document.LoadXml(sessionKeyString);

            System.Xml.XmlNode node = document.SelectSingleNode("/RijndaelManagedKey");
            System.Xml.XmlAttribute attribute = node.Attributes["format"];
            if (attribute != null && attribute.Value != "B64")
                throw new ApplicationException("Unknown key format " + attribute.Value);

            byte[] key = null;
            byte[] iv = null;

            foreach (System.Xml.XmlNode child in node.ChildNodes)
            {
                switch (child.Name)
                {
                    case "Key":
                        key = Convert.FromBase64String(child.InnerText);
                        break;

                    case "IV" :
                        iv = Convert.FromBase64String(child.InnerText);
                        break;
                }
            }

            RijndaelManaged csp = new RijndaelManaged();
            csp.Key = key;
            csp.IV = iv;

            return csp;
        }
        
        private static RSACryptoServiceProvider LoadKey(string thumb, bool includePrivate)
        {
            System.Security.Cryptography.X509Certificates.X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);

            string certThumb = thumb.Replace(" ", string.Empty);

            foreach (X509Certificate2 certificate in store.Certificates)
            {
                if (certThumb.ToLower() == certificate.Thumbprint.ToLower())
                {
                    RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
                    if (includePrivate == true)
                    {

                        if (certificate.HasPrivateKey == false)
                            throw new ArgumentException("Private key for specified key is not available");

                        csp.FromXmlString(certificate.PrivateKey.ToXmlString(true));

                    }
                    else
                    {
                        csp.FromXmlString(certificate.PublicKey.Key.ToXmlString(false));
                    }

                    return csp;
                }
            }

            throw new ApplicationException("Specified certificate was not found on this machine");
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions