|  | @@ -5,28 +5,56 @@ using System.Text;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	/// <summary>
 | 
	
		
			
				|  |  | -	/// 
 | 
	
		
			
				|  |  | -	/// </summary>
 | 
	
		
			
				|  |  | -	public class AesCipher : BlockCipher
 | 
	
		
			
				|  |  | -	{
 | 
	
		
			
				|  |  | -		private const uint m1 = 0x80808080;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private const uint m2 = 0x7f7f7f7f;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private const uint m3 = 0x0000001b;
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -		private int _rounds;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint[,] _encryptionKey;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint[,] _decryptionKey;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint C0, C1, C2, C3;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		#region Static Definition Tables
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private static readonly byte[] S =
 | 
	
		
			
				|  |  | +    /// <summary>
 | 
	
		
			
				|  |  | +    /// 
 | 
	
		
			
				|  |  | +    /// </summary>
 | 
	
		
			
				|  |  | +    public class AesCipher : BlockCipher
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        private const uint m1 = 0x80808080;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private const uint m2 = 0x7f7f7f7f;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private const uint m3 = 0x0000001b;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private int _rounds;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint[,] _encryptionKey;
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Gets the encryption key.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        protected uint[,] EncryptionKey
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (this._encryptionKey == null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    this._encryptionKey = this.GenerateWorkingKey(true, this.Key);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                return this._encryptionKey;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint[,] _decryptionKey;
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Gets the encryption key.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        protected uint[,] DecryptionKey
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (this._decryptionKey == null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    this._decryptionKey = this.GenerateWorkingKey(false, this.Key);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                return this._decryptionKey;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint C0, C1, C2, C3;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        #region Static Definition Tables
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static readonly byte[] S =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			99, 124, 119, 123, 242, 107, 111, 197,
 | 
	
		
			
				|  |  |  			48,   1, 103,  43, 254, 215, 171, 118,
 | 
	
	
		
			
				|  | @@ -62,8 +90,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			65, 153,  45,  15, 176,  84, 187,  22,
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		// The inverse S-box
 | 
	
		
			
				|  |  | -		private static readonly byte[] Si =
 | 
	
		
			
				|  |  | +        // The inverse S-box
 | 
	
		
			
				|  |  | +        private static readonly byte[] Si =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			82,   9, 106, 213,  48,  54, 165,  56,
 | 
	
		
			
				|  |  |  			191,  64, 163, 158, 129, 243, 215, 251,
 | 
	
	
		
			
				|  | @@ -99,15 +127,15 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			225, 105,  20,  99,  85,  33,  12, 125,
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		// vector used in calculating key schedule (powers of x in GF(256))
 | 
	
		
			
				|  |  | -		private static readonly byte[] rcon =
 | 
	
		
			
				|  |  | +        // vector used in calculating key schedule (powers of x in GF(256))
 | 
	
		
			
				|  |  | +        private static readonly byte[] rcon =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
 | 
	
		
			
				|  |  |  			0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		// precomputation tables of calculations for rounds
 | 
	
		
			
				|  |  | -		private static readonly uint[] T0 =
 | 
	
		
			
				|  |  | +        // precomputation tables of calculations for rounds
 | 
	
		
			
				|  |  | +        private static readonly uint[] T0 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
 | 
	
		
			
				|  |  |  			0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
 | 
	
	
		
			
				|  | @@ -163,7 +191,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x3a16162c
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] T1 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] T1 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
 | 
	
		
			
				|  |  |  			0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
 | 
	
	
		
			
				|  | @@ -219,7 +247,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x16162c3a
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] T2 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] T2 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
 | 
	
		
			
				|  |  |  			0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
 | 
	
	
		
			
				|  | @@ -275,7 +303,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x162c3a16
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] T3 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] T3 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
 | 
	
		
			
				|  |  |  			0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
 | 
	
	
		
			
				|  | @@ -331,7 +359,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x2c3a1616
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] Tinv0 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] Tinv0 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
 | 
	
		
			
				|  |  |  			0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
 | 
	
	
		
			
				|  | @@ -387,7 +415,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x4257b8d0
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] Tinv1 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] Tinv1 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
 | 
	
		
			
				|  |  |  			0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
 | 
	
	
		
			
				|  | @@ -443,7 +471,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0x57b8d042
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] Tinv2 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] Tinv2 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
 | 
	
		
			
				|  |  |  			0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
 | 
	
	
		
			
				|  | @@ -499,7 +527,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0xb8d04257
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		private static readonly uint[] Tinv3 =
 | 
	
		
			
				|  |  | +        private static readonly uint[] Tinv3 =
 | 
	
		
			
				|  |  |  		{
 | 
	
		
			
				|  |  |  			0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
 | 
	
		
			
				|  |  |  			0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
 | 
	
	
		
			
				|  | @@ -555,292 +583,267 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 | 
	
		
			
				|  |  |  			0xd04257b8
 | 
	
		
			
				|  |  |  		};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		#endregion
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/// <summary>
 | 
	
		
			
				|  |  | -		/// Gets the size of the block in bytes.
 | 
	
		
			
				|  |  | -		/// </summary>
 | 
	
		
			
				|  |  | -		/// <value>
 | 
	
		
			
				|  |  | -		/// The size of the block in bytes.
 | 
	
		
			
				|  |  | -		/// </value>
 | 
	
		
			
				|  |  | -		public override int BlockSize
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			get { return 16; }
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/// <summary>
 | 
	
		
			
				|  |  | -		/// Initializes a new instance of the <see cref="AesCipher"/> class.
 | 
	
		
			
				|  |  | -		/// </summary>
 | 
	
		
			
				|  |  | -		/// <param name="key">The key.</param>
 | 
	
		
			
				|  |  | -		/// <param name="mode">The mode.</param>
 | 
	
		
			
				|  |  | -		/// <param name="padding">The padding.</param>
 | 
	
		
			
				|  |  | -		public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
 | 
	
		
			
				|  |  | -			: base(key, mode, padding)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			this._encryptionKey = this.GenerateWorkingKey(true, key);
 | 
	
		
			
				|  |  | -			this._decryptionKey = this.GenerateWorkingKey(false, key);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/// <summary>
 | 
	
		
			
				|  |  | -		/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
 | 
	
		
			
				|  |  | -		/// </summary>
 | 
	
		
			
				|  |  | -		/// <param name="inputBuffer">The input data to encrypt.</param>
 | 
	
		
			
				|  |  | -		/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="outputBuffer">The output to which to write encrypted data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 | 
	
		
			
				|  |  | -		/// <returns>
 | 
	
		
			
				|  |  | -		/// The number of bytes encrypted.
 | 
	
		
			
				|  |  | -		/// </returns>
 | 
	
		
			
				|  |  | -		public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			if ((inputOffset + (32 / 2)) > inputBuffer.Length)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				throw new IndexOutOfRangeException("input buffer too short");
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if ((outputOffset + (32 / 2)) > outputBuffer.Length)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				throw new IndexOutOfRangeException("output buffer too short");
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.UnPackBlock(inputBuffer, inputOffset);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.EncryptBlock(this._encryptionKey);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.PackBlock(outputBuffer, outputOffset);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return this.BlockSize;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/// <summary>
 | 
	
		
			
				|  |  | -		/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
 | 
	
		
			
				|  |  | -		/// </summary>
 | 
	
		
			
				|  |  | -		/// <param name="inputBuffer">The input data to decrypt.</param>
 | 
	
		
			
				|  |  | -		/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="outputBuffer">The output to which to write decrypted data.</param>
 | 
	
		
			
				|  |  | -		/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 | 
	
		
			
				|  |  | -		/// <returns>
 | 
	
		
			
				|  |  | -		/// The number of bytes decrypted.
 | 
	
		
			
				|  |  | -		/// </returns>
 | 
	
		
			
				|  |  | -		public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			if ((inputOffset + (32 / 2)) > inputBuffer.Length)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				throw new IndexOutOfRangeException("input buffer too short");
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if ((outputOffset + (32 / 2)) > outputBuffer.Length)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				throw new IndexOutOfRangeException("output buffer too short");
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.UnPackBlock(inputBuffer, inputOffset);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.DecryptBlock(this._decryptionKey);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			this.PackBlock(outputBuffer, outputOffset);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return this.BlockSize;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/// <summary>
 | 
	
		
			
				|  |  | -		/// Validates the size of the key.
 | 
	
		
			
				|  |  | -		/// </summary>
 | 
	
		
			
				|  |  | -		/// <param name="keySize">Size of the key.</param>
 | 
	
		
			
				|  |  | -		/// <returns>
 | 
	
		
			
				|  |  | -		/// true if keySize is valid; otherwise false
 | 
	
		
			
				|  |  | -		/// </returns>
 | 
	
		
			
				|  |  | -		protected override bool ValidateKeySize(int keySize)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			if (keySize == 256 ||
 | 
	
		
			
				|  |  | -				keySize == 192 ||
 | 
	
		
			
				|  |  | -				keySize == 128)
 | 
	
		
			
				|  |  | -				return true;
 | 
	
		
			
				|  |  | -			else
 | 
	
		
			
				|  |  | -				return false;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint[,] GenerateWorkingKey(bool isEncryption, byte[] key)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			int KC = key.Length / 4;  // key length in words
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
 | 
	
		
			
				|  |  | -				throw new ArgumentException("Key length not 128/192/256 bits.");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			_rounds = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
 | 
	
		
			
				|  |  | -			uint[,] W = new uint[_rounds + 1, 4];   // 4 words in a block
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			//
 | 
	
		
			
				|  |  | -			// copy the key into the round key array
 | 
	
		
			
				|  |  | -			//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			int t = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			for (int i = 0; i < key.Length; t++)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				W[t >> 2, t & 3] = LittleEndianToUInt32(key, i);
 | 
	
		
			
				|  |  | -				i += 4;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			//
 | 
	
		
			
				|  |  | -			// while not enough round key material calculated
 | 
	
		
			
				|  |  | -			// calculate new values
 | 
	
		
			
				|  |  | -			//
 | 
	
		
			
				|  |  | -			int k = (_rounds + 1) << 2;
 | 
	
		
			
				|  |  | -			for (int i = KC; (i < k); i++)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				uint temp = W[(i - 1) >> 2, (i - 1) & 3];
 | 
	
		
			
				|  |  | -				if ((i % KC) == 0)
 | 
	
		
			
				|  |  | -				{
 | 
	
		
			
				|  |  | -					temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC) - 1];
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				else if ((KC > 6) && ((i % KC) == 4))
 | 
	
		
			
				|  |  | -				{
 | 
	
		
			
				|  |  | -					temp = SubWord(temp);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				W[i >> 2, i & 3] = W[(i - KC) >> 2, (i - KC) & 3] ^ temp;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if (!isEncryption)
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				for (int j = 1; j < _rounds; j++)
 | 
	
		
			
				|  |  | -				{
 | 
	
		
			
				|  |  | -					for (int i = 0; i < 4; i++)
 | 
	
		
			
				|  |  | -					{
 | 
	
		
			
				|  |  | -						W[j, i] = InvMcol(W[j, i]);
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return W;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint Shift(uint r, int shift)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			return (r >> shift) | (r << (32 - shift));
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint FFmulX(uint x)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		/*
 | 
	
		
			
				|  |  | -		The following defines provide alternative definitions of FFmulX that might
 | 
	
		
			
				|  |  | -		give improved performance if a fast 32-bit multiply is not available.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
 | 
	
		
			
				|  |  | -		private static final int  m4 = 0x1b1b1b1b;
 | 
	
		
			
				|  |  | -		private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		*/
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint InvMcol(uint x)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			uint f2 = FFmulX(x);
 | 
	
		
			
				|  |  | -			uint f4 = FFmulX(f2);
 | 
	
		
			
				|  |  | -			uint f8 = FFmulX(f4);
 | 
	
		
			
				|  |  | -			uint f9 = x ^ f8;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private uint SubWord(uint x)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			return (uint)S[x & 255]
 | 
	
		
			
				|  |  | -				| (((uint)S[(x >> 8) & 255]) << 8)
 | 
	
		
			
				|  |  | -				| (((uint)S[(x >> 16) & 255]) << 16)
 | 
	
		
			
				|  |  | -				| (((uint)S[(x >> 24) & 255]) << 24);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private void UnPackBlock(byte[] bytes, int off)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			C0 = LittleEndianToUInt32(bytes, off);
 | 
	
		
			
				|  |  | -			C1 = LittleEndianToUInt32(bytes, off + 4);
 | 
	
		
			
				|  |  | -			C2 = LittleEndianToUInt32(bytes, off + 8);
 | 
	
		
			
				|  |  | -			C3 = LittleEndianToUInt32(bytes, off + 12);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private void PackBlock(byte[] bytes, int off)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			UInt32ToLittleEndian(C0, bytes, off);
 | 
	
		
			
				|  |  | -			UInt32ToLittleEndian(C1, bytes, off + 4);
 | 
	
		
			
				|  |  | -			UInt32ToLittleEndian(C2, bytes, off + 8);
 | 
	
		
			
				|  |  | -			UInt32ToLittleEndian(C3, bytes, off + 12);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private void EncryptBlock(uint[,] KW)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			int r;
 | 
	
		
			
				|  |  | -			uint r0, r1, r2, r3;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			C0 ^= KW[0, 0];
 | 
	
		
			
				|  |  | -			C1 ^= KW[0, 1];
 | 
	
		
			
				|  |  | -			C2 ^= KW[0, 2];
 | 
	
		
			
				|  |  | -			C3 ^= KW[0, 3];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			for (r = 1; r < _rounds - 1; )
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -				r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -				r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -				r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | -				C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -				C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -				C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -				C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -			r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -			r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -			r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			// the final round's table is a simple function of S so we don't use a whole other four tables for it
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[r, 0];
 | 
	
		
			
				|  |  | -			C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[r, 1];
 | 
	
		
			
				|  |  | -			C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[r, 2];
 | 
	
		
			
				|  |  | -			C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[r, 3];
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		private void DecryptBlock(uint[,] KW)
 | 
	
		
			
				|  |  | -		{
 | 
	
		
			
				|  |  | -			int r;
 | 
	
		
			
				|  |  | -			uint r0, r1, r2, r3;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			C0 ^= KW[_rounds, 0];
 | 
	
		
			
				|  |  | -			C1 ^= KW[_rounds, 1];
 | 
	
		
			
				|  |  | -			C2 ^= KW[_rounds, 2];
 | 
	
		
			
				|  |  | -			C3 ^= KW[_rounds, 3];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			for (r = _rounds - 1; r > 1; )
 | 
	
		
			
				|  |  | -			{
 | 
	
		
			
				|  |  | -				r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -				r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -				r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -				r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r--, 3];
 | 
	
		
			
				|  |  | -				C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -				C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -				C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -				C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[r--, 3];
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | -			r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | -			r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | -			r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r, 3];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			// the final round's table is a simple function of Si so we don't use a whole other four tables for it
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[0, 0];
 | 
	
		
			
				|  |  | -			C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[0, 1];
 | 
	
		
			
				|  |  | -			C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0, 2];
 | 
	
		
			
				|  |  | -			C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0, 3];
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | +        #endregion
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Gets the size of the block in bytes.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <value>
 | 
	
		
			
				|  |  | +        /// The size of the block in bytes.
 | 
	
		
			
				|  |  | +        /// </value>
 | 
	
		
			
				|  |  | +        public override int BlockSize
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get { return 16; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Initializes a new instance of the <see cref="AesCipher"/> class.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="key">The key.</param>
 | 
	
		
			
				|  |  | +        /// <param name="mode">The mode.</param>
 | 
	
		
			
				|  |  | +        /// <param name="padding">The padding.</param>
 | 
	
		
			
				|  |  | +        public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
 | 
	
		
			
				|  |  | +            : base(key, mode, padding)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var keySize = key.Length * 8;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!(keySize == 256 || keySize == 192 || keySize == 128))
 | 
	
		
			
				|  |  | +                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="inputBuffer">The input data to encrypt.</param>
 | 
	
		
			
				|  |  | +        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="outputBuffer">The output to which to write encrypted data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 | 
	
		
			
				|  |  | +        /// <returns>
 | 
	
		
			
				|  |  | +        /// The number of bytes encrypted.
 | 
	
		
			
				|  |  | +        /// </returns>
 | 
	
		
			
				|  |  | +        public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if ((inputOffset + (32 / 2)) > inputBuffer.Length)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new IndexOutOfRangeException("input buffer too short");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if ((outputOffset + (32 / 2)) > outputBuffer.Length)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new IndexOutOfRangeException("output buffer too short");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.UnPackBlock(inputBuffer, inputOffset);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.EncryptBlock(this.EncryptionKey);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.PackBlock(outputBuffer, outputOffset);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return this.BlockSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="inputBuffer">The input data to decrypt.</param>
 | 
	
		
			
				|  |  | +        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="outputBuffer">The output to which to write decrypted data.</param>
 | 
	
		
			
				|  |  | +        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 | 
	
		
			
				|  |  | +        /// <returns>
 | 
	
		
			
				|  |  | +        /// The number of bytes decrypted.
 | 
	
		
			
				|  |  | +        /// </returns>
 | 
	
		
			
				|  |  | +        public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if ((inputOffset + (32 / 2)) > inputBuffer.Length)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new IndexOutOfRangeException("input buffer too short");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if ((outputOffset + (32 / 2)) > outputBuffer.Length)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new IndexOutOfRangeException("output buffer too short");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.UnPackBlock(inputBuffer, inputOffset);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.DecryptBlock(this.DecryptionKey);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            this.PackBlock(outputBuffer, outputOffset);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return this.BlockSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint[,] GenerateWorkingKey(bool isEncryption, byte[] key)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            int KC = key.Length / 4;  // key length in words
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
 | 
	
		
			
				|  |  | +                throw new ArgumentException("Key length not 128/192/256 bits.");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            _rounds = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
 | 
	
		
			
				|  |  | +            uint[,] W = new uint[_rounds + 1, 4];   // 4 words in a block
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //
 | 
	
		
			
				|  |  | +            // copy the key into the round key array
 | 
	
		
			
				|  |  | +            //
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            int t = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for (int i = 0; i < key.Length; t++)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                W[t >> 2, t & 3] = LittleEndianToUInt32(key, i);
 | 
	
		
			
				|  |  | +                i += 4;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //
 | 
	
		
			
				|  |  | +            // while not enough round key material calculated
 | 
	
		
			
				|  |  | +            // calculate new values
 | 
	
		
			
				|  |  | +            //
 | 
	
		
			
				|  |  | +            int k = (_rounds + 1) << 2;
 | 
	
		
			
				|  |  | +            for (int i = KC; (i < k); i++)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                uint temp = W[(i - 1) >> 2, (i - 1) & 3];
 | 
	
		
			
				|  |  | +                if ((i % KC) == 0)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC) - 1];
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if ((KC > 6) && ((i % KC) == 4))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    temp = SubWord(temp);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                W[i >> 2, i & 3] = W[(i - KC) >> 2, (i - KC) & 3] ^ temp;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!isEncryption)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                for (int j = 1; j < _rounds; j++)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < 4; i++)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        W[j, i] = InvMcol(W[j, i]);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return W;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint Shift(uint r, int shift)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return (r >> shift) | (r << (32 - shift));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint FFmulX(uint x)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint InvMcol(uint x)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            uint f2 = FFmulX(x);
 | 
	
		
			
				|  |  | +            uint f4 = FFmulX(f2);
 | 
	
		
			
				|  |  | +            uint f8 = FFmulX(f4);
 | 
	
		
			
				|  |  | +            uint f9 = x ^ f8;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private uint SubWord(uint x)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return (uint)S[x & 255]
 | 
	
		
			
				|  |  | +                | (((uint)S[(x >> 8) & 255]) << 8)
 | 
	
		
			
				|  |  | +                | (((uint)S[(x >> 16) & 255]) << 16)
 | 
	
		
			
				|  |  | +                | (((uint)S[(x >> 24) & 255]) << 24);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void UnPackBlock(byte[] bytes, int off)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            C0 = LittleEndianToUInt32(bytes, off);
 | 
	
		
			
				|  |  | +            C1 = LittleEndianToUInt32(bytes, off + 4);
 | 
	
		
			
				|  |  | +            C2 = LittleEndianToUInt32(bytes, off + 8);
 | 
	
		
			
				|  |  | +            C3 = LittleEndianToUInt32(bytes, off + 12);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void PackBlock(byte[] bytes, int off)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            UInt32ToLittleEndian(C0, bytes, off);
 | 
	
		
			
				|  |  | +            UInt32ToLittleEndian(C1, bytes, off + 4);
 | 
	
		
			
				|  |  | +            UInt32ToLittleEndian(C2, bytes, off + 8);
 | 
	
		
			
				|  |  | +            UInt32ToLittleEndian(C3, bytes, off + 12);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void EncryptBlock(uint[,] KW)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            int r;
 | 
	
		
			
				|  |  | +            uint r0, r1, r2, r3;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            C0 ^= KW[0, 0];
 | 
	
		
			
				|  |  | +            C1 ^= KW[0, 1];
 | 
	
		
			
				|  |  | +            C2 ^= KW[0, 2];
 | 
	
		
			
				|  |  | +            C3 ^= KW[0, 3];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for (r = 1; r < _rounds - 1; )
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +                r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +                r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +                r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | +                C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +                C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +                C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +                C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +            r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +            r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +            r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++, 3];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // the final round's table is a simple function of S so we don't use a whole other four tables for it
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[r, 0];
 | 
	
		
			
				|  |  | +            C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[r, 1];
 | 
	
		
			
				|  |  | +            C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[r, 2];
 | 
	
		
			
				|  |  | +            C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[r, 3];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void DecryptBlock(uint[,] KW)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            int r;
 | 
	
		
			
				|  |  | +            uint r0, r1, r2, r3;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            C0 ^= KW[_rounds, 0];
 | 
	
		
			
				|  |  | +            C1 ^= KW[_rounds, 1];
 | 
	
		
			
				|  |  | +            C2 ^= KW[_rounds, 2];
 | 
	
		
			
				|  |  | +            C3 ^= KW[_rounds, 3];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for (r = _rounds - 1; r > 1; )
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +                r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +                r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +                r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r--, 3];
 | 
	
		
			
				|  |  | +                C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +                C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +                C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +                C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[r--, 3];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r, 0];
 | 
	
		
			
				|  |  | +            r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r, 1];
 | 
	
		
			
				|  |  | +            r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r, 2];
 | 
	
		
			
				|  |  | +            r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r, 3];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // the final round's table is a simple function of Si so we don't use a whole other four tables for it
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[0, 0];
 | 
	
		
			
				|  |  | +            C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[0, 1];
 | 
	
		
			
				|  |  | +            C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0, 2];
 | 
	
		
			
				|  |  | +            C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0, 3];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 |