2
0
Эх сурвалжийг харах

Fix CA2214 and some other CA complaints
Fix some comments
Fix DownloadFile hang error introduced in previouse check in

olegkap_cp 14 жил өмнө
parent
commit
dbd5f07d20
22 өөрчлөгдсөн 917 нэмэгдсэн , 677 устгасан
  1. 1 1
      Renci.SshClient/Renci.SshNet/Common/DerData.cs
  2. 4 13
      Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs
  3. 326 323
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs
  4. 0 12
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs
  5. 5 15
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs
  6. 7 17
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs
  7. 31 26
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs
  8. 5 15
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs
  9. 61 42
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs
  10. 13 27
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs
  11. 56 1
      Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs
  12. 99 43
      Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs
  13. 49 34
      Renci.SshClient/Renci.SshNet/Security/Cryptography/HMAC.cs
  14. 6 1
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs
  15. 19 15
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs
  16. 21 17
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs
  17. 6 9
      Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs
  18. 68 2
      Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
  19. 131 39
      Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs
  20. 3 22
      Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs
  21. 4 2
      Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs
  22. 2 1
      Renci.SshClient/Renci.SshNet/SftpClient.cs

+ 1 - 1
Renci.SshClient/Renci.SshNet/Common/DerData.cs

@@ -194,7 +194,7 @@ namespace Renci.SshNet.Common
         /// <summary>
         /// Writes OBJECTIDENTIFIER data into internal buffer.
         /// </summary>
-        /// <param name="identifiers">The identifiers.</param>
+        /// <param name="identifier">The identifier.</param>
         public void Write(ObjectIdentifier identifier)
         {
             var temp = new ulong[identifier.Identifiers.Length - 1];

+ 4 - 13
Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs

@@ -10,10 +10,8 @@ namespace Renci.SshNet.Security.Cryptography
     /// <summary>
     /// Implements digital signature where where asymmetric cipher is used,
     /// </summary>
-    public class CipherDigitalSignature : DigitalSignature
+    public abstract class CipherDigitalSignature : DigitalSignature
     {
-        private HashAlgorithm _hash;
-
         private AsymmetricCipher _cipher;
 
         private ObjectIdentifier _oid;
@@ -21,17 +19,13 @@ namespace Renci.SshNet.Security.Cryptography
         /// <summary>
         /// Initializes a new instance of the <see cref="CipherDigitalSignature"/> class.
         /// </summary>
-        /// <param name="hash">The hash.</param>
+        /// <param name="oid">The object identifier.</param>
         /// <param name="cipher">The cipher.</param>
-        public CipherDigitalSignature(HashAlgorithm hash, ObjectIdentifier oid, AsymmetricCipher cipher)
+        public CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher)
         {
-            if (hash == null)
-                throw new ArgumentNullException("hash");
-
             if (cipher == null)
                 throw new ArgumentNullException("cipher");
 
-            this._hash = hash;
             this._cipher = cipher;
             this._oid = oid;
         }
@@ -104,10 +98,7 @@ namespace Renci.SshNet.Security.Cryptography
         /// </summary>
         /// <param name="input">The input.</param>
         /// <returns></returns>
-        protected byte[] Hash(byte[] input)
-        {
-            return this._hash.ComputeHash(input);
-        }
+        protected abstract byte[] Hash(byte[] input);
 
         /// <summary>
         /// Encodes hash using DER.

+ 326 - 323
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs

@@ -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];
+        }
+
+    }
 }

+ 0 - 12
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs

@@ -71,17 +71,5 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
         {
             throw new NotImplementedException();
         }
-
-        /// <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)
-        {
-            throw new NotImplementedException();
-        }
     }
 }

+ 5 - 15
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs

@@ -318,6 +318,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 		public BlowfishCipher(byte[] key, CipherMode mode, CipherPadding padding)
 			: base(key, mode, padding)
 		{
+			var keySize = key.Length * 8;
+
+			if (keySize < 1 || keySize > 448)
+				throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+
 			//  TODO:   Refactor this algorithm
 
 			S0 = new uint[SBOX_SK];
@@ -399,21 +404,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 			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 >= 1 && keySize <= 448)
-				return true;
-			else
-				return false;
-		}
-
 		private uint F(uint x)
 		{
 			return (((S0[x >> 24] + S1[(x >> 16) & 0xff]) ^ S2[(x >> 8) & 0xff]) + S3[x & 0xff]);

+ 7 - 17
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs

@@ -36,8 +36,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
         /// <param name="mode">The mode.</param>
         /// <param name="padding">The padding.</param>
         public CastCipher(byte[] key, CipherMode mode, CipherPadding padding)
-			: base(key, mode, padding)
-		{
+            : base(key, mode, padding)
+        {
+            var keySize = key.Length * 8;
+
+            if (!(keySize >= 40 && keySize <= 128 && keySize % 8 == 0))
+                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+
             //  TODO:   Refactor this algorithm
             this.SetKey(key);
         }
@@ -101,21 +106,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             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 >= 40 && keySize <= 128 && keySize % 8 == 0)
-                return true;
-            else
-                return false;
-        }
-
         #region Static Definition Tables
 
         internal static readonly uint[] S1 =

