Can someone give me the code to encrypt and decrypt a string in C#?

2 upvote
  flag
2 upvote
  flag
Needed something simple... this link worked for me saipanyam.net/2010/03/encrypt-query-strings.html – MrM
4 upvote
  flag
I would HIGHLY recommend dropping 3DES and using AES-GCM. AES-GCM is NOT found in .NET 4.5 crypto libs and IS different from 'usual AES' (=AES-CBC mode usually). AES-GCM is far better than 'usual' AES for cryptographic reason I won't go into. So jbtule has the best answer below under this Bouncy Castle AES-GCM subsection. If you don't believe us, at least trust the experts at the NSA (NSA Suite B @ nsa.gov/ia/programs/suiteb_cryptography/index.shtml : The Galois/Counter Mode (GCM) is the preferred AES mode.) – DeepSpace101
1 upvote
  flag
@Sid Personally I'd prefer AES-CBC + HMAC-SHA2 over AES-GCM for most situations. GCM fails catastrophically if you ever reuse a nonce. – CodesInChaos
upvote
  flag
@CodesInChaos: Nonce reuse sounds like a bad idea to begin with but can you offer more details on this? link or post? GCM supersedes CBC on NSA's Suite B ciphers ... – DeepSpace101
2 upvote
  flag
@Sid Nonce reuse is a bad idea, yes. But I've seen it happen, even with competent programmers/cryptographers. If that happens, GCM breaks down totally, whereas CBC+HMAC only develops some minor weaknesses. With an SSL like protocol GCM is fine, but I'm not comfortable with it as the standard "encrypt&authenticate" API. – CodesInChaos
upvote
  flag
Possible duplicate of Simple two-way encryption for C# – angularsen
upvote
  flag
upvote
  flag
Possible duplicate of Encrypting & Decrypting a String in C# – CraigTP
upvote
  flag
This is a nice thread with functions already written, you can adapt to you r preference - c-sharpcorner.com/UploadFile/145c93/… - see 'Step 2: Creating Helper class.' – David

23 Answers 11

Here is an example using RSA.

Important: There is a limit to the size of data you can encrypt with the RSA encryption, KeySize - MinimumPadding. e.g. 256 bytes (assuming 2048 bit key) - 42 bytes (min OEAP padding) = 214 bytes (max plaintext size)

Replace your_rsa_key with your RSA key.

var provider = new System.Security.Cryptography.RSACryptoServiceProvider();
provider.ImportParameters(your_rsa_key);

var encryptedBytes = provider.Encrypt(
    System.Text.Encoding.UTF8.GetBytes("Hello World!"), true);

string decryptedTest = System.Text.Encoding.UTF8.GetString(
    provider.Decrypt(encryptedBytes, true));

For more info, visit MSDN - RSACryptoServiceProvider

5 upvote
  flag
Sorry to ask such a simple question but can anyone tell me where do I get RSA Key or how do i generate one? – Akash Kava
11 upvote
  flag
Why RSA? RSA has its uses, but nothing indicated that this is one of them. – CodesInChaos
2 upvote
  flag
@CodeInChaos: Because when I have provided this answer, almost 3 years ago, the question originally didn't indicate anything. That was added later. I have answered the original question. Look at the question history and see it for yourself. – Tamas Czinege
31 upvote
  flag
Even in the original question there is no indication that RSA might be a good fit. Asymmetric encryption has its uses, but it's not the right choice as a default encryption. Your example code will fail for longer strings because the RSA class isn't designed for general purpose encryption. If you need the asymmetric features you should encrypt a symmetric key with RSA and encrypt the actual data with that symmetric key. So I still believe your answer is bad advice. – CodesInChaos
7 upvote
  flag
I'm impressed, 70 votes for a wrong answer!!!, as CodesInChaos said for this type of encryption you need a Symmetric key, not an Assymetric. – Otto Kanellis
4 upvote
  flag
It's not a wrong answer, just over-complicating with a huge overhead... use AES / any other Symmetric methods for better results. – Tomer W

EDIT 2013-Oct: Although I've edited this answer over time to address shortcomings, please see jbtule's answer for a more robust, informed solution.

//allinonescript.com/a/10366194/188474

Original Answer:

Here's a working example derived from the "RijndaelManaged Class" documentation and the MCTS Training Kit.

EDIT 2012-April: This answer was edited to pre-pend the IV per jbtule's suggestion and as illustrated here:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged%28v=vs.95%29.aspx

Good luck!

public class Crypto
{

    //While an app specific salt is not the best practice for
    //password based encryption, it's probably safe enough as long as
    //it is truly uncommon. Also too much work to alter this answer otherwise.
    private static byte[] _salt = __To_Do__("Add a app specific salt here");

    /// <summary>
    /// Encrypt the given string using AES.  The string can be decrypted using 
    /// DecryptStringAES().  The sharedSecret parameters must match.
    /// </summary>
    /// <param name="plainText">The text to encrypt.</param>
    /// <param name="sharedSecret">A password used to generate a key for encryption.</param>
    public static string EncryptStringAES(string plainText, string sharedSecret)
    {
        if (string.IsNullOrEmpty(plainText))
            throw new ArgumentNullException("plainText");
        if (string.IsNullOrEmpty(sharedSecret))
            throw new ArgumentNullException("sharedSecret");

        string outStr = null;                       // Encrypted string to return
        RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

            // Create a RijndaelManaged object
            aesAlg = new RijndaelManaged();
            aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);

            // Create a decryptor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                // prepend the IV
                msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
                msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                }
                outStr = Convert.ToBase64String(msEncrypt.ToArray());
            }
        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        // Return the encrypted bytes from the memory stream.
        return outStr;
    }

    /// <summary>
    /// Decrypt the given string.  Assumes the string was encrypted using 
    /// EncryptStringAES(), using an identical sharedSecret.
    /// </summary>
    /// <param name="cipherText">The text to decrypt.</param>
    /// <param name="sharedSecret">A password used to generate a key for decryption.</param>
    public static string DecryptStringAES(string cipherText, string sharedSecret)
    {
        if (string.IsNullOrEmpty(cipherText))
            throw new ArgumentNullException("cipherText");
        if (string.IsNullOrEmpty(sharedSecret))
            throw new ArgumentNullException("sharedSecret");

        // Declare the RijndaelManaged object
        // used to decrypt the data.
        RijndaelManaged aesAlg = null;

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

            // Create the streams used for decryption.                
            byte[] bytes = Convert.FromBase64String(cipherText);
            using (MemoryStream msDecrypt = new MemoryStream(bytes))
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                // Get the initialization vector from the encrypted stream
                aesAlg.IV = ReadByteArray(msDecrypt);
                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        return plaintext;
    }

    private static byte[] ReadByteArray(Stream s)
    {
        byte[] rawLength = new byte[sizeof(int)];
        if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
        {
            throw new SystemException("Stream did not contain properly formatted byte array");
        }

        byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
        if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
        {
            throw new SystemException("Did not read byte array properly");
        }

        return buffer;
    }
}
2 upvote
  flag
To Bret - hi thx for your example. Maybye one think - I had issue with key leng - I did modification with MD5, so if somebody will use your example in the feature pls use this for key normalization(or you can use other hash algoritm: HashAlgorithm hash = new MD5CryptoServiceProvider(); UnicodeEncoding UE = new UnicodeEncoding(); byte[] key = hash.ComputeHash(UE.GetBytes(encrypt_password)); ps:sorry for my english :) slinti – user593912
upvote
  flag
what is the length of the result byte array (as a function of the plainText input length)? Thank you! – nakhli
upvote
  flag
Block size is 16 bytes. The output byte length will be the same size as the input, rounded up to fill the block. e.g., an input string of 120 bytes will result in an output string of 8 blocks, or 128 bytes. See: en.wikipedia.org/wiki/Block_size_%28cryptography%29 – Brett
upvote
  flag
It looks like AES is the newer form of Rijndeal, and according to the MSDN AES should be used instead of Rijndeal: So use AesManaged instead? More info here – John Bubriski
upvote
  flag
I guess AES is not available in 2.0. – John Bubriski
13 upvote
  flag
The above code is not secure, it breaks the most basic rule of semantic security with aes, you should NEVER use the same IV more than once with the same key. This always gives an identical IV every time you use the same key. – jbtule
upvote
  flag
@jbtule - Thanks. Please see my edits above. Deriving the key from the password would satisfy your concerns, I believe. The MCTS text says this about the IV: "Like the Key property, both the encryptor and decryptor must specify the same value. To avoid the overhead of transferring the IV securely between the encryptor and decryptor, you might choose to define the IV in your application statically or to derive this from the Key property." The code above does the latter -- derives the IV from the key. – Brett
upvote
  flag
This is current MCTS text?! Avoiding just a single block of overhead by basically disabling a security feature of AES doesn't seem like something Microsoft such be training people to do. Microsofts docs for aes are correct at least. – jbtule
1 upvote
  flag
This is a good answer of how to use an IV, that MCTS text is irresponsible and nonstandard. – jbtule
1 upvote
  flag
Thanks. I'll edit the answer to pre-pend the IV. – Brett
upvote
  flag
I am encrypting a string for use as a url parameter. The strings that this returns contains slashes and other symbols that mess up my URL, is there anything clever I can do to stop that from happening ? – wotney
upvote
  flag
@wotney: the returned string is base64, which may contain ?'s and /'s. I suggest that you UrlEncode the string: msdn.microsoft.com/en-us/library/… – Brett
upvote
  flag
Yup, simple solution. I was just wondering whether there was a setting in the RijndaelManaged class that could be invoked instead of using UrlEncode. Thanks though Brett ! – wotney
upvote
  flag
@Brett using this method for the data that are going to be serialized and deserialized will cause an error since it can produce hexadecimal characters. how can I encode it to acceptable character set for XML? – Afflatus
upvote
  flag
@Elham It's difficult to respond. I suspect you are trying to write the xml directly and then de-serialize that xml back into an object. Perhaps you can refactor how you're writing your xml? Are you using the XmlSerializer (best approach)? Or perhaps you can simply wrap the base64 output with CDATA?. Surely the XmlSerializer will serialize and de-serialize string data that includes ampersands, etc? – Brett
upvote
  flag
@Brett I do employ XmlSerializer for the task. I had a varbinary element which was causing trouble I changed the type to varchar and the problem got solved. thanks anyway! – Afflatus
7 upvote
  flag
Using a salt in the key-derivation process wouldn't hurt. A constant isn't a good salt, just like a constant isn't a good IV. – CodesInChaos
5 upvote
  flag
Concerning the AES vs. Rijndael confusion: AES is a subset of Rijndael. If you use Rijndael with 128 bit blocks and either 128, 192 or 256 bit keys you're using AES. – CodesInChaos
upvote
  flag
Just tried this and it's working great - However, in ASP.NET when the webserver restarts, the string aren't decrypted correctly, just decrypted yet look like a different encrypted string... Any ideas as to why? – RemarkLima
upvote
  flag
@RemarkLima I'm afraid I don't have any suggestions. The intent of this algorithm was to avoid such problems. – Brett
1 upvote
  flag
@Brett Sorry, found my mistake - Encrypting twice before saving to the database slaps forehead – RemarkLima
upvote
  flag
So the _salt is the key you want to keep safe correct? – Rod
3 upvote
  flag
The salt adds a degree of obfuscation to prevent cracking. Recommend that you read jbtules examples below where the salt is generated. – Brett
upvote
  flag
