Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypt and decrypt a string in C#? [closed]

How can I encrypt and decrypt a string in C#?

like image 756
NotDan Avatar asked Oct 14 '08 17:10

NotDan


People also ask

What does it mean to encrypt a string?

Encrypts a string, using a symmetric key-based algorithm, in which the same key is used to encrypt and decrypt a string. The security of the encrypted string depends on maintaining the secrecy of the key, and the algoirthm choice.

How do I encrypt and decrypt a text file?

Right-click (or press and hold) a file or folder and select Properties. Select the Advanced button and select the Encrypt contents to secure data check box. Select OK to close the Advanced Attributes window, select Apply, and then select OK.


Video Answer


17 Answers

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.

https://stackoverflow.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;     } } 
like image 86
Brett Avatar answered Sep 30 '22 01:09

Brett


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);     }   } } 
like image 36
jbtule Avatar answered Sep 30 '22 03:09

jbtule


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

like image 33
Tamas Czinege Avatar answered Sep 30 '22 03:09

Tamas Czinege


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.

like image 27
mattmanser Avatar answered Sep 30 '22 03:09

mattmanser


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.

like image 25
nerdybeardo Avatar answered Sep 30 '22 02:09

nerdybeardo


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;
    }
}
like image 22
Gil Cohen Avatar answered Sep 30 '22 03:09

Gil Cohen


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());
}
like image 22
Gopal Reddy V Avatar answered Sep 30 '22 01:09

Gopal Reddy V


The following example demonstrates how to encrypt and decrypt sample data:

    // This constant is used to determine the keysize of the encryption algorithm in bits.
    // We divide this by 8 within the code below to get the equivalent number of bytes.
    private const int Keysize = 128;

    // This constant determines the number of iterations for the password bytes generation function.
    private const int DerivationIterations = 1000;

    public static string Encrypt(string plainText, string passPhrase)
    {
        // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
        // so that the same Salt and IV values can be used when decrypting.  
        var saltStringBytes = GenerateBitsOfRandomEntropy(16);
        var ivStringBytes = GenerateBitsOfRandomEntropy(16);
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = new RijndaelManaged())
            {
                symmetricKey.BlockSize = 128;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                        {
                            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                            cryptoStream.FlushFinalBlock();
                            // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
                            var cipherTextBytes = saltStringBytes;
                            cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
                            cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Convert.ToBase64String(cipherTextBytes);
                        }
                    }
                }
            }
        }
    }

    public static string Decrypt(string cipherText, string passPhrase)
    {
        // Get the complete stream of bytes that represent:
        // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
        var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
        // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
        var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
        // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
        var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
        // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
        var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        {
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = new RijndaelManaged())
            {
                symmetricKey.BlockSize = 128;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                {
                    using (var memoryStream = new MemoryStream(cipherTextBytes))
                    {
                        using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                        {
                            var plainTextBytes = new byte[cipherTextBytes.Length];
                            var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                        }
                    }
                }
            }
        }
    }

    private static byte[] GenerateBitsOfRandomEntropy(int size)
    {
        // 32 Bytes will give us 256 bits.
        // 16 Bytes will give us 128 bits.
        var randomBytes = new byte[size]; 
        using (var rngCsp = new RNGCryptoServiceProvider())
        {
            // Fill the array with cryptographically secure random bytes.
            rngCsp.GetBytes(randomBytes);
        }
        return randomBytes;
    }
like image 36
reza.Nikmaram Avatar answered Sep 30 '22 01:09

reza.Nikmaram


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());
}
like image 34
Rahul Modi Avatar answered Sep 30 '22 01:09

Rahul Modi


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;
    }
like image 41
josedbaez Avatar answered Sep 30 '22 01:09

josedbaez


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);
}
like image 39
Jim Flood Avatar answered Sep 30 '22 03:09

Jim Flood


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;
    }

}
like image 30
Catto Avatar answered Sep 30 '22 02:09

Catto


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

public class Program
{
    public static void Main()
    {
        var key = Encoding.UTF8.GetBytes("SUkbqO2ycDo7QwpR25kfgmC7f8CoyrZy");
        var data = Encoding.UTF8.GetBytes("testData");

        //Encrypt data
        var encrypted = CryptoHelper.EncryptData(data,key);

        //Decrypt data
        var decrypted = CryptoHelper.DecryptData(encrypted,key);

        //Display result
        Console.WriteLine(Encoding.UTF8.GetString(decrypted));
    }
}

public static class CryptoHelper
{
    public static byte[] EncryptData(byte[] data, byte[] key)
    {
        using (var aesAlg = Aes.Create())
        {
            aesAlg.Mode = CipherMode.CBC;
            using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
            {
                using (var msEncrypt = new MemoryStream())
                {
                    msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);

                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        csEncrypt.Write(data, 0, data.Length);

                    return msEncrypt.ToArray();
                }
            }
        }

    }

    public static byte[] DecryptData(byte[] encrypted, byte[] key)
    {
        var iv = new byte[16];
        Buffer.BlockCopy(encrypted, 0, iv, 0, iv.Length);
        using (var aesAlg = Aes.Create())
        {
            aesAlg.Mode = CipherMode.CBC;
            using (var decryptor = aesAlg.CreateDecryptor(key, iv))
            {
                using (var msDecrypt = new MemoryStream(encrypted, iv.Length, encrypted.Length - iv.Length))
                {
                    using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (var resultStream = new MemoryStream())
                        {
                            csDecrypt.CopyTo(resultStream);
                            return resultStream.ToArray();
                        }
                    }
                }
            }
        }
    }
}
like image 25
Davit Tvildiani Avatar answered Sep 30 '22 02:09