+ 31 - 26
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs

@@ -10,9 +10,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
     /// </summary>
 	public class DesCipher : BlockCipher
 	{
-		private readonly int[] _encryptionKey;
+		private int[] _encryptionKey;
 
-		private readonly int[] _decryptionKey;
+		private int[] _decryptionKey;
 
 		/// <summary>
 		/// Gets the size of the block in bytes.
@@ -238,8 +238,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 		public DesCipher(byte[] key, CipherMode mode, CipherPadding padding)
 			: base(key, mode, padding)
 		{
-			this._encryptionKey = GenerateWorkingKey(true, key);
-			this._decryptionKey = GenerateWorkingKey(false, key);
 		}
 
 		/// <summary>
@@ -261,6 +259,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 			if ((outputOffset + this.BlockSize) > outputBuffer.Length)
 				throw new IndexOutOfRangeException("output buffer too short");
 
+            if (this._encryptionKey == null)
+            {
+                this._encryptionKey = GenerateWorkingKey(true, this.Key);
+            }
+
 			DesCipher.DesFunc(this._encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
 
 			return this.BlockSize;
@@ -285,25 +288,14 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 			if ((outputOffset + this.BlockSize) > outputBuffer.Length)
 				throw new IndexOutOfRangeException("output buffer too short");
 
+            if (this._decryptionKey == null)
+            {
+                this._decryptionKey = GenerateWorkingKey(false, this.Key);
+            }
+
 			DesCipher.DesFunc(this._decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
 
 			return this.BlockSize;
-			throw new NotImplementedException();
-		}
-
-        /// <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 == 64)
-				return true;
-			else
-				return false;
 		}
 
 		/// <summary>
@@ -312,8 +304,10 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 		/// <param name="encrypting">if set to <c>true</c> [encrypting].</param>
 		/// <param name="key">The key.</param>
 		/// <returns></returns>
-		protected static int[] GenerateWorkingKey(bool encrypting, byte[] key)
+		protected int[] GenerateWorkingKey(bool encrypting, byte[] key)
 		{
+            this.ValidateKey();
+
 			int[] newKey = new int[32];
 			bool[] pc1m = new bool[56];
 			bool[] pcr = new bool[56];
@@ -391,22 +385,33 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 				i1 = newKey[i];
 				i2 = newKey[i + 1];
 
-				newKey[i] = (int)((uint)((i1 & 0x00fc0000) << 6) |
+				newKey[i] = (int)  ((uint)((i1 & 0x00fc0000) << 6) |
 									(uint)((i1 & 0x00000fc0) << 10) |
 									((uint)(i2 & 0x00fc0000) >> 10) |
 									((uint)(i2 & 0x00000fc0) >> 6));
 
 				newKey[i + 1] = (int)((uint)((i1 & 0x0003f000) << 12) |
-										(uint)((i1 & 0x0000003f) << 16) |
-										((uint)(i2 & 0x0003f000) >> 4) |
-										(uint)(i2 & 0x0000003f));
+									  (uint)((i1 & 0x0000003f) << 16) |
+									  ((uint)(i2 & 0x0003f000) >> 4) |
+									   (uint)(i2 & 0x0000003f));
 			}
 
 			return newKey;
 		}
 
+        /// <summary>
+        /// Validates the key.
+        /// </summary>
+        protected virtual void ValidateKey()
+        {
+            var keySize = this.Key.Length * 8;
+            
+            if (!(keySize == 64))
+                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+        }
+
 		/// <summary>
-		/// Perfoms DES function.
+		/// Performs DES function.
 		/// </summary>
 		/// <param name="wKey">The w key.</param>
 		/// <param name="input">The input.</param>

+ 5 - 15
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs

@@ -39,6 +39,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 		{
 			//  TODO:   Refactor this algorithm
 
+            var keySize = key.Length * 8;
+
+            if (!(keySize == 128 || keySize == 192 || keySize == 256))
+                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+
 			this._workingKey = this.MakeWorkingKey(key);
 		}
 
