⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clsaes.cs

📁 AES 128/192位加密算法,可与C++加密算法共用
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.Windows.Forms;

namespace AES
{
	/// <summary>
	/// Performs AES (Advanced Encryption Standard) cryptography
	/// see: http://msdn.microsoft.com/msdnmag/issues/03/11/AES/
	/// </summary>
	public class clsAES
	{
		public enum KeySize { Bits128, Bits192, Bits256 };  // key size, in bits, for construtor

		private int Nb;         // block size in 32-bit words.  Always 4 for AES.  (128 bits).
		private int Nk;         // key size in 32-bit words.  4, 6, 8.  (128, 192, 256 bits).
		private int Nr;         // number of rounds. 10, 12, 14.

		private byte[] key;     // the seed key. size will be 4 * keySize from ctor.
		private byte[,] Sbox;   // Substitution box
		private byte[,] iSbox;  // inverse Substitution box 
		private byte[,] w;      // key schedule array. 
		private byte[,] Rcon;   // Round constants.
		private byte[,] State;  // State matrix

		private const int BlockSize = 16; // block size for encrypt and decrypt. should always be 16

		#region Initialize

		/// <summary>
		/// Initializes the AES engine
		/// </summary>
		/// <param name="keySize">Size of the key</param>
		/// <param name="Password">the password</param>
		public clsAES(KeySize keySize, string Password)
		{
			// convert the password to a byte array, then call the other init func
			byte[] keyBytes = ConvertStringToByteArray(Password);
			Init(keySize, keyBytes);
		}

		/// <summary>
		/// Initializes the AES engine
		/// </summary>
		/// <param name="keySize">Size of the key</param>
		/// <param name="keyBytes">the password, in a byte array</param>
		public clsAES(KeySize keySize, byte[] keyBytes)
		{
			Init(keySize, keyBytes);
		}  // Aes constructor