RijndaelManaged has a method GenerateIV() – Ian Warburton
upvote
  flag
@IanWarburton We're simply referencing the IV property off of RijndaelManaged class. The documentation states that the IV is set to a new random value whenever you instantiate the class. See the remarks section of the documentation: bit.ly/1ObZRzg – Brett
upvote
  flag
Aha... handy. :) – Ian Warburton
upvote
  flag
Isn't it a vulnerability that you transport the IV unencrypted? Doesn't this lose its point if an attacker knows the IV? – Foxman
upvote
  flag
The IV and the key are both required to decrypt. A random IV provides "semantic security" -- prevents anyone watching traffic from discerning patterns. For example, if everyone's password were set to "change me" random IVs would nevertheless result in random cipher text, even if the key were the same. – Brett
1 upvote
  flag
RijndaelManaged is not FIPS 140-2 compliant and might throw exception on DOD systems where FIPS is enabled. – Farukh
upvote
  flag
Could someone please explain me how to use this with an interger? I don't know how to use this and what to set as salt value. How do I save the int encrypted? – J.K. Harthoorn
using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.Security.Cryptography;

namespace Encription
{
    class CryptorEngine
    {
        public static string Encrypt(string ToEncrypt, bool useHasing)
        {
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(ToEncrypt);
            //System.Configuration.AppSettingsReader settingsReader = new     AppSettingsReader();
           string Key = "Bhagwati";
            if (useHasing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(Key));
                hashmd5.Clear();  
            }
            else
            {
                keyArray = UTF8Encoding.UTF8.GetBytes(Key);
            }
            TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();
            tDes.Key = keyArray;
            tDes.Mode = CipherMode.ECB;
            tDes.Padding = PaddingMode.PKCS7;
            ICryptoTransform cTransform = tDes.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0,     toEncryptArray.Length);
            tDes.Clear();
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
        public static string Decrypt(string cypherString, bool useHasing)
        {
            byte[] keyArray;
            byte[] toDecryptArray = Convert.FromBase64String(cypherString);
            //byte[] toEncryptArray = Convert.FromBase64String(cypherString);
            //System.Configuration.AppSettingsReader settingReader = new     AppSettingsReader();
            string key = "Bhagwati";
            if (useHasing)
            {
                MD5CryptoServiceProvider hashmd = new MD5CryptoServiceProvider();
                keyArray = hashmd.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                hashmd.Clear();
            }
            else
            {
                keyArray = UTF8Encoding.UTF8.GetBytes(key);
            }
            TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();
            tDes.Key = keyArray;
            tDes.Mode = CipherMode.ECB;
            tDes.Padding = PaddingMode.PKCS7;
            ICryptoTransform cTransform = tDes.CreateDecryptor();
            try
            {
                byte[] resultArray = cTransform.TransformFinalBlock(toDecryptArray, 0,         toDecryptArray.Length);

                tDes.Clear();
                return UTF8Encoding.UTF8.GetString(resultArray,0,resultArray.Length);
            }
            catch (Exception ex)
            {
                throw ex;
             }
        }
    }
}
14 upvote
  flag
Isn't the ECB cipher mode a big no-no? – John Bubriski
3 upvote
  flag
Yes, ECB is the least secure option. See MS's comments: "Important: This mode is not recommended because it opens the door for multiple security exploits." msdn.microsoft.com/en-us/library/… – Rich

Modern Examples of Symmetric Authenticated Encryption of a string.

The general best practice for symmetric encryption is to use Authenticated Encryption with Associated Data (AEAD), however this isn't a part of the standard .net crypto libraries. So the first example uses AES256 and then HMAC256, a two step Encrypt then MAC, which requires more overhead and more keys.

The second example uses the simpler practice of AES256-GCM using the open source Bouncy Castle (via nuget).

Both examples have a main function that takes secret message string, key(s) and an optional non-secret payload and return and authenticated encrypted string optionally prepended with the non-secret data. Ideally you would use these with 256bit key(s) randomly generated see NewKey().

Both examples also have a helper methods that use a string password to generate the keys. These helper methods are provided as a convenience to match up with other examples, however they are far less secure because the strength of the password is going to be far weaker than a 256 bit key.

Update: Added byte[] overloads, and only the Gist has the full formatting with 4 spaces indent and api docs due to StackOverflow answer limits.


.NET Built-in Encrypt(AES)-Then-MAC(HMAC) [Gist]

/*
 * This work (Modern Encryption of a String C#, by James Tuley), 
 * identified by James Tuley, is free of known copyright restrictions.
 * https://gist.github.com/4336842
 * http://creativecommons.org/publicdomain/mark/1.0/ 
 */

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Encryption
{
  public static class AESThenHMAC
  {
    private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();

    //Preconfigured Encryption Parameters
    public static readonly int BlockBitSize = 128;
    public static readonly int KeyBitSize = 256;

    //Preconfigured Password Key Derivation Parameters
    public static readonly int SaltBitSize = 64;
    public static readonly int Iterations = 10000;
    public static readonly int MinPasswordLength = 12;

    /// <summary>
    /// Helper that generates a random key on each call.
    /// </summary>
    /// <returns></returns>
    public static byte[] NewKey()
    {
      var key = new byte[KeyBitSize / 8];
      Random.GetBytes(key);
      return key;
    }

    /// <summary>
    /// Simple Encryption (AES) then Authentication (HMAC) for a UTF8 Message.
    /// </summary>
    /// <param name="secretMessage">The secret message.</param>
    /// <param name="cryptKey">The crypt key.</param>
    /// <param name="authKey">The auth key.</param>
    /// <param name="nonSecretPayload">(Optional) Non-Secret Payload.</param>
    /// <returns>
    /// Encrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">Secret Message Required!;secretMessage</exception>
    /// <remarks>
    /// Adds overhead of (Optional-Payload + BlockSize(16) + Message-Padded-To-Blocksize +  HMac-Tag(32)) * 1.33 Base64
    /// </remarks>
    public static string SimpleEncrypt(string secretMessage, byte[] cryptKey, byte[] authKey,
                       byte[] nonSecretPayload = null)
    {
      if (string.IsNullOrEmpty(secretMessage))
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var plainText = Encoding.UTF8.GetBytes(secretMessage);
      var cipherText = SimpleEncrypt(plainText, cryptKey, authKey, nonSecretPayload);
      return Convert.ToBase64String(cipherText);
    }

    /// <summary>
    /// Simple Authentication (HMAC) then Decryption (AES) for a secrets UTF8 Message.
    /// </summary>
    /// <param name="encryptedMessage">The encrypted message.</param>
    /// <param name="cryptKey">The crypt key.</param>
    /// <param name="authKey">The auth key.</param>
    /// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
    /// <returns>
    /// Decrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
    public static string SimpleDecrypt(string encryptedMessage, byte[] cryptKey, byte[] authKey,
                       int nonSecretPayloadLength = 0)
    {
      if (string.IsNullOrWhiteSpace(encryptedMessage))
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var cipherText = Convert.FromBase64String(encryptedMessage);
      var plainText = SimpleDecrypt(cipherText, cryptKey, authKey, nonSecretPayloadLength);
      return plainText == null ? null : Encoding.UTF8.GetString(plainText);
    }

    /// <summary>
    /// Simple Encryption (AES) then Authentication (HMAC) of a UTF8 message
    /// using Keys derived from a Password (PBKDF2).
    /// </summary>
    /// <param name="secretMessage">The secret message.</param>
    /// <param name="password">The password.</param>
    /// <param name="nonSecretPayload">The non secret payload.</param>
    /// <returns>
    /// Encrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">password</exception>
    /// <remarks>
    /// Significantly less secure than using random binary keys.
    /// Adds additional non secret payload for key generation parameters.
    /// </remarks>
    public static string SimpleEncryptWithPassword(string secretMessage, string password,
                             byte[] nonSecretPayload = null)
    {
      if (string.IsNullOrEmpty(secretMessage))
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var plainText = Encoding.UTF8.GetBytes(secretMessage);
      var cipherText = SimpleEncryptWithPassword(plainText, password, nonSecretPayload);
      return Convert.ToBase64String(cipherText);
    }

    /// <summary>
    /// Simple Authentication (HMAC) and then Descryption (AES) of a UTF8 Message
    /// using keys derived from a password (PBKDF2). 
    /// </summary>
    /// <param name="encryptedMessage">The encrypted message.</param>
    /// <param name="password">The password.</param>
    /// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
    /// <returns>
    /// Decrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
    /// <remarks>
    /// Significantly less secure than using random binary keys.
    /// </remarks>
    public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
                             int nonSecretPayloadLength = 0)
    {
      if (string.IsNullOrWhiteSpace(encryptedMessage))
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var cipherText = Convert.FromBase64String(encryptedMessage);
      var plainText = SimpleDecryptWithPassword(cipherText, password, nonSecretPayloadLength);
      return plainText == null ? null : Encoding.UTF8.GetString(plainText);
    }

    public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
    {
      //User Error Checks
      if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");

      if (authKey == null || authKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");

      if (secretMessage == null || secretMessage.Length < 1)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      //non-secret payload optional
      nonSecretPayload = nonSecretPayload ?? new byte[] { };

      byte[] cipherText;
      byte[] iv;

      using (var aes = new AesManaged
      {
        KeySize = KeyBitSize,
        BlockSize = BlockBitSize,
        Mode = CipherMode.CBC,
        Padding = PaddingMode.PKCS7
      })
      {

        //Use random IV
        aes.GenerateIV();
        iv = aes.IV;

        using (var encrypter = aes.CreateEncryptor(cryptKey, iv))
        using (var cipherStream = new MemoryStream())
        {
          using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
          using (var binaryWriter = new BinaryWriter(cryptoStream))
          {
            //Encrypt Data
            binaryWriter.Write(secretMessage);
          }

          cipherText = cipherStream.ToArray();
        }

      }

      //Assemble encrypted message and add authentication
      using (var hmac = new HMACSHA256(authKey))
      using (var encryptedStream = new MemoryStream())
      {
        using (var binaryWriter = new BinaryWriter(encryptedStream))
        {
          //Prepend non-secret payload if any
          binaryWriter.Write(nonSecretPayload);
          //Prepend IV
          binaryWriter.Write(iv);
          //Write Ciphertext
          binaryWriter.Write(cipherText);
          binaryWriter.Flush();

          //Authenticate all data
          var tag = hmac.ComputeHash(encryptedStream.ToArray());
          //Postpend tag
          binaryWriter.Write(tag);
        }
        return encryptedStream.ToArray();
      }

    }

    public static byte[] SimpleDecrypt(byte[] encryptedMessage, byte[] cryptKey, byte[] authKey, int nonSecretPayloadLength = 0)
    {

      //Basic Usage Error Checks
      if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("CryptKey needs to be {0} bit!", KeyBitSize), "cryptKey");

      if (authKey == null || authKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("AuthKey needs to be {0} bit!", KeyBitSize), "authKey");

      if (encryptedMessage == null || encryptedMessage.Length == 0)
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      using (var hmac = new HMACSHA256(authKey))
      {
        var sentTag = new byte[hmac.HashSize / 8];
        //Calculate Tag
        var calcTag = hmac.ComputeHash(encryptedMessage, 0, encryptedMessage.Length - sentTag.Length);
        var ivLength = (BlockBitSize / 8);

        //if message length is to small just return null
        if (encryptedMessage.Length < sentTag.Length + nonSecretPayloadLength + ivLength)
          return null;

        //Grab Sent Tag
        Array.Copy(encryptedMessage, encryptedMessage.Length - sentTag.Length, sentTag, 0, sentTag.Length);

        //Compare Tag with constant time comparison
        var compare = 0;
        for (var i = 0; i < sentTag.Length; i++)
          compare |= sentTag[i] ^ calcTag[i]; 

        //if message doesn't authenticate return null
        if (compare != 0)
          return null;

        using (var aes = new AesManaged
        {
          KeySize = KeyBitSize,
          BlockSize = BlockBitSize,
          Mode = CipherMode.CBC,
          Padding = PaddingMode.PKCS7
        })
        {

          //Grab IV from message
          var iv = new byte[ivLength];
          Array.Copy(encryptedMessage, nonSecretPayloadLength, iv, 0, iv.Length);

          using (var decrypter = aes.CreateDecryptor(cryptKey, iv))
          using (var plainTextStream = new MemoryStream())
          {
            using (var decrypterStream = new CryptoStream(plainTextStream, decrypter, CryptoStreamMode.Write))
            using (var binaryWriter = new BinaryWriter(decrypterStream))
            {
              //Decrypt Cipher Text from Message
              binaryWriter.Write(
                encryptedMessage,
                nonSecretPayloadLength + iv.Length,
                encryptedMessage.Length - nonSecretPayloadLength - iv.Length - sentTag.Length
              );
            }
            //Return Plain Text
            return plainTextStream.ToArray();
          }
        }
      }
    }

    public static byte[] SimpleEncryptWithPassword(byte[] secretMessage, string password, byte[] nonSecretPayload = null)
    {
      nonSecretPayload = nonSecretPayload ?? new byte[] {};

      //User Error Checks
      if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
        throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");

      if (secretMessage == null || secretMessage.Length ==0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var payload = new byte[((SaltBitSize / 8) * 2) + nonSecretPayload.Length];

      Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
      int payloadIndex = nonSecretPayload.Length;

      byte[] cryptKey;
      byte[] authKey;
      //Use Random Salt to prevent pre-generated weak password attacks.
      using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
      {
        var salt = generator.Salt;

        //Generate Keys
        cryptKey = generator.GetBytes(KeyBitSize / 8);

        //Create Non Secret Payload
        Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
        payloadIndex += salt.Length;
      }

      //Deriving separate key, might be less efficient than using HKDF, 
      //but now compatible with RNEncryptor which had a very similar wireformat and requires less code than HKDF.
      using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize / 8, Iterations))
      {
        var salt = generator.Salt;

        //Generate Keys
        authKey = generator.GetBytes(KeyBitSize / 8);

        //Create Rest of Non Secret Payload
        Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
      }

      return SimpleEncrypt(secretMessage, cryptKey, authKey, payload);
    }

    public static byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, string password, int nonSecretPayloadLength = 0)
    {
      //User Error Checks
      if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
        throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");

      if (encryptedMessage == null || encryptedMessage.Length == 0)
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var cryptSalt = new byte[SaltBitSize / 8];
      var authSalt = new byte[SaltBitSize / 8];

      //Grab Salt from Non-Secret Payload
      Array.Copy(encryptedMessage, nonSecretPayloadLength, cryptSalt, 0, cryptSalt.Length);
      Array.Copy(encryptedMessage, nonSecretPayloadLength + cryptSalt.Length, authSalt, 0, authSalt.Length);

      byte[] cryptKey;
      byte[] authKey;

      //Generate crypt key
      using (var generator = new Rfc2898DeriveBytes(password, cryptSalt, Iterations))
      {
        cryptKey = generator.GetBytes(KeyBitSize / 8);
      }
      //Generate auth key
      using (var generator = new Rfc2898DeriveBytes(password, authSalt, Iterations))
      {
        authKey = generator.GetBytes(KeyBitSize / 8);
      }

      return SimpleDecrypt(encryptedMessage, cryptKey, authKey, cryptSalt.Length + authSalt.Length + nonSecretPayloadLength);
    }
  }
}

Bouncy Castle AES-GCM [Gist]

/*
 * This work (Modern Encryption of a String C#, by James Tuley), 
 * identified by James Tuley, is free of known copyright restrictions.
 * https://gist.github.com/4336842
 * http://creativecommons.org/publicdomain/mark/1.0/ 
 */

using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace Encryption
{

  public static class AESGCM
  {
    private static readonly SecureRandom Random = new SecureRandom();

    //Preconfigured Encryption Parameters
    public static readonly int NonceBitSize = 128;
    public static readonly int MacBitSize = 128;
    public static readonly int KeyBitSize = 256;

    //Preconfigured Password Key Derivation Parameters
    public static readonly int SaltBitSize = 128;
    public static readonly int Iterations = 10000;
    public static readonly int MinPasswordLength = 12;


    /// <summary>
    /// Helper that generates a random new key on each call.
    /// </summary>
    /// <returns></returns>
    public static byte[] NewKey()
    {
      var key = new byte[KeyBitSize / 8];
      Random.NextBytes(key);
      return key;
    }

    /// <summary>
    /// Simple Encryption And Authentication (AES-GCM) of a UTF8 string.
    /// </summary>
    /// <param name="secretMessage">The secret message.</param>
    /// <param name="key">The key.</param>
    /// <param name="nonSecretPayload">Optional non-secret payload.</param>
    /// <returns>
    /// Encrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">Secret Message Required!;secretMessage</exception>
    /// <remarks>
    /// Adds overhead of (Optional-Payload + BlockSize(16) + Message +  HMac-Tag(16)) * 1.33 Base64
    /// </remarks>
    public static string SimpleEncrypt(string secretMessage, byte[] key, byte[] nonSecretPayload = null)
    {
      if (string.IsNullOrEmpty(secretMessage))
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var plainText = Encoding.UTF8.GetBytes(secretMessage);
      var cipherText = SimpleEncrypt(plainText, key, nonSecretPayload);
      return Convert.ToBase64String(cipherText);
    }


    /// <summary>
    /// Simple Decryption & Authentication (AES-GCM) of a UTF8 Message
    /// </summary>
    /// <param name="encryptedMessage">The encrypted message.</param>
    /// <param name="key">The key.</param>
    /// <param name="nonSecretPayloadLength">Length of the optional non-secret payload.</param>
    /// <returns>Decrypted Message</returns>
    public static string SimpleDecrypt(string encryptedMessage, byte[] key, int nonSecretPayloadLength = 0)
    {
      if (string.IsNullOrEmpty(encryptedMessage))
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var cipherText = Convert.FromBase64String(encryptedMessage);
      var plainText = SimpleDecrypt(cipherText, key, nonSecretPayloadLength);
      return plainText == null ? null : Encoding.UTF8.GetString(plainText);
    }

    /// <summary>
    /// Simple Encryption And Authentication (AES-GCM) of a UTF8 String
    /// using key derived from a password (PBKDF2).
    /// </summary>
    /// <param name="secretMessage">The secret message.</param>
    /// <param name="password">The password.</param>
    /// <param name="nonSecretPayload">The non secret payload.</param>
    /// <returns>
    /// Encrypted Message
    /// </returns>
    /// <remarks>
    /// Significantly less secure than using random binary keys.
    /// Adds additional non secret payload for key generation parameters.
    /// </remarks>
    public static string SimpleEncryptWithPassword(string secretMessage, string password,
                             byte[] nonSecretPayload = null)
    {
      if (string.IsNullOrEmpty(secretMessage))
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var plainText = Encoding.UTF8.GetBytes(secretMessage);
      var cipherText = SimpleEncryptWithPassword(plainText, password, nonSecretPayload);
      return Convert.ToBase64String(cipherText);
    }


    /// <summary>
    /// Simple Decryption and Authentication (AES-GCM) of a UTF8 message
    /// using a key derived from a password (PBKDF2)
    /// </summary>
    /// <param name="encryptedMessage">The encrypted message.</param>
    /// <param name="password">The password.</param>
    /// <param name="nonSecretPayloadLength">Length of the non secret payload.</param>
    /// <returns>
    /// Decrypted Message
    /// </returns>
    /// <exception cref="System.ArgumentException">Encrypted Message Required!;encryptedMessage</exception>
    /// <remarks>
    /// Significantly less secure than using random binary keys.
    /// </remarks>
    public static string SimpleDecryptWithPassword(string encryptedMessage, string password,
                             int nonSecretPayloadLength = 0)
    {
      if (string.IsNullOrWhiteSpace(encryptedMessage))
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var cipherText = Convert.FromBase64String(encryptedMessage);
      var plainText = SimpleDecryptWithPassword(cipherText, password, nonSecretPayloadLength);
      return plainText == null ? null : Encoding.UTF8.GetString(plainText);
    }

    public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key, byte[] nonSecretPayload = null)
    {
      //User Error Checks
      if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");

      if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      //Non-secret Payload Optional
      nonSecretPayload = nonSecretPayload ?? new byte[] { };

      //Using random nonce large enough not to repeat
      var nonce = new byte[NonceBitSize / 8];
      Random.NextBytes(nonce, 0, nonce.Length);

      var cipher = new GcmBlockCipher(new AesFastEngine());
      var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
      cipher.Init(true, parameters);

      //Generate Cipher Text With Auth Tag
      var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
      var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
      cipher.DoFinal(cipherText, len);

      //Assemble Message
      using (var combinedStream = new MemoryStream())
      {
        using (var binaryWriter = new BinaryWriter(combinedStream))
        {
          //Prepend Authenticated Payload
          binaryWriter.Write(nonSecretPayload);
          //Prepend Nonce
          binaryWriter.Write(nonce);
          //Write Cipher Text
          binaryWriter.Write(cipherText);
        }
        return combinedStream.ToArray();
      }
    }

    public static byte[] SimpleDecrypt(byte[] encryptedMessage, byte[] key, int nonSecretPayloadLength = 0)
    {
      //User Error Checks
      if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");

      if (encryptedMessage == null || encryptedMessage.Length == 0)
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      using (var cipherStream = new MemoryStream(encryptedMessage))
      using (var cipherReader = new BinaryReader(cipherStream))
      {
        //Grab Payload
        var nonSecretPayload = cipherReader.ReadBytes(nonSecretPayloadLength);

        //Grab Nonce
        var nonce = cipherReader.ReadBytes(NonceBitSize / 8);

        var cipher = new GcmBlockCipher(new AesFastEngine());
        var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, nonSecretPayload);
        cipher.Init(false, parameters);

        //Decrypt Cipher Text
        var cipherText = cipherReader.ReadBytes(encryptedMessage.Length - nonSecretPayloadLength - nonce.Length);
        var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];  

        try
        {
          var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
          cipher.DoFinal(plainText, len);

        }
        catch (InvalidCipherTextException)
        {
          //Return null if it doesn't authenticate
          return null;
        }

        return plainText;
      }

    }

    public static byte[] SimpleEncryptWithPassword(byte[] secretMessage, string password, byte[] nonSecretPayload = null)
    {
      nonSecretPayload = nonSecretPayload ?? new byte[] {};

      //User Error Checks
      if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
        throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");

      if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

      var generator = new Pkcs5S2ParametersGenerator();

      //Use Random Salt to minimize pre-generated weak password attacks.
      var salt = new byte[SaltBitSize / 8];
      Random.NextBytes(salt);

      generator.Init(
        PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
        salt,
        Iterations);

      //Generate Key
      var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);

      //Create Full Non Secret Payload
      var payload = new byte[salt.Length + nonSecretPayload.Length];
      Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
      Array.Copy(salt,0, payload,nonSecretPayload.Length, salt.Length);

      return SimpleEncrypt(secretMessage, key.GetKey(), payload);
    }

    public static byte[] SimpleDecryptWithPassword(byte[] encryptedMessage, string password, int nonSecretPayloadLength = 0)
    {
      //User Error Checks
      if (string.IsNullOrWhiteSpace(password) || password.Length < MinPasswordLength)
        throw new ArgumentException(String.Format("Must have a password of at least {0} characters!", MinPasswordLength), "password");

      if (encryptedMessage == null || encryptedMessage.Length == 0)
        throw new ArgumentException("Encrypted Message Required!", "encryptedMessage");

      var generator = new Pkcs5S2ParametersGenerator();

      //Grab Salt from Payload
      var salt = new byte[SaltBitSize / 8];
      Array.Copy(encryptedMessage, nonSecretPayloadLength, salt, 0, salt.Length);

      generator.Init(
        PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()),
        salt,
        Iterations);

      //Generate Key
      var key = (KeyParameter)generator.GenerateDerivedMacParameters(KeyBitSize);

      return SimpleDecrypt(encryptedMessage, key.GetKey(), salt.Length + nonSecretPayloadLength);
    }
  }
}
6 upvote
  flag
Have these samples posted on code review too. – jbtule
1 upvote
  flag
For the first code example, and the decryption method... There are two things I do not understand very well and hope you can clarify. In what circumstances would the first if statement return? And the for loop that checks that each element in bot arrays match: I've never seen your logic before "auth = auth && sentTag[i] == calcTag[i];" is there anything special about it or could I yield false as soon as I detect one byte does not correspond? Sorry for being vague, there's not a lot of room to comment and format code here! – Caster Troy
3 upvote
  flag
That's a good question, these are using Authenticated Encryption examples, in addition to encrypting they have a MAC to validate that the ciphertext hasn't been modifed by someone else, this is primarily to thwart chosen-ciphertext attacks. So when decrypting it calculates the MAC to check against the appended one to authenticate it, if it authenticates it decrypts and if it doesn't it returns null. – jbtule
3 upvote
  flag
The array check on the MAC does every index, because a timing attack can be used to calculate a new MAC on a fake ciphertext if it returns the first byte that doesn't match. – jbtule
3 upvote
  flag
Superb, thanks! Would you recommend Practical Cryptography by Niels Ferguson? Everybody seems to recommend it for a primer on cryptography. It's all very well understanding how to implement the bare bones encryption but it's extra security measures like you describe that interest me the most. One last question if you don't mind; You use AesManaged which I understand to be not certified. Should I / is it okay for me to use AesCryptoServiceProvider? I feel more comfortable using that class at the moment. – Caster Troy
5 upvote
  flag
That is a good book and relatively recent. What I would recommend even more is the free online course Cryptography I by Dan Boneh. Really good videos, really good quizes, and really good machine problems too that provide a good practical base for the usage of cryptography. You should use what you are most comfortable with in regards to the AesCryptoServiceProvider. – jbtule
1 upvote
  flag
In AESThenHMAC.SimpleEncryptWithPassword() what is the non-secret payload for? – Jan
1 upvote
  flag
It's anything that you want to send with your data (not encrypted) that you want to verify that it hasn't been altered from something like a man in the middle or fuzzing from an attacker. It's non-encrypted signed data. – jbtule
upvote
  flag
SimpleEncrypt example for BouncyCastle is giving me a compilation error on Random.NextBytes(nonce, 0, nonce.Length); saying it only takes one argument. – Kyle
upvote
  flag
Well it's not true, and doesn't give me any compiler warnings. github.com/bcgit/bc-csharp/blob/master/crypto/src/security/… Did you make any edits or exclude anything when copy and pasting? – jbtule
upvote
  flag
Thanks for this superb answer. I have a general question about this encryption scenario -- appending the HMAC enables a holder of the auth key to verify that the first section (non-secret portion + AES IV + encrypted message) was signed by another party who holds the same auth key. In this case though, if you have two parties communicating (and ignoring the plain text portion for a second) isn't the mere fact of their ability to decrypt the AES encrypted section an equally strong guarantee? What more does the HMAC buy you (or is it solely to authenticate the non-encrypted part)? – Benji XVI
upvote
  flag
@BenjiXVI no it is not a strong guarentee, see above comment about authenticated encryption and chosen-ciphertext attacks. – jbtule
3 upvote
  flag
I apologize for the stupidity of the following questions. 1) How or what is the recommended best practice for storing the crypt and auth keys for AESThenHMAC solution? 2) Is it a bad idea to use the same crypt and auth keys over the lifetime of the application? I am considering using this code for encrypting sensitive data prior to storing it in my database. – Parth Shah
1 upvote
  flag
@ParthShah It's not a stupid question, and it's actually an often overlooked one. Storing keys is HARD-very. There isn't an ideal way without specialized hardware, so just do the best you can keeping it as separate from your ciphertext as possible (in this case don't store the keys (or keys to decrypt the keys) in the same database as the ciphertext at the very least). Rotating keys over the lifetime of the app involves more than the above code, but is available for dotnet in library form: github.com/jbtule/keyczar-dotnet – jbtule
upvote
  flag
@jbtule : The AESThenHMAC.cs Gist's SimpleDecrypt & SimpleDecryptWithPassword attempt to return "plaintext" all lower case instead of camel case as declared. – olingern
upvote
  flag
@jbtule I'm trying to adapt the code in public static byte[] SimpleDecrypt(byte[] encryptedMessage, byte[] key, int nonSecretPayloadLength = 0) to my use-case where there is no noonce and no authentication. With the changes (i.e. NonceBitSize = 0; MacBitSize = 0)) I get an AccessViolationException on the line cipher.ProcessBytes inside the try-catch... could you kindly suggest where am I going wrong? – dotnetguy
upvote
  flag
@dotnetguy this is a practical example of how to do symmetric encryption appropriately, what you describe is not appropriate. – jbtule
upvote
  flag
@jbtule I may not have worded my question correctly 'cause I'm a newbie in this area, but this is what I was looking for: //allinonescript.com/a/31419559/190476 – dotnetguy
4 upvote
  flag
A nicely explained usage section would be extremely helpful. – Rocklan
upvote
  flag
RandomNumberGenerator is not thread-safe; consider RNGCryptoServiceProvider instead. And second the need for a usage section! – TrueWill
2 upvote
  flag
@TrueWill RandomNumberGenerator is an abstract class, System.Security.Cryptography,RandomNumberGenerate.Create() actually returns RNGCryptoServiceProvider -//allinonescript.com/a/12329913/637783. I think about a usage example. – jbtule
upvote
  flag
Note that, with Iterations = 10000 and a string password, this may be unacceptably slow for certain scenarios. – TrueWill
2 upvote
  flag
@TrueWill It's true, it's 10000 because it's supposed to be slow. Better to not use password generated key's when performance is important. And password derived keys are not ideal for most scenarios, i added them as an option in this example because most SO encrypt examples use a password :'( so I wanted to provide the best practice securitywise to deal with them. – jbtule
upvote
  flag
Is there a version of this that works with files instead of strings? – Ian Warburton
1 upvote
  flag
@IanWarburton nah this is example code, while you could convert a file into a byte array and then use this as is, it's not ideal, you'd have to modify a little to efficiently encrypt a file. At the point you are trying to encrypt files use github.com/jbtule/keyczar-dotnet as it handles other concerns like keyrotation etc. – jbtule
upvote
  flag
@IanWarburton Data that you want to keep with your cipher text that you need authenticated because it's important to know if an attacker modified. Anything you need to look at before decryption, In the password examples you can see I put the salt in the nonSecretPayload. – jbtule
upvote
  flag
@jbtule Why do you use one key for encryption and another for hashing? Why not use one key for both? – Ian Warburton
upvote
  flag
Not strictly designed to be used that way, I don't know of any attacks, but it's better to go with the best practices, if you can't manage another 16 bytes of key data use AES-GCM. – jbtule
upvote
  flag
If I am storing the encrypted text in a database, will I also need to store the key in the database to know what the key is to decrypt the encrypted data? – dub stylee
upvote
  flag
Key handling is a bit out of scope and a more difficult problem. Generally the best thing to do is store the key as far away from the data as possible (so not in the database). Going with a library that has the infrastructure to handle keys including rotating keys would be a better fit for you @dubstylee such as keyczar jay.tuley.name/keyczar-dotnet – jbtule
upvote
  flag
Keyczar looks like a great solution. One question: how about decrypting the same data on multiple devices? Is it possible to share the keyset among different devices? By share the keyset, I mean keep them synchronized, not just import/export. – dub stylee
upvote
  flag
Yes, a keyset is just data, but very sensitve data, so you need to figure how to distributed it securely (public/private key cryptography). That is more of an architecture question and out side the scope of this set of comments. – jbtule
upvote
  flag
This might be a stupid question, but the salt, is that stored with the encrypted ciphertext? I thought I would need to store them separately in my database, but if I'm reading the code properly, I don't need to do this using this code sample? Is that right? – Junto
upvote
  flag
You are correct, if you are using a string password, the salt is randomly generated and added to the authenticated payload of the ciphertext. Design wise it ideal, because it keeps people from incorrectly using the function by reusing salts per application etc. – jbtule
upvote
  flag
@jbtule you might be interested in the question I posted concerning your code: //allinonescript.com/questions/36503620/… (with bounty). – Junto
upvote
  flag
@Junto not my code, you used nerdybeardo code, but I posted my thoughts anyway. – jbtule
1 upvote
  flag
Which of the two solutions would you recommend? Since you refer to your second solution as a simpler practice, do we assume that means it's technically inferior but faster then the first solution? – rdans
2 upvote
  flag
@rdans it's not technically inferior, quite the opposite, it's easier to use by having authentication and encryption in one step. The second solution's down side is that you need an extra dependency, which is the only reason I provided the first solution. – jbtule
upvote
  flag
I got it working. What is the difference between "SimdpleDecrypt" and "SimpleDecryptWithPassword"? – STORM
upvote
  flag
@STORM using an actually randomized key is way more secure than a password based key. – jbtule
upvote
  flag
Is there a particular reason the salt byte size is derived by dividing by 8? var salt = new byte[SaltBitSize / 8]; – kristian mo
upvote
  flag
@kristianmo How many bits in a byte? – jbtule
1 upvote
  flag
This is great, and your answering of questions is too. There's a ton of subtlety and difficulty in proper encryption, and it's little wonder that it's so often screwed up. – Mark Sowul
upvote
  flag
@jbtule Thank you for these Examples, so is it secure to reuse the same cryptKey and authKey for multiple (many?) Messages? Is it because of the random IV? I'm asking, because the Generation of these Keys is (supposed to be) expensive, so at least cacheing them for the runtime of the current Process would be a huge boost. – Spoc

I want to give you my contribute, with my code for AES Rfc2898DeriveBytes (here the documentation) algorhytm, written in C# (.NET framework 4) and fully working also for limited platforms, as .NET Compact Framework for Windows Phone 7.0+ (not all platforms support every criptographic method of the .NET framework!).

I hope this can help anyone!

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class Crypto
{
    private static readonly byte[] IVa = new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x11, 0x12, 0x13, 0x14, 0x0e, 0x16, 0x17 };


    public static string Encrypt(this string text, string salt)
    {
        try
        {
            using (Aes aes = new AesManaged())
            {
                Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
                aes.Key = deriveBytes.GetBytes(128 / 8);
                aes.IV = aes.Key;
                using (MemoryStream encryptionStream = new MemoryStream())
                {
                    using (CryptoStream encrypt = new CryptoStream(encryptionStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        byte[] cleanText = Encoding.UTF8.GetBytes(text);
                        encrypt.Write(cleanText, 0, cleanText.Length);
                        encrypt.FlushFinalBlock();
                    }

                    byte[] encryptedData = encryptionStream.ToArray();
                    string encryptedText = Convert.ToBase64String(encryptedData);


                    return encryptedText;
                }
            }
        }
        catch
        {
            return String.Empty;
        }
    }

    public static string Decrypt(this string text, string salt)
    {
        try
        {
            using (Aes aes = new AesManaged())
            {
                Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(IVa, 0, IVa.Length), Encoding.UTF8.GetBytes(salt));
                aes.Key = deriveBytes.GetBytes(128 / 8);
                aes.IV = aes.Key;

                using (MemoryStream decryptionStream = new MemoryStream())
                {
                    using (CryptoStream decrypt = new CryptoStream(decryptionStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        byte[] encryptedData = Convert.FromBase64String(text);


                        decrypt.Write(encryptedData, 0, encryptedData.Length);
                        decrypt.Flush();
                    }

                    byte[] decryptedData = decryptionStream.ToArray();
                    string decryptedText = Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);


                    return decryptedText;
                }
            }
        }
        catch
        {
            return String.Empty;
        }
        }
    }
}
8 upvote
  flag
1) Why are you using a variable called IVa which is no IV, but a password? 2) Why are you setting IV=Key? You need a new random IV for each encryption. 3) Lack of MAC enables padding oracle attacks – CodesInChaos

BouncyCastle is a great Crypto library for .NET, it's available as a Nuget package for install into your projects. I like it a lot more than what's currently available in the System.Security.Cryptography library. It gives you a lot more options in terms of available algorithms, and provides more modes for those algorithms.

This is an example of an implementation of TwoFish, which was written by Bruce Schneier (hero to all us paranoid people out there). It's a symmetric algorithm like the Rijndael (aka AES). It was one of the three finalists for the AES standard and sibling to another famous algorithm written by Bruce Schneier called BlowFish.

First thing with bouncycastle is to create an encryptor class, this will make it easier to implement other block ciphers within the library. The following encryptor class takes in a generic argument T where T implements IBlockCipher and has a default constructor.

UPDATE: Due to popular demand I have decided to implement generating a random IV as well as include an HMAC into this class. Although from a style perspective this goes against the SOLID principle of single responsibility, because of the nature of what this class does I reniged. This class will now take two generic parameters, one for the cipher and one for the digest. It automatically generates the IV using RNGCryptoServiceProvider to provide good RNG entropy, and allows you to use whatever digest algorithm you want from BouncyCastle to generate the MAC.

using System;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;

public sealed class Encryptor<TBlockCipher, TDigest>
    where TBlockCipher : IBlockCipher, new()
    where TDigest : IDigest, new()
{
    private Encoding encoding;

    private IBlockCipher blockCipher;

    private BufferedBlockCipher cipher;

    private HMac mac;

    private byte[] key;

    public Encryptor(Encoding encoding, byte[] key, byte[] macKey)
    {
        this.encoding = encoding;
        this.key = key;
        this.Init(key, macKey, new Pkcs7Padding());
    }

    public Encryptor(Encoding encoding, byte[] key, byte[] macKey, IBlockCipherPadding padding)
    {
        this.encoding = encoding;
        this.key = key;
        this.Init(key, macKey, padding);
    }

    private void Init(byte[] key, byte[] macKey, IBlockCipherPadding padding)
    {
        this.blockCipher = new CbcBlockCipher(new TBlockCipher());
        this.cipher = new PaddedBufferedBlockCipher(this.blockCipher, padding);
        this.mac = new HMac(new TDigest());
        this.mac.Init(new KeyParameter(macKey));
    }

    public string Encrypt(string plain)
    {
        return Convert.ToBase64String(EncryptBytes(plain));
    }

    public byte[] EncryptBytes(string plain)
    {
        byte[] input = this.encoding.GetBytes(plain);

        var iv = this.GenerateIV();

        var cipher = this.BouncyCastleCrypto(true, input, new ParametersWithIV(new KeyParameter(key), iv));
        byte[] message = CombineArrays(iv, cipher);

        this.mac.Reset();
        this.mac.BlockUpdate(message, 0, message.Length);
        byte[] digest = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
        this.mac.DoFinal(digest, 0);

        var result = CombineArrays(digest, message);
        return result;
    }

    public byte[] DecryptBytes(byte[] bytes)
    {
        // split the digest into component parts
        var digest = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
        var message = new byte[bytes.Length - digest.Length];
        var iv = new byte[this.blockCipher.GetBlockSize()];
        var cipher = new byte[message.Length - iv.Length];

        Buffer.BlockCopy(bytes, 0, digest, 0, digest.Length);
        Buffer.BlockCopy(bytes, digest.Length, message, 0, message.Length);
        if (!IsValidHMac(digest, message))
        {
            throw new CryptoException();
        }

        Buffer.BlockCopy(message, 0, iv, 0, iv.Length);
        Buffer.BlockCopy(message, iv.Length, cipher, 0, cipher.Length);

        byte[] result = this.BouncyCastleCrypto(false, cipher, new ParametersWithIV(new KeyParameter(key), iv));
        return result;
    }

    public string Decrypt(byte[] bytes)
    {
        return this.encoding.GetString(DecryptBytes(bytes));
    }

    public string Decrypt(string cipher)
    {
        return this.Decrypt(Convert.FromBase64String(cipher));
    }

    private bool IsValidHMac(byte[] digest, byte[] message)
    {
        this.mac.Reset();
        this.mac.BlockUpdate(message, 0, message.Length);
        byte[] computed = new byte[this.mac.GetUnderlyingDigest().GetDigestSize()];
        this.mac.DoFinal(computed, 0);

        return AreEqual(digest,computed);
    }

    private static bool AreEqual(byte [] digest, byte[] computed)
    {
        if(digest.Length != computed.Length)
        {
            return false;
        }

        int result = 0;
        for (int i = 0; i < digest.Length; i++)
        {
            // compute equality of all bytes before returning.
            //   helps prevent timing attacks: 
            //   https://codahale.com/a-lesson-in-timing-attacks/
            result |= digest[i] ^ computed[i];
        }

        return result == 0;
    }

    private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, ICipherParameters parameters)
    {
        try
        {
            cipher.Init(forEncrypt, parameters);

            return this.cipher.DoFinal(input);
        }
        catch (CryptoException)
        {
            throw;
        }
    }

    private byte[] GenerateIV()
    {
        using (var provider = new RNGCryptoServiceProvider())
        {
            // 1st block
            byte[] result = new byte[this.blockCipher.GetBlockSize()];
            provider.GetBytes(result);

            return result;
        }
    }

    private static byte[] CombineArrays(byte[] source1, byte[] source2)
    {
        byte[] result = new byte[source1.Length + source2.Length];
        Buffer.BlockCopy(source1, 0, result, 0, source1.Length);
        Buffer.BlockCopy(source2, 0, result, source1.Length, source2.Length);

        return result;
    }
}

Next just call the encrypt and decrypt methods on the new class, here's the example using twofish:

var encrypt = new Encryptor<TwofishEngine, Sha1Digest>(Encoding.UTF8, key, hmacKey);

string cipher = encrypt.Encrypt("TEST");   
string plainText = encrypt.Decrypt(cipher);

It's just as easy to substitute another block cipher like TripleDES:

var des = new Encryptor<DesEdeEngine, Sha1Digest>(Encoding.UTF8, key, hmacKey);

string cipher = des.Encrypt("TEST");
string plainText = des.Decrypt(cipher);

Finally if you want to use AES with SHA256 HMAC you can do the following:

var aes = new Encryptor<AesEngine, Sha256Digest>(Encoding.UTF8, key, hmacKey);

cipher = aes.Encrypt("TEST");
plainText = aes.Decrypt(cipher);

The hardest part about encryption actually deals with the keys and not the algorithms. You'll have to think about where you store your keys, and if you have to, how you exchange them. These algorithms have all withstood the test of time, and are extremely hard to break. Someone who wants to steal information from you isn't going to spend eternity doing cryptanalysis on your messages, they're going to try to figure out what or where your key is. So #1 choose your keys wisely, #2 store them in a safe place, if you use a web.config and IIS then you can encrypt parts of the the web.config, and finally if you have to exchange keys make sure that your protocol for exchanging the key is secure.

Update 2 Changed compare method to mitigate against timing attacks. See more info here http://codahale.com/a-lesson-in-timing-attacks/ . Also updated to default to PKCS7 padding and added new constructor to allow end user the ability to choose which padding they would like to use. Thanks @CodesInChaos for the suggestions.

2 upvote
  flag
1) That class is pretty annoying to use since you put the burden of IV management on the user who will almost certainly get it wrong. 2) Lack of MAC makes this vulnerable to padding oracles. – CodesInChaos
2 upvote
  flag
1) Your padding looks broken to me. You add a zero padding and don't remove it. Zero padding is a bad idea since it can't be removed reliably. Use PKCS#7 padding instead. I'd expect the bouncycastle encryption/decryption function to already support this. 2) You should use a constant time comparison to validate the MAC, not SequenceEqual. This avoids a timing side-channel that leaks how long a prefix of the presented MAC and the actual MAC match. – CodesInChaos
1 upvote
  flag
@CodesInChaos I agree, thanks for checking this I've made an edit to resolve these couple issues. – nerdybeardo – nerdybeardo
upvote
  flag
great answer, just one question....what would be the key and hmacKey, i'm new to crypto..thanks ! – Terkhos
1 upvote
  flag
@Terkhos You should use a secure random number generator for generating keys like RNGCryptoServiceProvider, you should never use a passphrase or something predictable. You should also use the maximum length that the algorithm will provide for example AES 256 uses a key size that's 256 bits in length so 32 random bytes would be best, HMAC key sizes are typically are based on the size of the algorithm for example SHA2 (256) a 256 bit key generated by a secure random number generator would suffice. Change keys often! The more often the better! – nerdybeardo
upvote
  flag
@nerdybeardo thanks man, it helped a lot ! – Terkhos
upvote
  flag
does the HMAC class come from System.Security.Cryptography or Org.BouncyCastle.Crypto.Macs? – ps2goat
upvote
  flag
I have a question about this one, must it really use two keys? I understand they do different things, but can both keys perhaps be combined into one or is that bad practice? How come i cannot find anywhere else on the internet where an encryption takes two keys? – maksymiuk

If you are using ASP.Net you can now use built in functionality in .Net 4.0 onwards.

System.Web.Security.MachineKey

.Net 4.5 has MachineKey.Protect() and MachineKey.Unprotect().

.Net 4.0 has MachineKey.Encode() and MachineKey.Decode(). You should just set the MachineKeyProtection to 'All'.

Outside of ASP.Net this class seems to generate a new key with every app restart so doesn't work. With a quick peek in ILSpy it looks to me like it generates its own defaults if the appropriate app.settings are missing. So you may actually be able to set it up outside ASP.Net.

I haven't been able to find a non-ASP.Net equivalent outside the System.Web namespace.

upvote
  flag
hmm can anyone tell me why does this answer has so few votes? It looks like a very convenient way for ASP.NET applications – Dirk Boer
upvote
  flag
@DirkBoer The functionality was added a couple of years after the question was asked, I added my answer to this question to let people know there are easier ways today. This also only works with ASP.Net without some app.config-fu which is fairly dangerous if you don't know what you are doing. – mattmanser
upvote
  flag
Pardon my ignorance but from the web page I can't figure out my answer. If I encrypt a string on one machine, write it to a database, and read it with another machine will I be able to decrypt it as long as the purposes parameters are the same value? Maybe I'm just confused by the class name "MachineKey" – Adriaan Davel
upvote
  flag
Another question, can I use this in a WPF app? It has no web references, is it ok to add the references to System.Web? – Adriaan Davel
upvote
  flag
@AdriaanDavel Yes, but be aware that I think it generates a new machine key each app run, so depending on what you are using it for I think you need to save your own machine key somewhere. – mattmanser
upvote
  flag
@AdriaanDavel Per the linked docs, "The MachineKey APIs should only be used in an ASP.NET app. Behavior of the MachineKey APIs outside the context of an ASP.NET application is undefined" -- use it only if you enjoy the game of Russian Roulette – Mark Sowul

This is the class that was placed here by Brett. However I made a slight edit since I was receiving the error 'Invalid length for a Base-64 char array' when using it for URL strings to encrypt and decrypt.

public class CryptoURL
{
    private static byte[] _salt = Encoding.ASCII.GetBytes("Catto_Salt_Enter_Any_Value99");

    /// <summary>
    /// Encrypt the given string using AES.  The string can be decrypted using 
    /// DecryptStringAES().  The sharedSecret parameters must match. 
    /// The SharedSecret for the Password Reset that is used is in the next line
    ///  string sharedSecret = "OneUpSharedSecret9";
    /// </summary>
    /// <param name="plainText">The text to encrypt.</param>
    /// <param name="sharedSecret">A password used to generate a key for encryption.</param>
    public static string EncryptString(string plainText, string sharedSecret)
    {
        if (string.IsNullOrEmpty(plainText))
            throw new ArgumentNullException("plainText");
        if (string.IsNullOrEmpty(sharedSecret))
            throw new ArgumentNullException("sharedSecret");

        string outStr = null;                       // Encrypted string to return
        RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

            // Create a RijndaelManaged object
            aesAlg = new RijndaelManaged();
            aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);

            // Create a decryptor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                // prepend the IV
                msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
                msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                }

                outStr = HttpServerUtility.UrlTokenEncode(msEncrypt.ToArray());
                //outStr = Convert.ToBase64String(msEncrypt.ToArray());
                // you may need to add a reference. right click reference in solution explorer => "add Reference" => .NET tab => select "System.Web"
            }
        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        // Return the encrypted bytes from the memory stream.
        return outStr;
    }

    /// <summary>
    /// Decrypt the given string.  Assumes the string was encrypted using 
    /// EncryptStringAES(), using an identical sharedSecret.
    /// </summary>
    /// <param name="cipherText">The text to decrypt.</param>
    /// <param name="sharedSecret">A password used to generate a key for decryption.</param>
    public static string DecryptString(string cipherText, string sharedSecret)
    {
        if (string.IsNullOrEmpty(cipherText))
            throw new ArgumentNullException("cipherText");
        if (string.IsNullOrEmpty(sharedSecret))
            throw new ArgumentNullException("sharedSecret");

        // Declare the RijndaelManaged object
        // used to decrypt the data.
        RijndaelManaged aesAlg = null;

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        byte[] inputByteArray;

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

            // Create the streams used for decryption.                
            //byte[] bytes = Convert.FromBase64String(cipherText);
            inputByteArray = HttpServerUtility.UrlTokenDecode(cipherText);

            using (MemoryStream msDecrypt = new MemoryStream(inputByteArray))
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                // Get the initialization vector from the encrypted stream
                aesAlg.IV = ReadByteArray(msDecrypt);
                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
        catch (System.Exception ex)
        {
            return "ERROR";
            //throw ex;

        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        return plaintext;
    }

    static string ConvertStringArrayToString(string[] array)
    {
        //
        // Concatenate all the elements into a StringBuilder.
        //
        StringBuilder builder = new StringBuilder();
        foreach (string value in array)
        {
            builder.Append(value);
            builder.Append('.');
        }
        return builder.ToString();
    }

    private static byte[] ReadByteArray(Stream s)
    {
        byte[] rawLength = new byte[sizeof(int)];
        if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
        {
            throw new SystemException("Stream did not contain properly formatted byte array");
        }

        byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
        if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
        {
            throw new SystemException("Did not read byte array properly");
        }

        return buffer;
    }

}
upvote
  flag
What is the ConvertStringArrayToString() method used for? – abenci
            using System;
            using System.Collections.Generic;
            using System.Text;
            using System.Text.RegularExpressions;  // This is for password validation
            using System.Security.Cryptography;
            using System.Configuration;  // This is where the hash functions reside

            namespace BullyTracker.Common
            {
                public class HashEncryption
                {
                    //public string GenerateHashvalue(string thisPassword)
                    //{
                    //    MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                    //    byte[] tmpSource;
                    //    byte[] tmpHash;

                    //    tmpSource = ASCIIEncoding.ASCII.GetBytes(thisPassword); // Turn password into byte array
                    //    tmpHash = md5.ComputeHash(tmpSource);

                    //    StringBuilder sOutput = new StringBuilder(tmpHash.Length);
                    //    for (int i = 0; i < tmpHash.Length; i++)
                    //    {
                    //        sOutput.Append(tmpHash[i].ToString("X2"));  // X2 formats to hexadecimal
                    //    }
                    //    return sOutput.ToString();
                    //}
                    //public Boolean VerifyHashPassword(string thisPassword, string thisHash)
                    //{
                    //    Boolean IsValid = false;
                    //    string tmpHash = GenerateHashvalue(thisPassword); // Call the routine on user input
                    //    if (tmpHash == thisHash) IsValid = true;  // Compare to previously generated hash
                    //    return IsValid;
                    //}
                    public string GenerateHashvalue(string toEncrypt, bool useHashing)
                    {
                        byte[] keyArray;
                        byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

                        System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
                        // Get the key from config file
                        string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
                        //System.Windows.Forms.MessageBox.Show(key);
                        if (useHashing)
                        {
                            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                            keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                            hashmd5.Clear();
                        }
                        else
                            keyArray = UTF8Encoding.UTF8.GetBytes(key);

                        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
                        tdes.Key = keyArray;
                        tdes.Mode = CipherMode.ECB;
                        tdes.Padding = PaddingMode.PKCS7;

                        ICryptoTransform cTransform = tdes.CreateEncryptor();
                        byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                        tdes.Clear();
                        return Convert.ToBase64String(resultArray, 0, resultArray.Length);
                    }
                    /// <summary>
                    /// DeCrypt a string using dual encryption method. Return a DeCrypted clear string
                    /// </summary>
                    /// <param name="cipherString">encrypted string</param>
                    /// <param name="useHashing">Did you use hashing to encrypt this data? pass true is yes</param>
                    /// <returns></returns>
                    public string Decrypt(string cipherString, bool useHashing)
                    {
                        byte[] keyArray;
                        byte[] toEncryptArray = Convert.FromBase64String(cipherString);

                        System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
                        //Get your key from config file to open the lock!
                        string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));

                        if (useHashing)
                        {
                            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                            keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                            hashmd5.Clear();
                        }
                        else
                            keyArray = UTF8Encoding.UTF8.GetBytes(key);

                        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
                        tdes.Key = keyArray;
                        tdes.Mode = CipherMode.ECB;
                        tdes.Padding = PaddingMode.PKCS7;

                        ICryptoTransform cTransform = tdes.CreateDecryptor();
                        byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

                        tdes.Clear();
                        return UTF8Encoding.UTF8.GetString(resultArray);
                    }


                }

            }
3 upvote
  flag
Really low quality. 1) ECB mode (which also implies no IV) 2) 3DES 3) Confuses keys and passwords. 4) Bad naming 5) No MAC – CodesInChaos

for simplicity i made for myself this function that i use for non crypto purposes : replace "yourpassphrase" with your password ...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

 namespace My
{
    public class strCrypto
    {
        // This constant string is used as a "salt" value for the PasswordDeriveBytes function calls.
    // This size of the IV (in bytes) must = (keysize / 8).  Default keysize is 256, so the IV must be
    // 32 bytes long.  Using a 16 character string here gives us 32 bytes when converted to a byte array.
    private const string initVector = "r5dm5fgm24mfhfku";
    private const string passPhrase = "yourpassphrase"; // email password encryption password

    // This constant is used to determine the keysize of the encryption algorithm.
    private const int keysize = 256;

    public static string encryptString(string plainText)
    {
        //if the plaintext  is empty or null string just return an empty string
        if (plainText == "" || plainText == null )
        {
            return "";
        }

        byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
        byte[] keyBytes = password.GetBytes(keysize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream();
        CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
        cryptoStream.FlushFinalBlock();
        byte[] cipherTextBytes = memoryStream.ToArray();
        memoryStream.Close();
        cryptoStream.Close();
        return Convert.ToBase64String(cipherTextBytes);
    }

    public static string decryptString(string cipherText)
    {
        //if the ciphertext is empty or null string just return an empty string
        if (cipherText == "" || cipherText == null )
        {
            return "";
        }

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
        byte[] keyBytes = password.GetBytes(keysize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
        CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
        memoryStream.Close();
        cryptoStream.Close();
        return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
    }


}

}

4 upvote
  flag
1) No salt in key derivation 2) Constant IV, which misses the whole point of an IV. It should be different for each encryption. 3) No authentication => padding oracles are a threat 4) encryptor.TransformFinalBlock is simpler than using those memory and crypto streams. – CodesInChaos

Here is a simple example of encrypting strings in C# using AES CBC mode with random IV and HMAC and password-derived keys, to show the basic moving parts:

private byte[] EncryptBytes(byte[] key, byte[] plaintext)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        using (var encryptor = cipher.CreateEncryptor())
        {
            var ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);

            // IV is prepended to ciphertext
            return cipher.IV.Concat(ciphertext).ToArray();
        }
    }
}

private byte[] DecryptBytes(byte[] key, byte[] packed)
{
    using (var cipher = new RijndaelManaged { Key = key })
    {
        int ivSize = cipher.BlockSize / 8;

        cipher.IV = packed.Take(ivSize).ToArray();

        using (var encryptor = cipher.CreateDecryptor())
        {
            return encryptor.TransformFinalBlock(packed, ivSize, packed.Length - ivSize);
        }
    }
}

private byte[] AddMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        var macBytes = hmac.ComputeHash(data);

        // HMAC is appended to data
        return data.Concat(macBytes).ToArray();
    }
}

private bool BadMac(byte[] found, byte[] computed)
{
    int mismatch = 0;

    // Aim for consistent timing regardless of inputs
    for (int i = 0; i < found.Length; i++)
    {
        mismatch += found[i] == computed[i] ? 0 : 1;
    }

    return mismatch != 0;
}