@@ -197,21 +202,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 			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 == 128 || keySize == 192 || keySize == 256)
-				return true;
-			else
-				return false;
-		}
-
 		/**
 		* Expand a user-supplied key material into a session key.
 		*

+ 61 - 42
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs

@@ -10,13 +10,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
     /// </summary>
     public class TripleDesCipher : DesCipher
     {
-        private readonly int[] _encryptionKey1;
-        private readonly int[] _encryptionKey2;
-        private readonly int[] _encryptionKey3;
+        private int[] _encryptionKey1;
+        private int[] _encryptionKey2;
+        private int[] _encryptionKey3;
 
-        private readonly int[] _decryptionKey1;
-        private readonly int[] _decryptionKey2;
-        private readonly int[] _decryptionKey3;
+        private int[] _decryptionKey1;
+        private int[] _decryptionKey2;
+        private int[] _decryptionKey3;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TripleDesCipher"/> class.
@@ -27,32 +27,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
         public TripleDesCipher(byte[] key, CipherMode mode, CipherPadding padding)
             : base(key, mode, padding)
         {
-            var part1 = new byte[8];
-            var part2 = new byte[8];
-
-            Array.Copy(key, 0, part1, 0, 8);
-            Array.Copy(key, 8, part2, 0, 8);
-
-            this._encryptionKey1 = GenerateWorkingKey(true, part1);
-            this._decryptionKey1 = GenerateWorkingKey(false, part1);
-
-            this._encryptionKey2 = GenerateWorkingKey(false, part2);
-            this._decryptionKey2 = GenerateWorkingKey(true, part2);
-
-            if (key.Length == 24)
-            {
-                var part3 = new byte[8];
-                Array.Copy(key, 16, part3, 0, 8);
-
-                this._encryptionKey3 = GenerateWorkingKey(true, part3);
-                this._decryptionKey3 = GenerateWorkingKey(false, part3);
-            }
-            else
-            {
-                this._encryptionKey3 = this._encryptionKey1;
-                this._decryptionKey3 = this._decryptionKey1;
-            }
-
         }
 
         /// <summary>
@@ -74,6 +48,31 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             if ((outputOffset + this.BlockSize) > outputBuffer.Length)
                 throw new IndexOutOfRangeException("output buffer too short");
 
+            if (this._encryptionKey1 == null || this._encryptionKey2 == null || this._encryptionKey3 == null)
+            {
+                var part1 = new byte[8];
+                var part2 = new byte[8];
+
+                Array.Copy(this.Key, 0, part1, 0, 8);
+                Array.Copy(this.Key, 8, part2, 0, 8);
+
+                this._encryptionKey1 = this.GenerateWorkingKey(true, part1);
+
+                this._encryptionKey2 = this.GenerateWorkingKey(false, part2);
+
+                if (this.Key.Length == 24)
+                {
+                    var part3 = new byte[8];
+                    Array.Copy(this.Key, 16, part3, 0, 8);
+
+                    this._encryptionKey3 = this.GenerateWorkingKey(true, part3);
+                }
+                else
+                {
+                    this._encryptionKey3 = this._encryptionKey1;
+                }
+            }
+
             byte[] temp = new byte[this.BlockSize];
 
             DesCipher.DesFunc(this._encryptionKey1, inputBuffer, inputOffset, temp, 0);
@@ -102,6 +101,30 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             if ((outputOffset + this.BlockSize) > outputBuffer.Length)
                 throw new IndexOutOfRangeException("output buffer too short");
 
+            if (this._decryptionKey1 == null || this._decryptionKey2 == null || this._decryptionKey3 == null)
+            {
+                var part1 = new byte[8];
+                var part2 = new byte[8];
+
+                Array.Copy(this.Key, 0, part1, 0, 8);
+                Array.Copy(this.Key, 8, part2, 0, 8);
+
+                this._decryptionKey1 = this.GenerateWorkingKey(false, part1);
+                this._decryptionKey2 = this.GenerateWorkingKey(true, part2);
+
+                if (this.Key.Length == 24)
+                {
+                    var part3 = new byte[8];
+                    Array.Copy(this.Key, 16, part3, 0, 8);
+
+                    this._decryptionKey3 = this.GenerateWorkingKey(false, part3);
+                }
+                else
+                {
+                    this._decryptionKey3 = this._decryptionKey1;
+                }
+            }
+
             byte[] temp = new byte[this.BlockSize];
 
             DesCipher.DesFunc(this._decryptionKey3, inputBuffer, inputOffset, temp, 0);
@@ -112,18 +135,14 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
         }
 
         /// <summary>
-        /// Validates the size of the key.
+        /// Validates 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)
+        protected override void ValidateKey()
         {
-            if (keySize == 128 || keySize == 128 + 64)
-                return true;
-            else
-                return false;
+            var keySize = this.Key.Length * 8;
+
+            if (!(keySize == 128 || keySize == 128 + 64))
+                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
         }
     }
 }

+ 13 - 27
Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs

@@ -30,6 +30,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 		public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding)
 			: base(key, mode, padding)
 		{
+            var keySize = key.Length * 8;
+
+            if (!(keySize == 128 || keySize == 192 || keySize == 256))
+                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+
 			//  TODO:   Refactor this algorithm
 
             // calculate the MDS matrix
@@ -50,20 +55,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
                 mX[1] = Mx_X(j) & 0xff;
                 mY[1] = Mx_Y(j) & 0xff;
 
-                gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
-                            mY[P_00] << 16 | mY[P_00] << 24;
+                gMDS0[i] = m1[P_00] | mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24;
 
-                gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
-                            mX[P_10] << 16 | m1[P_10] << 24;
+                gMDS1[i] = mY[P_10] | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24;
 
-                gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
-                            m1[P_20] << 16 | mY[P_20] << 24;
+                gMDS2[i] = mX[P_20] | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24;
 
-                gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
-                            mY[P_30] << 16 | mX[P_30] << 24;
+                gMDS3[i] = mX[P_30] | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24;
             }
 
-            this.k64Cnt = (key.Length / 8); // pre-padded ?
+            this.k64Cnt = key.Length / 8; // pre-padded ?
             this.SetKey(key);
 		}
 
@@ -153,21 +154,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             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 == 128 || keySize == 192 || keySize == 256)
-                return true;
-            else
-                return false;
-        }
-
         #region Static Definition Tables
 
         private static readonly byte[,] P =  {
@@ -488,9 +474,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             {
                 case 1:
                     result = gMDS0[(P[P_01, b0] & 0xff) ^ M_b0(k0)] ^
-                            gMDS1[(P[P_11, b1] & 0xff) ^ M_b1(k0)] ^
-                            gMDS2[(P[P_21, b2] & 0xff) ^ M_b2(k0)] ^
-                            gMDS3[(P[P_31, b3] & 0xff) ^ M_b3(k0)];
+                             gMDS1[(P[P_11, b1] & 0xff) ^ M_b1(k0)] ^
+                             gMDS2[(P[P_21, b2] & 0xff) ^ M_b2(k0)] ^
+                             gMDS3[(P[P_31, b3] & 0xff) ^ M_b3(k0)];
                     break;
                 case 0: /* 256 bits of key */
                     b0 = (P[P_04, b0] & 0xff) ^ M_b0(k3);

+ 56 - 1
Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs

@@ -11,7 +11,7 @@ namespace Renci.SshNet.Security.Cryptography
     /// <summary>
     /// Implements DSA digital signature algorithm.
     /// </summary>
-    public class DsaDigitalSignature : DigitalSignature
+    public class DsaDigitalSignature : DigitalSignature, IDisposable
     {
         private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
         
@@ -138,5 +138,60 @@ namespace Renci.SshNet.Security.Cryptography
             //  The signature is (r, s)
             return r.ToByteArray().Reverse().TrimLeadingZero().Concat(s.ToByteArray().Reverse().TrimLeadingZero()).ToArray();
         }
+        
+        #region IDisposable Members
+
+        private bool _isDisposed = false;
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            // Check to see if Dispose has already been called.
+            if (!this._isDisposed)
+            {
+                // If disposing equals true, dispose all managed
+                // and unmanaged ResourceMessages.
+                if (disposing)
+                {
+                    // Dispose managed ResourceMessages.
+                    if (this._hash != null)
+                    {
+                        this._hash.Dispose();
+                        this._hash = null;
+                    }
+                }
+
+                // Note disposing has been done.
+                this._isDisposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases unmanaged resources and performs other cleanup operations before the
+        /// <see cref="SshCommand"/> is reclaimed by garbage collection.
+        /// </summary>
+        ~DsaDigitalSignature()
+        {
+            // Do not re-create Dispose clean-up code here.
+            // Calling Dispose(false) is optimal in terms of
+            // readability and maintainability.
+            Dispose(false);
+        }
+
+        #endregion
+
     }
 }

+ 99 - 43
Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs

@@ -10,34 +10,64 @@ namespace Renci.SshNet.Security
     /// <summary>
     /// Contains DSA private and public key
     /// </summary>
-    public class DsaKey : Key
+    public class DsaKey : Key, IDisposable
     {
         /// <summary>
-        /// Gets public key Y.
+        /// Gets the P.
         /// </summary>
-        public BigInteger Y { get; private set; }
+        public BigInteger P
+        {
+            get
+            {
+                return this._privateKey[0];
+            }
+        }
 
         /// <summary>
-        /// Gets private key X.
+        /// Gets the Q.
         /// </summary>
-        public BigInteger X { get; private set; }
+        public BigInteger Q
+        {
+            get
+            {
+                return this._privateKey[1];
+            }
+        }
 
         /// <summary>
         /// Gets the G.
         /// </summary>
-        public BigInteger G { get; private set; }
+        public BigInteger G
+        {
+            get
+            {
+                return this._privateKey[2];
+            }
+        }
 
         /// <summary>
-        /// Gets the Q.
+        /// Gets public key Y.
         /// </summary>
-        public BigInteger Q { get; private set; }
+        public BigInteger Y
+        {
+            get
+            {
+                return this._privateKey[3];
+            }
+        }
 
         /// <summary>
-        /// Gets the P.
+        /// Gets private key X.
         /// </summary>
-        public BigInteger P { get; private set; }
+        public BigInteger X
+        {
+            get
+            {
+                return this._privateKey[4];
+            }
+        }
 
-        private DigitalSignature _digitalSignature;
+        private DsaDigitalSignature _digitalSignature;
         /// <summary>
         /// Gets the digital signature.
         /// </summary>
@@ -69,37 +99,8 @@ namespace Renci.SshNet.Security
             {
                 if (value.Length != 4)
                     throw new InvalidOperationException("Invalid public key.");
-
-                this.P = value[0];
-                this.Q = value[1];
-                this.G = value[2];
-                this.Y = value[3];
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the private.
-        /// </summary>
-        /// <value>
-        /// The private.
-        /// </value>
-        protected override BigInteger[] Private
-        {
-            get
-            {
-                //return new BigInteger[] { this.P, this.Q, this.G, this.Y, this.X };
-                return new BigInteger[] { this.P, this.Q, this.G, this.X };
-            }
-            set
-            {
-                if (value.Length != 5)
-                    throw new InvalidOperationException("Invalid private key.");
-
-                this.P = value[0];
-                this.Q = value[1];
-                this.G = value[2];
-                this.Y = value[3];
-                this.X = value[4];
+                
+                this._privateKey = value;
             }
         }
 
@@ -109,7 +110,7 @@ namespace Renci.SshNet.Security
         public DsaKey()
             : base()
         {
-
+            this._privateKey = new BigInteger[5];
         }
 
         /// <summary>
@@ -119,7 +120,62 @@ namespace Renci.SshNet.Security
         public DsaKey(byte[] data)
             : base(data)
         {
+            if (this._privateKey.Length != 5)
+                throw new InvalidOperationException("Invalid private key.");
+        }
+            
+        #region IDisposable Members
 
+        private bool _isDisposed = false;
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+
+            GC.SuppressFinalize(this);
         }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            // Check to see if Dispose has already been called.
+            if (!this._isDisposed)
+            {
+                // If disposing equals true, dispose all managed
+                // and unmanaged ResourceMessages.
+                if (disposing)
+                {
+                    // Dispose managed ResourceMessages.
+                    if (this._digitalSignature != null)
+                    {
+                        this._digitalSignature.Dispose();
+                        this._digitalSignature = null;
+                    }
+                }
+
+                // Note disposing has been done.
+                this._isDisposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Releases unmanaged resources and performs other cleanup operations before the
+        /// <see cref="SshCommand"/> is reclaimed by garbage collection.
+        /// </summary>
+        ~DsaKey()
+        {
+            // Do not re-create Dispose clean-up code here.
+            // Calling Dispose(false) is optimal in terms of
+            // readability and maintainability.
+            Dispose(false);
+        }
+
+        #endregion
     }
 }

