Asymmetric encryption in C# using RSA

Feel free to re-use this code for asymmetric encryption/decryption of large data.

    /// <summary>
    /// Asymmetric key pair container.
    /// </summary>
    public class AsymmetricKeyPair
    {
        private readonly string _publicKey;
        private readonly string _privateKey;

        internal AsymmetricKeyPair(string publicKey, string privateKey)
        {
            _publicKey = publicKey;
            _privateKey = privateKey;
        }

        /// <summary>
        /// Asymmetric private RSA key.
        /// </summary>
        public string PrivateKey
        {
            get { return _privateKey; }
        }

        /// <summary>
        /// Asymmetric public RSA key.
        /// </summary>
        public string PublicKey
        {
            get { return _publicKey; }
        }
    }
    /// <summary>
    /// Asymmetric encryption class that provides:
    /// <ul>
    /// <li>Generation of Asymmetric encryption/decryption keys using RSA.</li>
    /// <li>Encryption of text using asymmetric public key.</li>
    /// <li>Decryption of text using asymmetric private key.</li>
    /// </ul>
    /// </summary>
    public static class AsymmetricEncryption
    {
        #region "Private members"
        private static bool _optimalAsymmetricEncryptionPadding = false;
        #endregion

        #region "Public members"
        public static bool OptimalAsymmetricEncryptionPadding
        {
            get { return _optimalAsymmetricEncryptionPadding; }
            set { _optimalAsymmetricEncryptionPadding = value; }
        }
        #endregion

        #region "Public methods"
        /// <summary>
        /// Generates a new pair of asymmetric encryption/decryption keys
        /// </summary>
        /// <param name="keySize">The size of the key to be used in bits. Recommended 1024.</param>
        /// <returns>Returns <see cref="AsymmetricKeyPair"/></returns>
        /// <exception cref="ArgumentException">Thrown in the following situations
        /// <ul>
        /// <li>An invalid key size is provided.</li>
        /// </ul>
        /// </exception>
        public static AsymmetricKeyPair GenerateKeys(int keySize)
        {
            if (!IsKeySizeValid(keySize)) throw new ArgumentException("The provided key size is invalid.", "keySize");
            using (var provider = new RSACryptoServiceProvider(keySize))
            {
                return new AsymmetricKeyPair(provider.ToXmlString(false), provider.ToXmlString(true));
            }
        }

        /// <summary>
        /// Encrypts the provided text using the public key.
        /// </summary>
        /// <param name="text">Text to be encrypted.</param>
        /// <param name="publicKeyXml">XML string containing the public RSA key.</param>
        /// <param name="keySize">Size of the key used when generating the key pair. Default 1024 bits.</param>
        /// <returns>Encrypted text.</returns>
        /// <exception cref="ArgumentException">Thrown in the following situations
        /// <ul>
        /// <li>The provided text is empty or null.</li>
        /// <li>Length of the provided text exceeds the maximum string length that can be encrypted for the specified key size.</li>
        /// <li>An invalid key size is provided.</li>
        /// <li>The provided key is null or empty.</li>
        /// </ul>
        /// </exception>
        /// <exception cref="CryptographicException">Thrown when the format of the provided key is invalid.</exception>
        public static string EncryptText(string text, string publicKeyXml, int keySize)
        {
            int byteKeySize = keySize / 8;
            byte[] bytes = Encoding.UTF32.GetBytes(text);
            int maxLength = byteKeySize - 42;
            int dataLength = bytes.Length;
            int iterations = dataLength / maxLength;
            StringBuilder stringBuilder = new StringBuilder();

            if (!IsKeySizeValid(keySize)) throw new ArgumentException("The provided key size is invalid.", "keySize");
            if (String.IsNullOrEmpty(publicKeyXml)) throw new ArgumentException("The provided key is null or empty", "publicKeyXml");

            RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(keySize);
            rsaCryptoServiceProvider.FromXmlString(publicKeyXml);

            for (int counter = 0; counter <= iterations; counter++)
            {
                byte[] tempBytes = new byte[(dataLength - maxLength * counter > maxLength) ? maxLength : dataLength - maxLength * counter];
                Buffer.BlockCopy(bytes, maxLength * counter, tempBytes, 0, tempBytes.Length);
                byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt(tempBytes, true);
                Array.Reverse(encryptedBytes);
                stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
            }
            return stringBuilder.ToString();

        }

        /// <summary>
        /// Decrypts the provided text using the public and private RSA key.
        /// </summary>
        /// <param name="text">Text to be decrypted.</param>
        /// <param name="publicAndPrivateKeyXml">XML string containing the public and private RSA key.</param>
        /// <param name="keySize">Size of the key used when generating the key pair. Default 1024 bits.</param>
        /// <returns>Decrypted text.</returns>
        /// <exception cref="ArgumentException">Thrown in the following situations
        /// <ul>
        /// <li>The provided text is empty or null.</li>
        /// <li>An invalid key size is provided.</li>
        /// <li>The provided key is null or empty.</li>
        /// </ul>
        /// </exception>
        /// <exception cref="CryptographicException">Thrown when the format of the provided key is invalid.</exception>
        public static string DecryptText(string text, string publicAndPrivateKeyXml, int keySize)
        {

            RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(keySize);
            rsaCryptoServiceProvider.FromXmlString(publicAndPrivateKeyXml);

            int base64BlockSize = ((keySize / 8) % 3 != 0) ? (((keySize / 8) / 3) * 4) + 4 : ((keySize / 8) / 3) * 4;
            int iterations = text.Length / base64BlockSize;
            var arrayList = new ArrayList();

            for (int i = 0; i < iterations; i++)
            {
                byte[] encryptedBytes = Convert.FromBase64String(text.Substring(base64BlockSize * i, base64BlockSize));
                Array.Reverse(encryptedBytes);
                arrayList.AddRange(rsaCryptoServiceProvider.Decrypt(encryptedBytes, true));
            }
            return Encoding.UTF32.GetString(arrayList.ToArray(Type.GetType("System.Byte")) as byte[]);

        }

        #endregion

        #region "Private methods"
        private static bool IsKeySizeValid(int keySize)
        {
            return keySize >= 384 &&
                   keySize <= 16384 &&
                   keySize % 8 == 0;
        }

        private static int GetMaxDataLength(int keySize)
        {
            //Uncomment the following if we enable toggling of the OAEP option
            if (OptimalAsymmetricEncryptionPadding)
            {
                return ((keySize - 384) / 8) + 7;
            }
            return ((keySize - 384) / 8) + 37;
        }
        #endregion
    }

You can download the nuget package here.

Azure may not be Azure anymore

After the decision to retire the “Live” brand, Microsoft seems to be taking the next step to rename the “Azure” brand. In a recent mail to customers, Microsoft has suggested the new naming. While doing this, I hope Microsoft comes up with names that will qualify the services as cloud-based services. At least for the next few years, we will see the co-existence of cloud-based and on-premise solutions. And we need a set of terms that clearly qualify solution components as either residing on-premise or on the cloud. Hope that gets taken care of…My 2c

Prior Service Name New Service Name
Windows Azure Compute Cloud Services
Windows Azure Platform – All Services All Services
Windows Azure CDN CDN
Windows Azure Storage Storage
Windows Azure Traffic Manager Traffic Manager
Windows Azure Virtual Network Virtual Network
AppFabric Cache Cache
AppFabric Service Bus Service Bus
AppFabric Access Control Access Control
SQL Azure SQL Database
SQL Azure Reporting Service SQL Reporting