private byte[] RemoveMac(byte[] key, byte[] data)
{
    using (var hmac = new HMACSHA256(key))
    {
        int macSize = hmac.HashSize / 8;

        var packed = data.Take(data.Length - macSize).ToArray();

        var foundMac = data.Skip(packed.Length).ToArray();

        var computedMac = hmac.ComputeHash(packed);

        if (this.BadMac(foundMac, computedMac))
        {
            throw new Exception("Bad MAC");
        }

        return packed;
    }            
}

private List<byte[]> DeriveTwoKeys(string password)
{
    var salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    var kdf = new Rfc2898DeriveBytes(password, salt, 10000);

    var bytes = kdf.GetBytes(32); // Two keys 128 bits each

    return new List<byte[]> { bytes.Take(16).ToArray(), bytes.Skip(16).ToArray() };
}

public byte[] EncryptString(string password, String message)
{
    var keys = this.DeriveTwoKeys(password);

    var plaintext = Encoding.UTF8.GetBytes(message);

    var packed = this.EncryptBytes(keys[0], plaintext);

    return this.AddMac(keys[1], packed);
}

public String DecryptString(string password, byte[] secret)
{
    var keys = this.DeriveTwoKeys(password);

    var packed = this.RemoveMac(keys[1], secret);

    var plaintext = this.DecryptBytes(keys[0], packed);

    return Encoding.UTF8.GetString(plaintext);
}

public void Example()
{
    var password = "correcthorsebatterystaple";

    var secret = this.EncryptString(password, "Hello World");

    Console.WriteLine("secret: " + BitConverter.ToString(secret));

    var recovered = this.DecryptString(password, secret);

    Console.WriteLine(recovered);
}
2 upvote
  flag
A couple of issues: 1) You're not using a salt in the key derivation, enabling multi target attacks. 2) Your MAC comparison function is potentially vulnerable to side-channel/timing attacks since you branch on secret data. Use something like mismatch += found[i]^computed[i] instead. 3) You're using more than 20 bytes of PBKDF2-HMAC-SHA-1 which slows your KDF down by a factor of 2 without slowing down an attacker – CodesInChaos
upvote
  flag
@CodesInChaos: 1) This was meant as a simple example to get people started -- I omit random salt only for clarity. But, good point. 2) Good, subtle point. 3) What do you suggest to derive two 16 byte keys in twenty bytes? – Jim Flood
upvote
  flag
The simplest way is hashing the output of the slow hash with SHA-2. Fancier ways are HKDF or simply applying PBKDF2 again, but this time with iterations set to 1. – CodesInChaos
upvote
  flag
@CodesInChaos I would not use SHA-2. The job of a hash function is not the same as the job of a key derivation function. A hash only needs to be unpredictable, and to change when the input changes. A key needs to be indistinguishable from random. I would still draw 32 bytes from the KDF. In this case, you are optimizing too early and adding risk. – Jim Flood

If you got here looking for PGP encryption, in the following comment on an example of how to use PGP encryption via BouncyCastle, the PGPEncryptDecrypt class seems to work basically out of the box:

http://blogs.microsoft.co.il/kim/2009/01/23/pgp-zip-encrypted-files-with-c/#comment-611002

Too long to paste here, slightly modified: https://gist.github.com/zaus/c0ea1fd8dad5d9590af1

Copied in my answer here from a similar question: Simple two-way encryption for C#.

Based on multiple answers and comments.

  • Random initialization vector prepended to crypto text (@jbtule)
  • Use TransformFinalBlock() instead of MemoryStream (@RenniePet)
  • No pre-filled keys to avoid anyone copy & pasting a disaster
  • Proper dispose and using patterns

Code:

/// <summary>
/// Simple encryption/decryption using a random initialization vector
/// and prepending it to the crypto text.
/// </summary>
/// <remarks>Based on multiple answers in //allinonescript.com/questions/165808/simple-two-way-encryption-for-c-sharp </remarks>
public class SimpleAes : IDisposable
{
    /// <summary>
    ///     Initialization vector length in bytes.
    /// </summary>
    private const int IvBytes = 16;

    /// <summary>
    ///     Must be exactly 16, 24 or 32 characters long.
    /// </summary>
    private static readonly byte[] Key = Convert.FromBase64String("FILL ME WITH 16, 24 OR 32 CHARS");

    private readonly UTF8Encoding _encoder;
    private readonly ICryptoTransform _encryptor;
    private readonly RijndaelManaged _rijndael;

    public SimpleAes()
    {
        _rijndael = new RijndaelManaged {Key = Key};
        _rijndael.GenerateIV();
        _encryptor = _rijndael.CreateEncryptor();
        _encoder = new UTF8Encoding();
    }

    public string Decrypt(string encrypted)
    {
        return _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
    }

    public void Dispose()
    {
        _rijndael.Dispose();
        _encryptor.Dispose();
    }

    public string Encrypt(string unencrypted)
    {
        return Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted)));
    }

    private byte[] Decrypt(byte[] buffer)
    {
        // IV is prepended to cryptotext
        byte[] iv = buffer.Take(IvBytes).ToArray();
        using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv))
        {
            return decryptor.TransformFinalBlock(buffer, IvBytes, buffer.Length - IvBytes);
        }
    }

    private byte[] Encrypt(byte[] buffer)
    {
        // Prepend cryptotext with IV
        byte[] inputBuffer = _rijndael.IV.Concat(buffer).ToArray();
        return _encryptor.TransformFinalBlock(inputBuffer, IvBytes, buffer.Length);
    }
}
1 upvote
  flag
You should add a MAC to prevent active attacks, such as padding oracles. – CodesInChaos
upvote
  flag
You are probably right, I'm in no way proficient on this area. When I originally visited this topic I just wanted something simple that works and fairly secure. I'd definitely use a tried and true library for very sensitive data. – angularsen

You have to use the namespace using System.Security.Cryptography; and useHashing is a bool type either true or false. String variable "key" should be same for Encryption and for Decryption

//Encryption
public string EncryptText(string toEncrypt, bool useHashing)
    {
        try
        {
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            string key = "String Key Value"; //Based on this key stirng is encrypting
            //System.Windows.Forms.MessageBox.Show(key);
            //If hashing use get hashcode regards to your key
            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //Always release the resources and flush data
                //of the Cryptographic service provide. Best Practice

                hashmd5.Clear();
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes. We choose ECB(Electronic code Book)
            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateEncryptor();
            //transform the specified region of bytes array to resultArray
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0,          toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor
            tdes.Clear();
            //Return the encrypted data into unreadable string format
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
        catch (Exception e)
        {
            throw e;
        }
    }

    //Decryption
    public string DecryptText(string cipherString, bool useHashing)
    {

        try
        {
            byte[] keyArray;
            //get the byte code of the string

            byte[] toEncryptArray = Convert.FromBase64String(cipherString);

            string key = "String Key Value"; //Based on this key string is decrypted

            if (useHashing)
            {
                //if hashing was used get the hash code with regards to your key
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //release any resource held by the MD5CryptoServiceProvider

                hashmd5.Clear();
            }
            else
            {
                //if hashing was not implemented get the byte code of the key
                keyArray = UTF8Encoding.UTF8.GetBytes(key);
            }

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes.
            //We choose ECB(Electronic code Book)

            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateDecryptor();
            byte[] resultArray = cTransform.TransformFinalBlock
                    (toEncryptArray, 0, toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor
            tdes.Clear();
            //return the Clear decrypted TEXT
            return UTF8Encoding.UTF8.GetString(resultArray);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
3 upvote
  flag
-1 1) ECB mode is very weak 2) Lack of MAC leaves you open to active attacks, such as padding oracles. 3) Why would you still use 3DES nowadays? It's not broken, but AES is clearly a better choice. – CodesInChaos

Here is simple Snippet originally by ASP Snippets

using System.Text;
using System.Security.Cryptography;
using System.IO;


 private string Encrypt(string clearText)
    {
        string EncryptionKey = "yourkey";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText;
    }

 private string Decrypt(string cipherText)
    {
        string EncryptionKey = "yourkey";
        cipherText = cipherText.Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }
1 upvote
  flag
You don't check integrity/authentication. You should add a MAC. – Artjom B.
upvote
  flag
What you exactly mean actually the above example is to Encrypt/Decrypt the string variable. – Vijay Kumbhoje
3 upvote
  flag
The ciphertext should be authenticated (e.g. with HMAC) to protect against padding oracle attacks. When I look through this code again, it seems that you're using ECB mode which should never be used because it is not semantically secure. Also, when you derive the key and IV from a master key and salt, the salt is static. This leads to a static IV which breaks the whole concept of the IV and makes your scheme semantically insecure again. – Artjom B.
upvote
  flag
Thanks Brother, it would be great help if you can pass the corrected code here. – Vijay Kumbhoje

Encryption

public string EncryptString(string inputString)
{
MemoryStream memStream = null;
try
{
    byte[] key = { };
    byte[] IV = { 12, 21, 43, 17, 57, 35, 67, 27 };
    string encryptKey = "aXb2uy4z"; // MUST be 8 characters
    key = Encoding.UTF8.GetBytes(encryptKey);
    byte[] byteInput = Encoding.UTF8.GetBytes(inputString);
    DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
    memStream = new MemoryStream();
    ICryptoTransform transform = provider.CreateEncryptor(key, IV);
    CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
    cryptoStream.Write(byteInput, 0, byteInput.Length);
    cryptoStream.FlushFinalBlock();

}
catch (Exception ex)
{
    Response.Write(ex.Message);
}
return Convert.ToBase64String(memStream.ToArray());
}

Decryption:

public string DecryptString(string inputString)
{
MemoryStream memStream = null;
try
{
    byte[] key = { };
    byte[] IV = { 12, 21, 43, 17, 57, 35, 67, 27 };
    string encryptKey = "aXb2uy4z"; // MUST be 8 characters
    key = Encoding.UTF8.GetBytes(encryptKey);
    byte[] byteInput = new byte[inputString.Length];
    byteInput = Convert.FromBase64String(inputString);
    DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
    memStream = new MemoryStream();
    ICryptoTransform transform = provider.CreateDecryptor(key, IV);
    CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
    cryptoStream.Write(byteInput, 0, byteInput.Length);
    cryptoStream.FlushFinalBlock();
}
catch (Exception ex)
{
    Response.Write(ex.Message);
}

Encoding encoding1 = Encoding.UTF8;
return encoding1.GetString(memStream.ToArray());
}
6 upvote
  flag
-1 This is very weak. 1) DES is easy to brute force having a 56 bit key. 2) A key is binary, not UTF8. If the key consists of ASCII characters (likely in practice), this reduces the effective key size to 48 bits. 3) An IV should be different for each message 4) Lack of MAC leaves you open to active attacks, including padding oracles. – CodesInChaos
5 upvote
  flag
+1 OP had a very simple question, without requirement for maximum strenght, and this answer corresponds with that perfectly. At least I can use this because I also have a simple usage for encryption. – Roland
upvote
  flag
A little bit of explenation would be nice... – Dieter Meemken
upvote
  flag
-1 @Roland as mentioned by CodesInChaos an IV needs to be different for each message, very simply, if it isn't, you are using the API incorrectly, hence this code should never be used. Period. Not to overshadow the 48bit key makes this decryptable to anyone without the key in merely a day, so this this is no longer encryption and thus does not answer the question. – jbtule
upvote
  flag
@jbtule thanks, I will seriously consider the other answers when reviewing my encryption project. – Roland
upvote
  flag
Security Warning: Do Not Use This Code See above Comment by @CodesInChaos – jbtule

A good algorithm to securely encrypt data is BCrypt:

Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.

There's a nice .NET implementation of BCrypt that is available also as a NuGet package.

upvote
  flag
yes, good nuget package! – juFo
5 upvote
  flag
The question asks how to encrypt and decrypt a string. Unless I'm missing something huge -- how can you decrypt a string in BCrypt? BCrypt, despite its name, is a hashing function. – The1nk

Disclaimer: This solution should only be used for data at rest that is not exposed to the public (for example - a configuration file or DB). Only in this scenario, the quick-and-dirty solution can be considered better than @jbtule's solution, due to lower maintanance.

Original post: I found jbtule's answer a bit complicated for a quick and dirty secured AES string encryption and Brett's answer had a bug with the Initialization Vector being a fixed value making it vulnerable to padding attacks, so I fixed Brett's code and added a random IV that is added to the chipered string, creating a different encrypted value each and every encryption of the same value:

Encryption:

public static string Encrypt(string clearText)
    {            
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            byte[] IV = new byte[15];
            rand.NextBytes(IV);
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(IV) + Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText;
    }

Decryption:

public static string Decrypt(string cipherText)
    {
        byte[] IV = Convert.FromBase64String(cipherText.Substring(0, 20));
        cipherText = cipherText.Substring(20).Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }

Replace EncryptionKey with your key. In my implementation, the key is being saved in the configuration file (web.config\app.config) as you shouldn't save it hard coded. The configuration file should be also encrypted so the key won't be saved as clear text in it.

protected static string _Key = "";
    protected static string EncryptionKey
    {
        get
        {
            if (String.IsNullOrEmpty(_Key))
            {
                _Key = ConfigurationManager.AppSettings["AESKey"].ToString();
            }

            return _Key;
        }
    }
upvote
  flag
While your Encrypt method generates a different value for every call even with the same plain text, the Substring(20) will be the same every time, right? – dub stylee
upvote
  flag
What do you mean "the same"? The decrypt function takes every value that was generated by the encryption function, breaks it apart to the initialization vector and the encrypted value, and decrypt it, – Gil Cohen
upvote
  flag
I didn't notice that the Encrypt generated a different IV each time. For some reason I was thinking the IV was the same every time, which would basically make it pointless. – dub stylee
upvote
  flag
Security is complicated, and should not be quick and dirty. But ultimately -1 because you lose a lot of security with CBC and PKCS7 when you don't authenticate the cipher text. – jbtule
upvote
  flag
I understand what you say @jbtule, but it's really all about risk management. If all you need to do is to store some confidential info locally and you want extra defense with AES, this solution might satisfy your needs. – Gil Cohen
upvote
  flag
@GilCohen Well put a big disclaimer on this and say only use for data at rest, don't expose with a service and then you can claim risk management. however, your quick and dirty is just sloppy. For example why do you replace spaces with plus signs on just decrypt and not vice versa, is it because something else is modifying the ciphertext before you get? Like passing via a url query string, cookie or form variable, hmm, that sounds like a service, which is absolutely when you need to authenticate a cipher text. – jbtule
1 upvote
  flag
@jbtule actually no, this is the encoding of Base64 function for some reason. This was indeed used for data at rest and I agree with your comment. I'll add it. – Gil Cohen

AES Algorithm:

public static class CryptographyProvider
    {
        public static string EncryptString(string plainText, out string Key)
        {
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");

            using (Aes _aesAlg = Aes.Create())
            {
                Key = Convert.ToBase64String(_aesAlg.Key);
                ICryptoTransform _encryptor = _aesAlg.CreateEncryptor(_aesAlg.Key, _aesAlg.IV);

                using (MemoryStream _memoryStream = new MemoryStream())
                {
                    _memoryStream.Write(_aesAlg.IV, 0, 16);
                    using (CryptoStream _cryptoStream = new CryptoStream(_memoryStream, _encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter _streamWriter = new StreamWriter(_cryptoStream))
                        {
                            _streamWriter.Write(plainText);
                        }
                        return Convert.ToBase64String(_memoryStream.ToArray());
                    }
                }
            }
        }
        public static string DecryptString(string cipherText, string Key)
        {

            if (string.IsNullOrEmpty(cipherText))
                throw new ArgumentNullException("cipherText");
            if (string.IsNullOrEmpty(Key))
                throw new ArgumentNullException("Key");

            string plaintext = null;

            byte[] _initialVector = new byte[16];
            byte[] _Key = Convert.FromBase64String(Key);
            byte[] _cipherTextBytesArray = Convert.FromBase64String(cipherText);
            byte[] _originalString = new byte[_cipherTextBytesArray.Length - 16];

            Array.Copy(_cipherTextBytesArray, 0, _initialVector, 0, _initialVector.Length);
            Array.Copy(_cipherTextBytesArray, 16, _originalString, 0, _cipherTextBytesArray.Length - 16);

            using (Aes _aesAlg = Aes.Create())
            {
                _aesAlg.Key = _Key;
                _aesAlg.IV = _initialVector;
                ICryptoTransform decryptor = _aesAlg.CreateDecryptor(_aesAlg.Key, _aesAlg.IV);

                using (MemoryStream _memoryStream = new MemoryStream(_originalString))
                {
                    using (CryptoStream _cryptoStream = new CryptoStream(_memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader _streamReader = new StreamReader(_cryptoStream))
                        {
                            plaintext = _streamReader.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }
    }
upvote
  flag
1) The IV is passed in as a parameter which means that the developer has to do the IV management and they will get it wrong. Instead, the IV should be randomly generated and stored alongside of the ciphertext. 2) Since the IV and key will change between multiple executions of the Encryption method and does not persist, there is no need to have this method at all other than for demonstration purposes. 3) There is no authentication of the ciphertext, so attackers may manipulate it without you detecting it (see: padding oracle attack). – Artjom B.
upvote
  flag
hai @ArtjomB. developer need not to worry about iv management because it ll be get generated and added along with the encrypted string. – Skull
upvote
  flag
I have to disagree. The IV is stored in the _iv class variable and not written into the ciphertext. So, how do you think the receiver will know the key and IV? They would have to be distributed in some other way. Since the IV is not supposed to be secret, it should be randomly generated for each encryption and distributed along with the ciphertext. – Artjom B.
1 upvote
  flag
1 upvote
  flag
1)In the above link, you can get the way of implementing aes without ,need not to worry about iv management,because iv is also get encrypted along with string. 2)since function you refers contains private access modifier you are not be able to call it outside. Inorder to encrypt we can be able to use only Cryptographyclass.Encrytion("SAMPLEstring") function – Skull
upvote
  flag
That's better. Could you update the code in your answer, so I can remove my downvote? – Artjom B.
upvote
  flag
I have updated...@ArtjomB. – Skull

To support mattmanser answer. Here's an example using MachineKey class to encrypt/decrypt URL safe values.

Something to bear in mind, as mentioned before, this will use Machine config settings (https://msdn.microsoft.com/en-us/library/ff649308.aspx). You can set encryption and decryption key/algorithm manually (you might need this specially if your site is running on multiple servers) in web.config file. You can generate keys from IIS (see here: https://blogs.msdn.microsoft.com/vijaysk/2009/05/13/iis-7-tip-10-you-can-generate-machine-keys-from-the-iis-manager/) or can use an online machine key generator like: http://www.developerfusion.com/tools/generatemachinekey/

    private static readonly UTF8Encoding Encoder = new UTF8Encoding();

    public static string Encrypt(string unencrypted)
    {
        if (string.IsNullOrEmpty(unencrypted)) 
            return string.Empty;

        try
        {
            var encryptedBytes = MachineKey.Protect(Encoder.GetBytes(unencrypted));

            if (encryptedBytes != null && encryptedBytes.Length > 0)
                return HttpServerUtility.UrlTokenEncode(encryptedBytes);    
        }
        catch (Exception)
        {
            return string.Empty;
        }

        return string.Empty;
    }

    public static string Decrypt(string encrypted)
    {
        if (string.IsNullOrEmpty(encrypted)) 
            return string.Empty;

        try
        {
            var bytes = HttpServerUtility.UrlTokenDecode(encrypted);
            if (bytes != null && bytes.Length > 0)
            {
                var decryptedBytes = MachineKey.Unprotect(bytes);
                if(decryptedBytes != null && decryptedBytes.Length > 0)
                    return Encoder.GetString(decryptedBytes);
            }

        }
        catch (Exception)
        {
            return string.Empty;
        }

        return string.Empty;
    }

Encryption is a very common matter in programming. I think it is better to install a package to do the task for you. Maybe a simple open source Nuget project like Simple Aes Encryption

The key is in the config file and therefore it is easy to change in the production environment, and I don't see any drawbacks

<MessageEncryption>
  <EncryptionKey KeySize="256" Key="3q2+796tvu/erb7v3q2+796tvu/erb7v3q2+796tvu8="/>
</MessageEncryption>
1 upvote
  flag
Big drawback is that it's not authenticated encryption. – jbtule

An alternative to BouncyCastle for AES-GCM encryption is libsodium-net. It wraps the libsodium C library. One nice advantage is that it uses the AES-NI extension in CPUs for very fast encryption. The down side is that it won't work at all if the CPU doesn't have the extension. There's no software fall back.

With the reference of Encrypt and Decrypt a String in c#, I found one of good solution :

static readonly string PasswordHash = "P@@Sw0rd";
static readonly string SaltKey = "S@LT&KEY";
static readonly string VIKey = "@1B2c3D4e5F6g7H8";

For Encrypt

public static string Encrypt(string plainText)
{
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

    byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
    var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
    var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));

    byte[] cipherTextBytes;

    using (var memoryStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            cipherTextBytes = memoryStream.ToArray();
            cryptoStream.Close();
        }
        memoryStream.Close();
    }
    return Convert.ToBase64String(cipherTextBytes);
}

For Decrypt

public static string Decrypt(string encryptedText)
{
    byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
    byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
    var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };

    var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
    var memoryStream = new MemoryStream(cipherTextBytes);
    var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
    byte[] plainTextBytes = new byte[cipherTextBytes.Length];

    int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
    memoryStream.Close();
    cryptoStream.Close();
    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
}
4 upvote
  flag
Hardcoded Salt and IV, and using an ASCII representation for them, this is all kinds of wrong. – jbtule
3 upvote
  flag
Security Warning: Do Not Use This Code See my comment above. – jbtule
upvote
  flag
You know what Nothing is wrong/Unsafe/illogical in our logic industry.Though you might be good at some aspect, its dont mean that you are making wrong review to other post. In additionally, I have seen you some of post you are many of time posting negative blog in place of positive blog.However, your solution is good but never think its best. Life run on code. – Rahul Modi
4 upvote
  flag
I apologize that I didn't spell this out. IV is not a key, and keeping it secret offers zero added security, and making it predictable loses a quite a bit of security. Hardcoding the IV is completely unreasonable/illogical/wrong to anyone that actually knows how to use AES-CBC encryption. Encoding.ASCII.GetBytes for data that is intended to add entropy to something that human chosen, is going to be way less then entropy than expected and is a very novice mistake. These are all things that are easily correctable, but you aren't, so my bold warning stays, due to security implications. – jbtule
2 upvote
  flag
Rahul, chill down! Sit back, relax and think why all 3 comments from @jbtule got up-votes. He is talking something sensible in order to put you on right path. Nothing to feel offended. You are new to SO. You'll realize how it works eventually. – niksofteng

Not the answer you're looking for? Browse other questions tagged or ask your own question.