+ 49 - 34
Renci.SshClient/Renci.SshNet/Security/Cryptography/HMAC.cs

@@ -16,6 +16,7 @@ namespace Renci.SshNet.Security.Cryptography
         private bool _isHashing;
         private byte[] _innerPadding;
         private byte[] _outerPadding;
+        private byte[] _key;
 
         /// <summary>
         /// Gets the size of the block.
@@ -42,9 +43,9 @@ namespace Renci.SshNet.Security.Cryptography
 
             this.HashSizeValue = this._hash.HashSize;
 
-            this.Key = key;
+            this._key = key;
 
-            this.Initialize();
+            this.InternalInitialize();
         }
 
         /// <summary>
@@ -52,38 +53,13 @@ namespace Renci.SshNet.Security.Cryptography
         /// </summary>
         public override byte[] Key
         {
-            get { return (byte[])KeyValue.Clone(); }
+            get
+            {
+                return (byte[])KeyValue.Clone();
+            }
             set
             {
-                if (this._isHashing)
-                {
-                    throw new Exception("Cannot change key during hash operation");
-                }
-                if (value.Length > this.BlockSize)
-                {
-                    this.KeyValue = this._hash.ComputeHash(value);
-                    // No need to call Initialize, ComputeHash does it automatically.
-                }
-                else
-                {
-                    this.KeyValue = value.Clone() as byte[];
-                }
-
-                this._innerPadding = new byte[this.BlockSize];
-                this._outerPadding = new byte[this.BlockSize];
-
-                // Compute inner and outer padding.
-                int i = 0;
-                for (i = 0; i < 64; i++)
-                {
-                    this._innerPadding[i] = 0x36;
-                    this._outerPadding[i] = 0x5C;
-                }
-                for (i = 0; i < this.KeyValue.Length; i++)
-                {
-                    this._innerPadding[i] ^= this.KeyValue[i];
-                    this._outerPadding[i] ^= this.KeyValue[i];
-                }
+                this.SetKey(value);
             }
         }
 
@@ -92,7 +68,7 @@ namespace Renci.SshNet.Security.Cryptography
         /// </summary>
         public override void Initialize()
         {
-            this._isHashing = false;
+            this.InternalInitialize();
         }
 
         /// <summary>
@@ -137,6 +113,45 @@ namespace Renci.SshNet.Security.Cryptography
             this._isHashing = false;
 
             return this._hash.Hash;
-        }        
+        }
+
+        private void InternalInitialize()
+        {
+            this._isHashing = false;
+            this.SetKey(this._key);
+        }
+
+        private void SetKey(byte[] value)
+        {
+            if (this._isHashing)
+            {
+                throw new Exception("Cannot change key during hash operation");
+            }
+            if (value.Length > this.BlockSize)
+            {
+                this.KeyValue = this._hash.ComputeHash(value);
+                // No need to call Initialize, ComputeHash does it automatically.
+            }
+            else
+            {
+                this.KeyValue = value.Clone() as byte[];
+            }
+
+            this._innerPadding = new byte[this.BlockSize];
+            this._outerPadding = new byte[this.BlockSize];
+
+            // Compute inner and outer padding.
+            int i = 0;
+            for (i = 0; i < 64; i++)
+            {
+                this._innerPadding[i] = 0x36;
+                this._outerPadding[i] = 0x5C;
+            }
+            for (i = 0; i < this.KeyValue.Length; i++)
+            {
+                this._innerPadding[i] ^= this.KeyValue[i];
+                this._outerPadding[i] ^= this.KeyValue[i];
+            }
+        }
     }
 }