		private void Init(KeySize keySize, byte[] keyBytes)
		{
			int i = 0;
			int keyLen = 0, kbLen = 0;
			byte nextByte = 1;

			try
			{
				SetNbNkNr(keySize);
	 
				// set the key
				this.key = new byte[this.Nk * 4];  // 16, 24, 32 bytes

				// if the password is the right size, just copy the array
				if (this.key.Length == keyBytes.Length)
					keyBytes.CopyTo(this.key, 0);
				else // password is different size, so manually copy
				{
					// get the key lengths
					keyLen = this.key.Length;
					kbLen = keyBytes.Length;

					// manuually add the password
					for (i=0; i<keyLen; i++)
					{
						// make sure we can use the keyBytes
						if (i < kbLen)
							this.key[i] = keyBytes[i];
						else // we need to add some extra bytes
							this.key[i] = nextByte++;
					}
				}

				// build the two matrixes
				BuildSbox();
				BuildInvSbox();
				BuildRcon();
				KeyExpansion();  // expand the seed key into a key schedule and store in w
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Init"); }
		}

		#endregion // Initialize

		#region Public Encrypt and Decrypt

		/// <summary>
		/// Encrypts the input string
		/// </summary>
		/// <param name="input">the string to encrypt  -   
		/// Note: the base encryptiong algorithm uses a byte array, but it's not always
		/// possible to convert the byte array to a string, using a 1:1 conversion.
		/// Instead, we will convert each byte to a string, and add a space. So,
		/// when you are encrypting a string, the return result will always be larger
		/// in length than the original. When you are decrypting a string, the return
		/// result will always be smaller in length than the original encrypted string.
		/// </param>
		public string Encrypt(string input)
		{
			string rText = "";
			int i=0, sLen = 0;

			try
			{
				// convert the string to a byte
				byte[] bInput = ConvertStringToByteArray(input);

				// encrypt
				byte[] bText = Encrypt(bInput);

				// convert the byte array to a string
				sLen = bText.Length;
				for (i=0; i<sLen; i++)
					rText += bText[i].ToString().Trim() + " ";
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Encrypt"); }

			// return the text
			return rText.Trim();
		}

		/// <summary>
		/// Encrypts the input byte array
		/// </summary>
		/// <param name="input">the byte array to encrypt</param>
		public byte[] Encrypt(byte[] input)
		{
			int i=0, iLen = input.Length;
			byte[] output = new byte[0];
			byte[] newInput;
			byte[] inBuffer = new byte[BlockSize];
			byte[] buffer = new byte[BlockSize];
			int count=0;

			try
			{
				// we need to resize the arrays so they are 16 byte blocks
				count = GetArraySize(input.Length);
				output = new byte[count];
				newInput = new byte[count];

				// copy the data from input to newInput
				System.Array.Copy(input, 0, newInput, 0, input.Length);

				// we need to send the cipher function 16 bytes at a time to encrypt
				for (i=0; i<iLen; i= i + BlockSize)
				{
					// copy the input into the input buffer array
					System.Array.Copy(newInput, i, inBuffer, 0, BlockSize); // copy all 16 bytes

					// encrypt this block
					System.Array.Copy( Cipher(inBuffer), 0, output, i, BlockSize);
				}
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Encrypt"); }

			// return the byte array
			return output;
		}

		/// <summary>
		/// Decrypts the input string
		/// </summary>
		/// <param name="input">the string to decrypt  -  
		/// Note: the base encryption algorithm uses a byte array, but it's not always
		/// possible to convert the byte array to a string, using a 1:1 conversion.
		/// Instead, we converted each byte to a string, and added a space. So,
		/// when you are encrypting a string, the return result will always be larger
		/// in length than the original. When you are decrypting a string, the return
		/// result will always be smaller in length than the original encrypted string.
		/// </param>
		public string Decrypt(string input)
		{
			string rText = "";
			int i=0, sLen = 0;

			try
			{
				// convert the string to a byte array
				string[] tByte = input.Split(' ');
				sLen = tByte.Length;
				byte[] bInput = new byte[sLen];
				for (i=0; i<sLen; i++)
					bInput[i] = System.Convert.ToByte(tByte[i]);

				// decrypt and convert to the byte array to a string
				rText = ConvertByteArrayToString( Decrypt(bInput));
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Decrypt"); }

			// return
			return rText;
		}

		/// <summary>
		/// Decrypts the input byte array
		/// </summary>
		/// <param name="input">the byte array to decrypt</param>
		public byte[] Decrypt(byte[] input)
		{
			int i=0, iLen = input.Length;
			byte[] inBuffer = new byte[BlockSize];
			byte[] buffer = new byte[BlockSize];
			byte[] output = new byte[input.Length];
			int count=0;

			try
			{
				// we need to send the cipher function 16 bytes at a time to encrypt
				for (i=0; i<iLen; i= i + BlockSize)
				{
					// copy the input into the input buffer array
					System.Array.Copy(input, i, inBuffer, 0, BlockSize); // copy all 16 bytes

					// decrypt this block
					System.Array.Copy( InvCipher(inBuffer), 0, output, i, BlockSize);
				}
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Decrypt"); }

			// return the byte array
			return output;
		}

		#endregion // Public Encrypt and Decrypt

		#region Private Encrypt and Decrypt

		/// <summary>
		/// Encrypt the data in a 16 bit block. returns:
		/// 16 byte block of encrypted characters
		/// </summary>
		/// <param name="input">16 byte block of characters to encrypt</param>
		/// <param name="retCount">the number of bytes actually used</param>
		/// <returns>16 byte block of encrypted characters</returns>
		private byte[] Cipher(byte[] input)  // encipher 16-bit input
		{
			byte[] output = new byte[16];

			try
			{
				// state = input
				this.State = new byte[4,Nb];  // always [4,4]
				for (int i = 0; i < (4 * Nb); ++i)
				{
					this.State[i % 4, i / 4] = input[i];
				}

				AddRoundKey(0);
	          
				for (int round = 1; round <= (Nr - 1); ++round)  // main round loop
				{
					SubBytes(); 
					ShiftRows();  
					MixColumns(); 
					AddRoundKey(round);
				}  // main round loop

				SubBytes();
				ShiftRows();
				AddRoundKey(Nr);
	            
				// output = state
				for (int i = 0; i < (4 * Nb); ++i)
				{
					output[i] = this.State[i % 4, i / 4];
				}
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "Cipher"); }

			return output;
		}  // Cipher()

		/// <summary>
		/// Decrypts a 16 byte block of text
		/// </summary>
		/// <param name="input">16 byte block to decrypt</param>
		/// <returns>16 byte block of decrypted bytes</returns>
		private byte[] InvCipher(byte[] input)  // decipher 16-bit input
		{
			byte[] output = new byte[16];

			try
			{
				// state = input
				this.State = new byte[4,Nb];  // always [4,4]
				for (int i = 0; i < (4 * Nb); ++i)
				{
					this.State[i % 4, i / 4] = input[i];
				}

				AddRoundKey(Nr);
	      
				for (int round = Nr-1; round >= 1; --round)  // main round loop
				{
					InvShiftRows();
					InvSubBytes();
					AddRoundKey(round);
					InvMixColumns();
				}  // end main round loop for InvCipher

				InvShiftRows();
				InvSubBytes();
				AddRoundKey(0);

				// output = state
				for (int i = 0; i < (4 * Nb); ++i)
				{
					output[i] = this.State[i % 4, i / 4];
				}
			}

			catch (Exception excep)
			{ AES_ShowError(excep, "InvCipher"); }

			return output;
		}  // InvCipher()

		#endregion // Private Encrypt and Decrypt

		#region AES Tables and Work Body

		private void SetNbNkNr(KeySize keySize)
		{
			this.Nb = 4;     // block size always = 4 words = 16 bytes = 128 bits for AES

			if (keySize == KeySize.Bits128)
			{
				this.Nk = 4;   // key size = 4 words = 16 bytes = 128 bits
				this.Nr = 10;  // rounds for algorithm = 10
			}
			else if (keySize == KeySize.Bits192)
			{
				this.Nk = 6;   // 6 words = 24 bytes = 192 bits
				this.Nr = 12;
			}
			else if (keySize == KeySize.Bits256)
			{
				this.Nk = 8;   // 8 words = 32 bytes = 256 bits
				this.Nr = 14;
			}
		}  // SetNbNkNr()

		private void BuildSbox()
		{
			this.Sbox = new byte[16,16] {  // populate the Sbox matrix
											/* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */
											/*0*/  {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
											/*1*/  {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
											/*2*/  {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
											/*3*/  {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
											/*4*/  {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
											/*5*/  {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
											/*6*/  {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
											/*7*/  {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
											/*8*/  {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
											/*9*/  {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
											/*a*/  {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
											/*b*/  {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
											/*c*/  {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -