diff --git a/Renci.SshClient/Renci.SshNet/Common/DerData.cs b/Renci.SshClient/Renci.SshNet/Common/DerData.cs
index 1bc765b3..e6521bca 100644
--- a/Renci.SshClient/Renci.SshNet/Common/DerData.cs
+++ b/Renci.SshClient/Renci.SshNet/Common/DerData.cs
@@ -194,7 +194,7 @@ namespace Renci.SshNet.Common
///
/// Writes OBJECTIDENTIFIER data into internal buffer.
///
- /// The identifiers.
+ /// The identifier.
public void Write(ObjectIdentifier identifier)
{
var temp = new ulong[identifier.Identifiers.Length - 1];
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs
index 93845150..ea88a02b 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs
@@ -10,10 +10,8 @@ namespace Renci.SshNet.Security.Cryptography
///
/// Implements digital signature where where asymmetric cipher is used,
///
- 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
///
/// Initializes a new instance of the class.
///
- /// The hash.
+ /// The object identifier.
/// The cipher.
- 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
///
/// The input.
///
- protected byte[] Hash(byte[] input)
- {
- return this._hash.ComputeHash(input);
- }
+ protected abstract byte[] Hash(byte[] input);
///
/// Encodes hash using DER.
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs
index 7e4f0b10..5e1c644f 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs
@@ -5,28 +5,56 @@ using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
- ///
- ///
- ///
- public class AesCipher : BlockCipher
- {
- private const uint m1 = 0x80808080;
+ ///
+ ///
+ ///
+ public class AesCipher : BlockCipher
+ {
+ private const uint m1 = 0x80808080;
- private const uint m2 = 0x7f7f7f7f;
+ private const uint m2 = 0x7f7f7f7f;
- private const uint m3 = 0x0000001b;
-
- private int _rounds;
+ private const uint m3 = 0x0000001b;
- private uint[,] _encryptionKey;
+ private int _rounds;
- private uint[,] _decryptionKey;
+ private uint[,] _encryptionKey;
+ ///
+ /// Gets the encryption key.
+ ///
+ protected uint[,] EncryptionKey
+ {
+ get
+ {
+ if (this._encryptionKey == null)
+ {
+ this._encryptionKey = this.GenerateWorkingKey(true, this.Key);
+ }
+ return this._encryptionKey;
+ }
+ }
- private uint C0, C1, C2, C3;
+ private uint[,] _decryptionKey;
+ ///
+ /// Gets the encryption key.
+ ///
+ protected uint[,] DecryptionKey
+ {
+ get
+ {
+ if (this._decryptionKey == null)
+ {
+ this._decryptionKey = this.GenerateWorkingKey(false, this.Key);
+ }
+ return this._decryptionKey;
+ }
+ }
- #region Static Definition Tables
+ private uint C0, C1, C2, C3;
- private static readonly byte[] S =
+ #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
+ #endregion
- ///
- /// Gets the size of the block in bytes.
- ///
- ///
- /// The size of the block in bytes.
- ///
- public override int BlockSize
- {
- get { return 16; }
- }
+ ///
+ /// Gets the size of the block in bytes.
+ ///
+ ///
+ /// The size of the block in bytes.
+ ///
+ public override int BlockSize
+ {
+ get { return 16; }
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// The key.
- /// The mode.
- /// The padding.
- public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
- : base(key, mode, padding)
- {
- this._encryptionKey = this.GenerateWorkingKey(true, key);
- this._decryptionKey = this.GenerateWorkingKey(false, key);
- }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The key.
+ /// The mode.
+ /// The padding.
+ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
+ : base(key, mode, padding)
+ {
+ var keySize = key.Length * 8;
- ///
- /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
- ///
- /// The input data to encrypt.
- /// The offset into the input byte array from which to begin using data.
- /// The number of bytes in the input byte array to use as data.
- /// The output to which to write encrypted data.
- /// The offset into the output byte array from which to begin writing data.
- ///
- /// The number of bytes encrypted.
- ///
- 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 (!(keySize == 256 || keySize == 192 || keySize == 128))
+ throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
+ }
- if ((outputOffset + (32 / 2)) > outputBuffer.Length)
- {
- throw new IndexOutOfRangeException("output buffer too short");
- }
+ ///
+ /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
+ ///
+ /// The input data to encrypt.
+ /// The offset into the input byte array from which to begin using data.
+ /// The number of bytes in the input byte array to use as data.
+ /// The output to which to write encrypted data.
+ /// The offset into the output byte array from which to begin writing data.
+ ///
+ /// The number of bytes encrypted.
+ ///
+ 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");
+ }
- this.UnPackBlock(inputBuffer, inputOffset);
+ if ((outputOffset + (32 / 2)) > outputBuffer.Length)
+ {
+ throw new IndexOutOfRangeException("output buffer too short");
+ }
- this.EncryptBlock(this._encryptionKey);
+ this.UnPackBlock(inputBuffer, inputOffset);
- this.PackBlock(outputBuffer, outputOffset);
+ this.EncryptBlock(this.EncryptionKey);
- return this.BlockSize;
- }
+ this.PackBlock(outputBuffer, outputOffset);
- ///
- /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
- ///
- /// The input data to decrypt.
- /// The offset into the input byte array from which to begin using data.
- /// The number of bytes in the input byte array to use as data.
- /// The output to which to write decrypted data.
- /// The offset into the output byte array from which to begin writing data.
- ///
- /// The number of bytes decrypted.
- ///
- 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");
- }
+ return this.BlockSize;
+ }
- if ((outputOffset + (32 / 2)) > outputBuffer.Length)
- {
- throw new IndexOutOfRangeException("output buffer too short");
- }
+ ///
+ /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
+ ///
+ /// The input data to decrypt.
+ /// The offset into the input byte array from which to begin using data.
+ /// The number of bytes in the input byte array to use as data.
+ /// The output to which to write decrypted data.
+ /// The offset into the output byte array from which to begin writing data.
+ ///
+ /// The number of bytes decrypted.
+ ///
+ 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");
+ }
- this.UnPackBlock(inputBuffer, inputOffset);
+ if ((outputOffset + (32 / 2)) > outputBuffer.Length)
+ {
+ throw new IndexOutOfRangeException("output buffer too short");
+ }
- this.DecryptBlock(this._decryptionKey);
+ this.UnPackBlock(inputBuffer, inputOffset);
- this.PackBlock(outputBuffer, outputOffset);
+ this.DecryptBlock(this.DecryptionKey);
- return this.BlockSize;
- }
+ this.PackBlock(outputBuffer, outputOffset);
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- protected override bool ValidateKeySize(int keySize)
- {
- if (keySize == 256 ||
- keySize == 192 ||
- keySize == 128)
- return true;
- else
- return false;
- }
+ return this.BlockSize;
+ }
- private uint[,] GenerateWorkingKey(bool isEncryption, byte[] key)
- {
- int KC = key.Length / 4; // key length in words
+ 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.");
+ 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
+ _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
- //
+ //
+ // copy the key into the round key array
+ //
- int t = 0;
+ int t = 0;
- for (int i = 0; i < key.Length; t++)
- {
- W[t >> 2, t & 3] = LittleEndianToUInt32(key, i);
- i += 4;
- }
+ 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);
- }
+ //
+ // 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;
- }
+ 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]);
- }
- }
- }
+ 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;
- }
+ return W;
+ }
- private uint Shift(uint r, int shift)
- {
- return (r >> shift) | (r << (32 - shift));
- }
+ 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 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 uint InvMcol(uint x)
+ {
+ uint f2 = FFmulX(x);
+ uint f4 = FFmulX(f2);
+ uint f8 = FFmulX(f4);
+ uint f9 = x ^ f8;
- 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); }
+ 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 uint InvMcol(uint x)
- {
- uint f2 = FFmulX(x);
- uint f4 = FFmulX(f2);
- uint f8 = FFmulX(f4);
- uint f9 = x ^ f8;
+ 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);
+ }
- return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
- }
+ 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 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 EncryptBlock(uint[,] KW)
+ {
+ int r;
+ uint r0, r1, r2, r3;
- 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);
- }
+ C0 ^= KW[0, 0];
+ C1 ^= KW[0, 1];
+ C2 ^= KW[0, 2];
+ C3 ^= KW[0, 3];
- 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);
- }
+ 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];
+ }
- private void EncryptBlock(uint[,] KW)
- {
- int r;
- uint r0, r1, r2, r3;
+ 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 ^= KW[0, 0];
- C1 ^= KW[0, 1];
- C2 ^= KW[0, 2];
- C3 ^= KW[0, 3];
+ // the final round's table is a simple function of S so we don't use a whole other four tables for it
- 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];
- }
+ 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];
+ }
- 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];
+ private void DecryptBlock(uint[,] KW)
+ {
+ int r;
+ uint r0, r1, r2, r3;
- // the final round's table is a simple function of S so we don't use a whole other four tables for it
+ C0 ^= KW[_rounds, 0];
+ C1 ^= KW[_rounds, 1];
+ C2 ^= KW[_rounds, 2];
+ C3 ^= KW[_rounds, 3];
- 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];
- }
+ 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];
+ }
- private void DecryptBlock(uint[,] KW)
- {
- int r;
- uint r0, r1, r2, r3;
+ 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 ^= KW[_rounds, 0];
- C1 ^= KW[_rounds, 1];
- C2 ^= KW[_rounds, 2];
- C3 ^= KW[_rounds, 3];
+ // the final round's table is a simple function of Si so we don't use a whole other four tables for it
- 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];
- }
+ 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];
+ }
- 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];
- }
-
- }
+ }
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs
index a3ce791f..8b635294 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs
@@ -71,17 +71,5 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
{
throw new NotImplementedException();
}
-
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- protected override bool ValidateKeySize(int keySize)
- {
- throw new NotImplementedException();
- }
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs
index 59e844bc..7fa1c4b8 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs
+++ b/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;
}
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- 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]);
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs
index 01867c09..3cb93713 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs
@@ -36,8 +36,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
/// The mode.
/// The padding.
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;
}
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- 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 =
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs
index ff79425f..fbfb00cb 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs
@@ -10,9 +10,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
///
public class DesCipher : BlockCipher
{
- private readonly int[] _encryptionKey;
+ private int[] _encryptionKey;
- private readonly int[] _decryptionKey;
+ private int[] _decryptionKey;
///
/// 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);
}
///
@@ -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();
- }
-
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- protected override bool ValidateKeySize(int keySize)
- {
- if (keySize == 64)
- return true;
- else
- return false;
}
///
@@ -312,8 +304,10 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
/// if set to true [encrypting].
/// The key.
///
- 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;
}
+ ///
+ /// Validates the key.
+ ///
+ 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));
+ }
+
///
- /// Perfoms DES function.
+ /// Performs DES function.
///
/// The w key.
/// The input.
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs
index 4c75ede9..94630d91 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs
+++ b/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;
}
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- 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.
*
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs
index f820d7b7..0394c38d 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs
@@ -10,13 +10,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
///
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;
///
/// Initializes a new instance of the 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;
- }
-
}
///
@@ -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
}
///
- /// Validates the size of the key.
+ /// Validates the key.
///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- 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));
}
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs
index 3e03715e..e407bba0 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs
+++ b/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;
}
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- ///
- /// true if keySize is valid; otherwise false
- ///
- 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);
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs
index 47205c54..34ada0a2 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs
@@ -11,7 +11,7 @@ namespace Renci.SshNet.Security.Cryptography
///
/// Implements DSA digital signature algorithm.
///
- 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;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
+ 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;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~DsaDigitalSignature()
+ {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose(false);
+ }
+
+ #endregion
+
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs
index e7d2353c..36b8871e 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaKey.cs
@@ -10,34 +10,64 @@ namespace Renci.SshNet.Security
///
/// Contains DSA private and public key
///
- public class DsaKey : Key
+ public class DsaKey : Key, IDisposable
{
///
- /// Gets public key Y.
+ /// Gets the P.
///
- public BigInteger Y { get; private set; }
-
- ///
- /// Gets private key X.
- ///
- public BigInteger X { get; private set; }
-
- ///
- /// Gets the G.
- ///
- public BigInteger G { get; private set; }
+ public BigInteger P
+ {
+ get
+ {
+ return this._privateKey[0];
+ }
+ }
///
/// Gets the Q.
///
- public BigInteger Q { get; private set; }
+ public BigInteger Q
+ {
+ get
+ {
+ return this._privateKey[1];
+ }
+ }
///
- /// Gets the P.
+ /// Gets the G.
///
- public BigInteger P { get; private set; }
+ public BigInteger G
+ {
+ get
+ {
+ return this._privateKey[2];
+ }
+ }
- private DigitalSignature _digitalSignature;
+ ///
+ /// Gets public key Y.
+ ///
+ public BigInteger Y
+ {
+ get
+ {
+ return this._privateKey[3];
+ }
+ }
+
+ ///
+ /// Gets private key X.
+ ///
+ public BigInteger X
+ {
+ get
+ {
+ return this._privateKey[4];
+ }
+ }
+
+ private DsaDigitalSignature _digitalSignature;
///
/// Gets the digital signature.
///
@@ -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];
- }
- }
-
- ///
- /// Gets or sets the private.
- ///
- ///
- /// The private.
- ///
- 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];
}
///
@@ -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;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
+ 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;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~DsaKey()
+ {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose(false);
+ }
+
+ #endregion
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/HMAC.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/HMAC.cs
index 0b9dac47..f0457357 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/HMAC.cs
+++ b/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;
///
/// 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();
}
///
@@ -52,38 +53,13 @@ namespace Renci.SshNet.Security.Cryptography
///
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
///
public override void Initialize()
{
- this._isHashing = false;
+ this.InternalInitialize();
}
///
@@ -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];
+ }
+ }
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs
index 8fbf3264..008bdb4c 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs
@@ -83,7 +83,7 @@ namespace Renci.SshNet.Security.Cryptography
///
public MD5Hash()
{
- this.Initialize();
+ this.InternalInitialize();
}
///
@@ -164,6 +164,11 @@ namespace Renci.SshNet.Security.Cryptography
/// Initializes an implementation of the class.
///
public override void Initialize()
+ {
+ this.InternalInitialize();
+ }
+
+ private void InternalInitialize()
{
this._byteCount = 0;
this._bufferOffset = 0;
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs
index b3e1d42a..798ebc76 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs
+++ b/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();
+ }
///
/// Routes data written to the object into the hash algorithm for computing the hash.
@@ -181,21 +181,25 @@ namespace Renci.SshNet.Security.Cryptography
///
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;
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs
index 74b978ca..a6820a9d 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs
+++ b/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();
}
///
@@ -179,24 +179,28 @@ namespace Renci.SshNet.Security.Cryptography
///
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;
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs
index b853f41f..906a1446 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/Key.cs
@@ -12,6 +12,11 @@ namespace Renci.SshNet.Security
///
public abstract class Key
{
+ ///
+ /// Specifies array of big integers that represent private key
+ ///
+ protected BigInteger[] _privateKey;
+
///
/// Gets the key specific digital signature.
///
@@ -25,14 +30,6 @@ namespace Renci.SshNet.Security
///
public abstract BigInteger[] Public { get; set; }
- ///
- /// Gets or sets the private key.
- ///
- ///
- /// The private.
- ///
- protected abstract BigInteger[] Private { get; set; }
-
///
/// Initializes a new instance of the class.
///
@@ -51,7 +48,7 @@ namespace Renci.SshNet.Security
keys.Add(der.ReadBigInteger());
}
- this.Private = keys.ToArray();
+ this._privateKey = keys.ToArray();
}
///
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
index 6a1d7883..3b52ce4e 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs
@@ -11,15 +11,81 @@ namespace Renci.SshNet.Security.Cryptography
///
/// Implements RSA digital signature algorithm.
///
- public class RsaDigitalSignature : CipherDigitalSignature
+ public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
{
+ private HashAlgorithm _hash = new SHA1Hash();
+
///
/// Initializes a new instance of the class.
///
/// The RSA key.
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))
{
}
+
+ ///
+ /// Hashes the specified input.
+ ///
+ /// The input.
+ ///
+ protected override byte[] Hash(byte[] input)
+ {
+ return this._hash.ComputeHash(input);
+ }
+
+ #region IDisposable Members
+
+ private bool _isDisposed = false;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
+ 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;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~RsaDigitalSignature()
+ {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose(false);
+ }
+
+ #endregion
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs
index 36cd1934..0b7b7ff7 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaKey.cs
@@ -10,49 +10,115 @@ namespace Renci.SshNet.Security
///
/// Contains RSA private and public key
///
- public class RsaKey : Key
+ public class RsaKey : Key, IDisposable
{
///
/// Gets the modulus.
///
- public BigInteger Modulus { get; private set; }
+ public BigInteger Modulus
+ {
+ get
+ {
+ return this._privateKey[0];
+ }
+ }
///
/// Gets the exponent.
///
- public BigInteger Exponent { get; private set; }
+ public BigInteger Exponent
+ {
+ get
+ {
+ return this._privateKey[1];
+ }
+ }
///
/// Gets the D.
///
- public BigInteger D { get; private set; }
+ public BigInteger D
+ {
+ get
+ {
+ if (this._privateKey.Length > 2)
+ return this._privateKey[2];
+ else
+ return BigInteger.Zero;
+ }
+ }
///
/// Gets the P.
///
- public BigInteger P { get; private set; }
+ public BigInteger P
+ {
+ get
+ {
+ if (this._privateKey.Length > 3)
+ return this._privateKey[3];
+ else
+ return BigInteger.Zero;
+ }
+ }
///
/// Gets the Q.
///
- public BigInteger Q { get; private set; }
+ public BigInteger Q
+ {
+ get
+ {
+ if (this._privateKey.Length > 4)
+ return this._privateKey[4];
+ else
+ return BigInteger.Zero;
+ }
+ }
///
/// Gets the DP.
///
- public BigInteger DP { get; private set; }
+ public BigInteger DP
+ {
+ get
+ {
+ if (this._privateKey.Length > 5)
+ return this._privateKey[5];
+ else
+ return BigInteger.Zero;
+ }
+ }
///
/// Gets the DQ.
///
- public BigInteger DQ { get; private set; }
+ public BigInteger DQ
+ {
+ get
+ {
+ if (this._privateKey.Length > 6)
+ return this._privateKey[6];
+ else
+ return BigInteger.Zero;
+ }
+ }
///
/// Gets the inverse Q.
///
- 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;
///
/// Gets the digital signature.
///
@@ -85,36 +151,7 @@ namespace Renci.SshNet.Security
if (value.Length != 2)
throw new InvalidOperationException("Invalid private key.");
- this.Exponent = value[0];
- this.Modulus = value[1];
- }
- }
-
- ///
- /// Gets or sets the private.
- ///
- ///
- /// The private.
- ///
- protected override BigInteger[] Private
- {
- 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];
+ this._privateKey = new BigInteger[] { value[1], value[0] };
}
}
@@ -133,7 +170,62 @@ namespace Renci.SshNet.Security
public RsaKey(byte[] data)
: base(data)
{
-
+ if (this._privateKey.Length != 8)
+ throw new InvalidOperationException("Invalid private key.");
}
+
+ #region IDisposable Members
+
+ private bool _isDisposed = false;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
+ 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;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~RsaKey()
+ {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose(false);
+ }
+
+ #endregion
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs b/Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs
index aeb901d6..170c2ccf 100644
--- a/Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs
@@ -11,12 +11,9 @@ namespace Renci.SshNet.Security.Cryptography
public abstract class SymmetricCipher : Cipher
{
///
- /// Gets the size of the key in bits.
+ /// Gets the key.
///
- ///
- /// The size of the key in bits.
- ///
- public int KeySize { get; private set; }
+ protected byte[] Key { get; private set; }
///
/// Initializes a new instance of the class.
@@ -24,16 +21,7 @@ namespace Renci.SshNet.Security.Cryptography
/// The key.
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;
}
///
@@ -61,12 +49,5 @@ namespace Renci.SshNet.Security.Cryptography
/// The number of bytes decrypted.
///
public abstract int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
-
- ///
- /// Validates the size of the key.
- ///
- /// Size of the key.
- /// true if keySize is valid; otherwise false
- protected abstract bool ValidateKeySize(int keySize);
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs b/Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs
index e2b0e767..b863de24 100644
--- a/Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs
+++ b/Renci.SshClient/Renci.SshNet/Security/KeyExchange.cs
@@ -283,8 +283,10 @@ namespace Renci.SshNet.Security
///
/// Hashes the specified data bytes.
///
- /// Data to hash.
- /// Hashed bytes
+ /// The hash data.
+ ///
+ /// Hashed bytes
+ ///
protected virtual byte[] Hash(byte[] hashData)
{
using (var sha1 = new Renci.SshNet.Security.Cryptography.SHA1Hash())
diff --git a/Renci.SshClient/Renci.SshNet/SftpClient.cs b/Renci.SshClient/Renci.SshNet/SftpClient.cs
index 04f5a682..0e5bed72 100644
--- a/Renci.SshClient/Renci.SshNet/SftpClient.cs
+++ b/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);