+ 6 - 1
Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs

@@ -83,7 +83,7 @@ namespace Renci.SshNet.Security.Cryptography
         /// </summary>
         public MD5Hash()
         {
-            this.Initialize();
+            this.InternalInitialize();
         }
 
         /// <summary>
@@ -164,6 +164,11 @@ namespace Renci.SshNet.Security.Cryptography
         /// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
         /// </summary>
         public override void Initialize()
+        {
+            this.InternalInitialize();
+        }
+
+        private void InternalInitialize()
         {
             this._byteCount = 0;
             this._bufferOffset = 0;

+ 19 - 15
Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs

@@ -96,8 +96,8 @@ namespace Renci.SshNet.Security.Cryptography
 		public SHA1Hash()
 		{
 			this._buffer = new byte[4];
-			this.Initialize();
-		}
+            this.InternalInitialize();
+        }
 
 		/// <summary>
 		/// Routes data written to the object into the hash algorithm for computing the hash.
@@ -181,21 +181,25 @@ namespace Renci.SshNet.Security.Cryptography
 		/// </summary>
 		public override void Initialize()
 		{
-			this._byteCount = 0;
-			this._bufferOffset = 0;
-			Array.Clear(this._buffer, 0, this._buffer.Length);
-
-			H1 = 0x67452301;
-			H2 = 0xefcdab89;
-			H3 = 0x98badcfe;
-			H4 = 0x10325476;
-			H5 = 0xc3d2e1f0;
-
-			this._offset = 0;
-			Array.Clear(_hashValue, 0, _hashValue.Length);
-
+            this.InternalInitialize();
 		}
 
+        private void InternalInitialize()
+        {
+            this._byteCount = 0;
+            this._bufferOffset = 0;
+            Array.Clear(this._buffer, 0, this._buffer.Length);
+
+            H1 = 0x67452301;
+            H2 = 0xefcdab89;
+            H3 = 0x98badcfe;
+            H4 = 0x10325476;
+            H5 = 0xc3d2e1f0;
+
+            this._offset = 0;
+            Array.Clear(_hashValue, 0, _hashValue.Length);
+        }
+
 		private void Update(byte input)
 		{
 			this._buffer[this._bufferOffset++] = input;

+ 21 - 17
Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs

@@ -91,7 +91,7 @@ namespace Renci.SshNet.Security.Cryptography
 		public SHA256Hash()
 		{
 			this._buffer = new byte[4];
-			this.Initialize();
+            this.InternalInitialize();
 		}
 
 		/// <summary>
@@ -179,24 +179,28 @@ namespace Renci.SshNet.Security.Cryptography
 		/// </summary>
 		public override void Initialize()
 		{
-			//this.Reset();
-			this._byteCount = 0;
-			this._bufferOffset = 0;
-			Array.Clear(this._buffer, 0, this._buffer.Length);
-
-			H1 = 0x6a09e667;
-			H2 = 0xbb67ae85;
-			H3 = 0x3c6ef372;
-			H4 = 0xa54ff53a;
-			H5 = 0x510e527f;
-			H6 = 0x9b05688c;
-			H7 = 0x1f83d9ab;
-			H8 = 0x5be0cd19;
-
-			this._offset = 0;
-			Array.Clear(X, 0, X.Length);
+            this.InternalInitialize();
 		}
 
+        private void InternalInitialize()
+        {
+            this._byteCount = 0;
+            this._bufferOffset = 0;
+            Array.Clear(this._buffer, 0, this._buffer.Length);
+
+            H1 = 0x6a09e667;
+            H2 = 0xbb67ae85;
+            H3 = 0x3c6ef372;
+            H4 = 0xa54ff53a;
+            H5 = 0x510e527f;
+            H6 = 0x9b05688c;
+            H7 = 0x1f83d9ab;
+            H8 = 0x5be0cd19;
+
+            this._offset = 0;
+            Array.Clear(X, 0, X.Length);
+        }
+
 		private void Update(byte input)
 		{
 			this._buffer[this._bufferOffset++] = input;

+ 6 - 9
Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs

@@ -12,6 +12,11 @@ namespace Renci.SshNet.Security
     /// </summary>
     public abstract class Key
     {
+        /// <summary>
+        /// Specifies array of big integers that represent private key
+        /// </summary>
+        protected BigInteger[] _privateKey;
+
         /// <summary>
         /// Gets the key specific digital signature.
         /// </summary>
@@ -25,14 +30,6 @@ namespace Renci.SshNet.Security
         /// </value>
         public abstract BigInteger[] Public { get; set; }
 
-        /// <summary>
-        /// Gets or sets the private key.
-        /// </summary>
-        /// <value>
-        /// The private.
-        /// </value>
-        protected abstract BigInteger[] Private { get; set; }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="Key"/> class.
         /// </summary>
@@ -51,7 +48,7 @@ namespace Renci.SshNet.Security
                 keys.Add(der.ReadBigInteger());
             }
 
-            this.Private = keys.ToArray();
+            this._privateKey = keys.ToArray();
         }
 
         /// <summary>

+ 68 - 2
Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs

@@ -11,15 +11,81 @@ namespace Renci.SshNet.Security.Cryptography
     /// <summary>
     /// Implements RSA digital signature algorithm.
     /// </summary>
-    public class RsaDigitalSignature : CipherDigitalSignature
+    public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
     {
+        private HashAlgorithm _hash = new SHA1Hash();
+
         /// <summary>
         /// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
         /// </summary>
         /// <param name="rsaKey">The RSA key.</param>
         public RsaDigitalSignature(RsaKey rsaKey)
-            : base(new SHA1Hash(), new ObjectIdentifier(1, 3, 14, 3, 2, 26), new RsaCipher(rsaKey))
+            : base(new ObjectIdentifier(1, 3, 14, 3, 2, 26), new RsaCipher(rsaKey))
+        {
+        }
+
+        /// <summary>
+        /// Hashes the specified input.
+        /// </summary>
+        /// <param name="input">The input.</param>
+        /// <returns></returns>
+        protected override byte[] Hash(byte[] input)
+        {
+            return this._hash.ComputeHash(input);
+        }
+
+        #region IDisposable Members
+
+        private bool _isDisposed = false;
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+        /// </summary>
+        public void Dispose()
         {
+            Dispose(true);
+
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            // Check to see if Dispose has already been called.
+            if (!this._isDisposed)
+            {
+                // If disposing equals true, dispose all managed
+                // and unmanaged ResourceMessages.
+                if (disposing)
+                {
+                    // Dispose managed ResourceMessages.
+                    if (this._hash != null)
+                    {
+                        this._hash.Dispose();
+                        this._hash = null;
+                    }
+                }
+
+                // Note disposing has been done.
+                this._isDisposed = true;
+            }
         }
+
+        /// <summary>
+        /// Releases unmanaged resources and performs other cleanup operations before the
+        /// <see cref="SshCommand"/> is reclaimed by garbage collection.
+        /// </summary>
+        ~RsaDigitalSignature()
+        {
+            // Do not re-create Dispose clean-up code here.
+            // Calling Dispose(false) is optimal in terms of
+            // readability and maintainability.
+            Dispose(false);
+        }
+
+        #endregion
     }
 }

+ 131 - 39
Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs

@@ -10,49 +10,115 @@ namespace Renci.SshNet.Security
     /// <summary>
     /// Contains RSA private and public key
     /// </summary>
-    public class RsaKey : Key
+    public class RsaKey : Key, IDisposable
     {
         /// <summary>
         /// Gets the modulus.
         /// </summary>
-        public BigInteger Modulus { get; private set; }
+        public BigInteger Modulus
+        {
+            get
+            {
+                return this._privateKey[0];
+            }
+        }
 
         /// <summary>
         /// Gets the exponent.
         /// </summary>
-        public BigInteger Exponent { get; private set; }
+        public BigInteger Exponent
+        {
+            get
+            {
+                return this._privateKey[1];
+            }
+        }
 
         /// <summary>
         /// Gets the D.
         /// </summary>
-        public BigInteger D { get; private set; }
+        public BigInteger D
+        {
+            get
+            {
+                if (this._privateKey.Length > 2)
+                    return this._privateKey[2];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
         /// <summary>
         /// Gets the P.
         /// </summary>
-        public BigInteger P { get; private set; }
+        public BigInteger P
+        {
+            get
+            {
+                if (this._privateKey.Length > 3)
+                    return this._privateKey[3];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
         /// <summary>
         /// Gets the Q.
         /// </summary>
-        public BigInteger Q { get; private set; }
+        public BigInteger Q
+        {
+            get
+            {
+                if (this._privateKey.Length > 4)
+                    return this._privateKey[4];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
         /// <summary>
         /// Gets the DP.
         /// </summary>
-        public BigInteger DP { get; private set; }
+        public BigInteger DP
+        {
+            get
+            {
+                if (this._privateKey.Length > 5)
+                    return this._privateKey[5];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
         /// <summary>
         /// Gets the DQ.
         /// </summary>
-        public BigInteger DQ { get; private set; }
+        public BigInteger DQ
+        {
+            get
+            {
+                if (this._privateKey.Length > 6)
+                    return this._privateKey[6];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
         /// <summary>
         /// Gets the inverse Q.
         /// </summary>
-        public BigInteger InverseQ { get; private set; }
+        public BigInteger InverseQ
+        {
+            get
+            {
+                if (this._privateKey.Length > 7)
+                    return this._privateKey[7];
+                else
+                    return BigInteger.Zero;
+            }
+        }
 
-        private DigitalSignature _digitalSignature;
+        private RsaDigitalSignature _digitalSignature;
         /// <summary>
         /// Gets the digital signature.
         /// </summary>
@@ -85,55 +151,81 @@ namespace Renci.SshNet.Security
                 if (value.Length != 2)
                     throw new InvalidOperationException("Invalid private key.");
 
-                this.Exponent = value[0];
-                this.Modulus = value[1];
+                this._privateKey = new BigInteger[] { value[1], value[0] };
             }
         }
 
         /// <summary>
-        /// Gets or sets the private.
+        /// Initializes a new instance of the <see cref="RsaKey"/> class.
         /// </summary>
-        /// <value>
-        /// The private.
-        /// </value>
-        protected override BigInteger[] Private
+        public RsaKey()
         {
-            get
-            {
-                return new BigInteger[] { this.Modulus, this.Exponent, this.D, this.P, this.Q, this.DP, this.DQ, this.InverseQ };
-            }
-            set
-            {
-                if (value.Length != 8)
-                    throw new InvalidOperationException("Invalid private key.");
 
-                this.Modulus = value[0];
-                this.Exponent = value[1];
-                this.D = value[2];
-                this.P = value[3];
-                this.Q = value[4];
-                this.DP = value[5];
-                this.DQ = value[6];
-                this.InverseQ = value[7];
-            }
         }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="RsaKey"/> class.
         /// </summary>
-        public RsaKey()
+        /// <param name="data">DER encoded private key data.</param>
+        public RsaKey(byte[] data)
+            : base(data)
+        {
+            if (this._privateKey.Length != 8)
+                throw new InvalidOperationException("Invalid private key.");
+        }
+
+        #region IDisposable Members
+
+        private bool _isDisposed = false;
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+        /// </summary>
+        public void Dispose()
         {
+            Dispose(true);
 
+            GC.SuppressFinalize(this);
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="RsaKey"/> class.
+        /// Releases unmanaged and - optionally - managed resources
         /// </summary>
-        /// <param name="data">DER encoded private key data.</param>
-        public RsaKey(byte[] data)
-            : base(data)
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
+        protected virtual void Dispose(bool disposing)
         {
+            // Check to see if Dispose has already been called.
+            if (!this._isDisposed)
+            {
+                // If disposing equals true, dispose all managed
+                // and unmanaged ResourceMessages.
+                if (disposing)
+                {
+                    // Dispose managed ResourceMessages.
+                    if (this._digitalSignature != null)
+                    {
+                        this._digitalSignature.Dispose();
+                        this._digitalSignature = null;
+                    }
+                }
 
+                // Note disposing has been done.
+                this._isDisposed = true;
+            }
         }
+
+        /// <summary>
+        /// Releases unmanaged resources and performs other cleanup operations before the
+        /// <see cref="SshCommand"/> is reclaimed by garbage collection.
+        /// </summary>
+        ~RsaKey()
+        {
+            // Do not re-create Dispose clean-up code here.
+            // Calling Dispose(false) is optimal in terms of
+            // readability and maintainability.
+            Dispose(false);
+        }
+
+        #endregion
     }
 }

+ 3 - 22
Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs

@@ -11,12 +11,9 @@ namespace Renci.SshNet.Security.Cryptography
     public abstract class SymmetricCipher : Cipher
     {
         /// <summary>
-        /// Gets the size of the key in bits.
+        /// Gets the key.
         /// </summary>
-        /// <value>
-        /// The size of the key in bits.
-        /// </value>
-        public int KeySize { get; private set; }
+        protected byte[] Key { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SymmetricCipher"/> class.
@@ -24,16 +21,7 @@ namespace Renci.SshNet.Security.Cryptography
         /// <param name="key">The key.</param>
         protected SymmetricCipher(byte[] key)
         {
-            var keySize = key.Length * 8;
-
-            if (this.ValidateKeySize(keySize))
-            {
-                this.KeySize = keySize;
-            }
-            else
-            {
-                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
-            }
+            this.Key = key;
         }
 
         /// <summary>
@@ -61,12 +49,5 @@ namespace Renci.SshNet.Security.Cryptography
         /// The number of bytes decrypted.
         /// </returns>
         public abstract int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
-
-        /// <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 abstract bool ValidateKeySize(int keySize);
     }
 }

+ 4 - 2
Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs

@@ -283,8 +283,10 @@ namespace Renci.SshNet.Security
         /// <summary>
         /// Hashes the specified data bytes.
         /// </summary>
-        /// <param name="hashBytes">Data to hash.</param>
-        /// <returns>Hashed bytes</returns>
+        /// <param name="hashData">The hash data.</param>
+        /// <returns>
+        /// Hashed bytes
+        /// </returns>
         protected virtual byte[] Hash(byte[] hashData)
         {
             using (var sha1 = new Renci.SshNet.Security.Cryptography.SHA1Hash())

+ 2 - 1
Renci.SshClient/Renci.SshNet/SftpClient.cs

@@ -1124,8 +1124,9 @@ namespace Renci.SshNet
             ulong offset = 0;
 
             var data = this._sftpSession.RequestRead(handle, offset, this.BufferSize);
+
             //  Read data while available
-            while (data != null)
+            while (data.Length > 0)
             {
                 output.Write(data, 0, data.Length);