Davit Tvildiani


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.

like image 32
James McLachlan Avatar answered Sep 30 '22 01:09

James McLachlan


The following code is an improved version of Ghazal's answer to a similar question.

public class EncryptionHelper
{
    private Aes aesEncryptor;

    public EncryptionHelper()
    {
    }

    private void BuildAesEncryptor(string key)
    {
        aesEncryptor = Aes.Create();
        var pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
        aesEncryptor.Key = pdb.GetBytes(32);
        aesEncryptor.IV = pdb.GetBytes(16);
    }

    public string EncryptString(string clearText, string key)
    {
        BuildAesEncryptor(key);
        var clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, aesEncryptor.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearBytes, 0, clearBytes.Length);
            }
            var encryptedText = Convert.ToBase64String(ms.ToArray());
            return encryptedText;
        }
    }

    public string DecryptString(string cipherText, string key)
    {
        BuildAesEncryptor(key);
        cipherText = cipherText.Replace(" ", "+");
        var cipherBytes = Convert.FromBase64String(cipherText);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, aesEncryptor.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(cipherBytes, 0, cipherBytes.Length);
            }
            var clearText = Encoding.Unicode.GetString(ms.ToArray());
            return clearText;
        }
    }
}
like image 43
Kolappan N Avatar answered Sep 30 '22 02:09

Kolappan N


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

/// <summary>
/// Summary description for Encryption
/// </summary>
public class Encryption
{
    public TripleDES CreateDES(string key)
    {
        MD5 md5 = new MD5CryptoServiceProvider();
        TripleDES des = new TripleDESCryptoServiceProvider();
        des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
        des.IV = new byte[des.BlockSize / 8];
        return des;
    }
    public  byte[] Encryptiondata(string PlainText)
    {
        TripleDES des = CreateDES("DreamMLMKey");
        ICryptoTransform ct = des.CreateEncryptor();
        byte[] input = Encoding.Unicode.GetBytes(PlainText);
        return ct.TransformFinalBlock(input, 0, input.Length);
    }

    public string Decryptiondata(string CypherText)
    {
        string stringToDecrypt = CypherText.Replace(" ", "+");
        int len = stringToDecrypt.Length;
        byte[] inputByteArray = Convert.FromBase64String(stringToDecrypt); 

        byte[] b = Convert.FromBase64String(CypherText);
        TripleDES des = CreateDES("DreamMLMKey");
        ICryptoTransform ct = des.CreateDecryptor();
        byte[] output = ct.TransformFinalBlock(b, 0, b.Length);
        return Encoding.Unicode.GetString(output);
    }
    public string Decryptiondataurl(string CypherText)
    {
        string newcyperttext=CypherText.Replace(' ', '+');
        byte[] b = Convert.FromBase64String(newcyperttext);
        TripleDES des = CreateDES("DreamMLMKey");
        ICryptoTransform ct = des.CreateDecryptor();
        byte[] output = ct.TransformFinalBlock(b, 0, b.Length);
        return Encoding.Unicode.GetString(output);
    }


    #region  encryption & Decription
    public  string Encrypt(string input, string key)
    {
        byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input);
        TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
        tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
        tripleDES.Mode = CipherMode.ECB;
        tripleDES.Padding = PaddingMode.PKCS7;
        ICryptoTransform cTransform = tripleDES.CreateEncryptor();
        byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
        tripleDES.Clear();
        return Convert.ToBase64String(resultArray, 0, resultArray.Length);
    }
    public  string Decrypt(string input, string key)
    {
        byte[] inputArray = Convert.FromBase64String(input);
        TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
        tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
        tripleDES.Mode = CipherMode.ECB;
        tripleDES.Padding = PaddingMode.PKCS7;
        ICryptoTransform cTransform = tripleDES.CreateDecryptor();
        byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
        tripleDES.Clear();
        return UTF8Encoding.UTF8.GetString(resultArray);
    }

    public string encrypt(string encryptString)
    {
        string EncryptionKey = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        byte[] clearBytes = Encoding.Unicode.GetBytes(encryptString);
        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();
                }
                encryptString = Convert.ToBase64String(ms.ToArray());
            }
        }
        return encryptString;
    }

    public string Decrypt(string cipherText)
    {
        string EncryptionKey = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        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;
    }

    #endregion
}
like image 30
Code Avatar answered Sep 30 '22 01:09

Code


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>
like image 26
Ashkan S Avatar answered Sep 30 '22 02:09

Ashkan S