开发者

C# Example of AES256 encryption using System.Security.Cryptography.Aes

开发者 https://www.devze.com 2023-04-04 17:40 出处:网络
I need to implement AES 256 encryption /decryption and I haven\'t been able to find an example that works correctly.

I need to implement AES 256 encryption /decryption and I haven't been able to find an example that works correctly.

MSDN suggests that I should use the AES class.

The Rijndael class is the predecessor of the Aes algorithm. You should use the Aes algorithm instead of Rijndael. For more information, see the entry The Differences Between Rijndael and AES in the .NET Security blog.

Could anyone point me in the direction of a good example using the AES class for AES256?

To add a little more clarity:

I have a cipher file that contains the sh开发者_StackOverflowared key and a string of encrypted text. I need to decrypt the text and then validate it.

All the examples I've seen expect at least 2 parameters to perform the encryption/decryption.

Should I be able to infer the Initialisation vector and the key from the text in the cipher file?

This is an example of the text held in my cipher file:

ÊÚḱÌrá ƒ@†²;Ä;öDWnªóª©©¨¦L


Maybe this example listed here can help you out. Statement from the author

about 24 lines of code to encrypt, 23 to decrypt

Due to the fact that the link in the original posting is dead - here the needed code parts (c&p without any change to the original source)

  /*
  Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.*/
   
  #region Usings
  using System;
  using System.IO;
  using System.Security.Cryptography;
  using System.Text;
  #endregion
   
  namespace Utilities.Encryption
  {
      /// <summary>
      /// Utility class that handles encryption
      /// </summary>
      public static class AESEncryption
      {
          #region Static Functions
   
          /// <summary>
          /// Encrypts a string
          /// </summary>
          /// <param name="PlainText">Text to be encrypted</param>
          /// <param name="Password">Password to encrypt with</param>
          /// <param name="Salt">Salt to encrypt with</param>
          /// <param name="HashAlgorithm">Can be either SHA1 or MD5</param>
          /// <param name="PasswordIterations">Number of iterations to do</param>
          /// <param name="InitialVector">Needs to be 16 ASCII characters long</param>
          /// <param name="KeySize">Can be 128, 192, or 256</param>
          /// <returns>An encrypted string</returns>
          public static string Encrypt(string PlainText, string Password,
              string Salt = "Kosher", string HashAlgorithm = "SHA1",
              int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
              int KeySize = 256)
          {
              if (string.IsNullOrEmpty(PlainText))
                  return "";
              byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
              byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
              byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
              PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
              byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
              RijndaelManaged SymmetricKey = new RijndaelManaged();
              SymmetricKey.Mode = CipherMode.CBC;
              byte[] CipherTextBytes = null;
              using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
              {
                  using (MemoryStream MemStream = new MemoryStream())
                  {
                      using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
                      {
                          CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
                          CryptoStream.FlushFinalBlock();
                          CipherTextBytes = MemStream.ToArray();
                          MemStream.Close();
                          CryptoStream.Close();
                      }
                  }
              }
              SymmetricKey.Clear();
              return Convert.ToBase64String(CipherTextBytes);
          }
   
          /// <summary>
          /// Decrypts a string
          /// </summary>
          /// <param name="CipherText">Text to be decrypted</param>
          /// <param name="Password">Password to decrypt with</param>
          /// <param name="Salt">Salt to decrypt with</param>
          /// <param name="HashAlgorithm">Can be either SHA1 or MD5</param>
          /// <param name="PasswordIterations">Number of iterations to do</param>
          /// <param name="InitialVector">Needs to be 16 ASCII characters long</param>
          /// <param name="KeySize">Can be 128, 192, or 256</param>
          /// <returns>A decrypted string</returns>
          public static string Decrypt(string CipherText, string Password,
              string Salt = "Kosher", string HashAlgorithm = "SHA1",
              int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
              int KeySize = 256)
          {
              if (string.IsNullOrEmpty(CipherText))
                  return "";
              byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
              byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
              byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
              PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
              byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
              RijndaelManaged SymmetricKey = new RijndaelManaged();
              SymmetricKey.Mode = CipherMode.CBC;
              byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
              int ByteCount = 0;
              using (ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes))
              {
                  using (MemoryStream MemStream = new MemoryStream(CipherTextBytes))
                  {
                      using (CryptoStream CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read))
                      {
   
                          ByteCount = CryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
                          MemStream.Close();
                          CryptoStream.Close();
                      }
                  }
              }
              SymmetricKey.Clear();
              return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
          }
   
          #endregion
      }
  }


Once I'd discovered all the information of how my client was handling the encryption/decryption at their end it was straight forward using the AesManaged example suggested by dtb.

The finally implemented code started like this:

    try
    {
        // Create a new instance of the AesManaged class.  This generates a new key and initialization vector (IV).
        AesManaged myAes = new AesManaged();

        // Override the cipher mode, key and IV
        myAes.Mode = CipherMode.ECB;
        myAes.IV = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // CRB mode uses an empty IV
        myAes.Key = CipherKey;  // Byte array representing the key
        myAes.Padding = PaddingMode.None;

        // Create a encryption object to perform the stream transform.
        ICryptoTransform encryptor = myAes.CreateEncryptor();

        // TODO: perform the encryption / decryption as required...

    }
    catch (Exception ex)
    {
        // TODO: Log the error 
        throw ex;
    }


public class AesCryptoService
{
    private static byte[] Key = Encoding.ASCII.GetBytes(@"qwr{@^h`h&_`50/ja9!'dcmh3!uw<&=?");
    private static byte[] IV = Encoding.ASCII.GetBytes(@"9/\~V).A,lY&=t2b");


    public static string EncryptStringToBytes_Aes(string plainText)
    {
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");
        byte[] encrypted;


        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        
        return Convert.ToBase64String(encrypted);
    }


    
    public static string DecryptStringFromBytes_Aes(string Text)
    {
        if (Text == null || Text.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        string plaintext = null;
        byte[] cipherText = Convert.FromBase64String(Text.Replace(' ', '+'));

        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;


            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }

        }

        return plaintext;
    }
}


Since both RijndaelManaged and AesManaged classes are deprecated, I am including the updated modern representation below. Also please take into account the discussions in this thread about IV generation and such, but this is plenty good enough for our application.

/*
  Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.*/

#region Usings
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
#endregion

namespace Utilities.Encryption
{
    public class AESEncryption
    {
        private const string _ENCRYPT_PASSWORD = "16BytePasswordz!";

        #region Static Functions

        public static string Encrypt(string PlainText)
        {
            return Encrypt(PlainText, _ENCRYPT_PASSWORD);
        }

        public static string Decrypt(string PlainText)
        {
            return Decrypt(PlainText, _ENCRYPT_PASSWORD);
        }

        /// <summary>
        /// Encrypts a string
        /// </summary>
        /// <param name="PlainText">Text to be encrypted</param>
        /// <param name="Password">Password to encrypt with</param>
        /// <param name="Salt">Salt to encrypt with</param>
        /// <param name="HashAlgorithm">Can be either SHA1 or MD5</param>
        /// <param name="PasswordIterations">Number of iterations to do</param>
        /// <param name="InitialVector">Needs to be 16 ASCII characters long</param>
        /// <param name="KeySize">Can be 128, 192, or 256</param>
        /// <returns>An encrypted string</returns>
        public static string Encrypt(string PlainText, string Password,
            string Salt = "Kosher", string HashAlgorithm = "SHA1",
            int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
            int KeySize = 256)
        {
            if (string.IsNullOrEmpty(PlainText))
                return "";
            byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
            byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
            byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
            PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
            byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
            var SymmetricKey = Aes.Create();
            SymmetricKey.Mode = CipherMode.CBC;
            byte[]? CipherTextBytes = null;
            using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
            {
                using (MemoryStream MemStream = new MemoryStream())
                {
                    using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
                    {
                        CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
                        CryptoStream.FlushFinalBlock();
                        CipherTextBytes = MemStream.ToArray();
                        MemStream.Close();
                        CryptoStream.Close();
                    }
                }
            }
            SymmetricKey.Clear();
            return Convert.ToBase64String(CipherTextBytes);
        }

        /// <summary>
        /// Decrypts a string
        /// </summary>
        /// <param name="CipherText">Text to be decrypted</param>
        /// <param name="Password">Password to decrypt with</param>
        /// <param name="Salt">Salt to decrypt with</param>
        /// <param name="HashAlgorithm">Can be either SHA1 or MD5</param>
        /// <param name="PasswordIterations">Number of iterations to do</param>
        /// <param name="InitialVector">Needs to be 16 ASCII characters long</param>
        /// <param name="KeySize">Can be 128, 192, or 256</param>
        /// <returns>A decrypted string</returns>
        public static string Decrypt(string CipherText, string Password,
            string Salt = "Kosher", string HashAlgorithm = "SHA1",
            int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
            int KeySize = 256)
        {
            if (string.IsNullOrEmpty(CipherText))
                return "";
            byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
            byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
            byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
            PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
            byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
            var SymmetricKey = Aes.Create();
            SymmetricKey.Mode = CipherMode.CBC;
            byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
            int ByteCount = 0;
            using (ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes))
            {
                using (MemoryStream MemStream = new MemoryStream(CipherTextBytes))
                {
                    using (CryptoStream CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read))
                    {

                        ByteCount = CryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
                        MemStream.Close();
                        CryptoStream.Close();
                    }
                }
            }
            SymmetricKey.Clear();
            return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
        }

        #endregion
    }
}


0

精彩评论

暂无评论...
验证码 换一张
取 消