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);