mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 17:25:51 +00:00
Fix CA2214 and some other CA complaints
Fix some comments Fix DownloadFile hang error introduced in previouse check in
This commit is contained in:
@@ -194,7 +194,7 @@ namespace Renci.SshNet.Common
|
||||
/// <summary>
|
||||
/// Writes OBJECTIDENTIFIER data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="identifiers">The identifiers.</param>
|
||||
/// <param name="identifier">The identifier.</param>
|
||||
public void Write(ObjectIdentifier identifier)
|
||||
{
|
||||
var temp = new ulong[identifier.Identifiers.Length - 1];
|
||||
|
||||
@@ -10,10 +10,8 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <summary>
|
||||
/// Implements digital signature where where asymmetric cipher is used,
|
||||
/// </summary>
|
||||
public class CipherDigitalSignature : DigitalSignature
|
||||
public abstract class CipherDigitalSignature : DigitalSignature
|
||||
{
|
||||
private HashAlgorithm _hash;
|
||||
|
||||
private AsymmetricCipher _cipher;
|
||||
|
||||
private ObjectIdentifier _oid;
|
||||
@@ -21,17 +19,13 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CipherDigitalSignature"/> class.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash.</param>
|
||||
/// <param name="oid">The object identifier.</param>
|
||||
/// <param name="cipher">The cipher.</param>
|
||||
public CipherDigitalSignature(HashAlgorithm hash, ObjectIdentifier oid, AsymmetricCipher cipher)
|
||||
public CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher)
|
||||
{
|
||||
if (hash == null)
|
||||
throw new ArgumentNullException("hash");
|
||||
|
||||
if (cipher == null)
|
||||
throw new ArgumentNullException("cipher");
|
||||
|
||||
this._hash = hash;
|
||||
this._cipher = cipher;
|
||||
this._oid = oid;
|
||||
}
|
||||
@@ -104,10 +98,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
protected byte[] Hash(byte[] input)
|
||||
{
|
||||
return this._hash.ComputeHash(input);
|
||||
}
|
||||
protected abstract byte[] Hash(byte[] input);
|
||||
|
||||
/// <summary>
|
||||
/// Encodes hash using DER.
|
||||
|
||||
@@ -5,28 +5,56 @@ using System.Text;
|
||||
|
||||
namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class AesCipher : BlockCipher
|
||||
{
|
||||
private const uint m1 = 0x80808080;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
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;
|
||||
/// <summary>
|
||||
/// Gets the encryption key.
|
||||
/// </summary>
|
||||
protected uint[,] EncryptionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._encryptionKey == null)
|
||||
{
|
||||
this._encryptionKey = this.GenerateWorkingKey(true, this.Key);
|
||||
}
|
||||
return this._encryptionKey;
|
||||
}
|
||||
}
|
||||
|
||||
private uint C0, C1, C2, C3;
|
||||
private uint[,] _decryptionKey;
|
||||
/// <summary>
|
||||
/// Gets the encryption key.
|
||||
/// </summary>
|
||||
protected uint[,] DecryptionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._decryptionKey == null)
|
||||
{
|
||||
this._decryptionKey = this.GenerateWorkingKey(false, this.Key);
|
||||
}
|
||||
return this._decryptionKey;
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the block in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the block in bytes.
|
||||
/// </value>
|
||||
public override int BlockSize
|
||||
{
|
||||
get { return 16; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the size of the block in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the block in bytes.
|
||||
/// </value>
|
||||
public override int BlockSize
|
||||
{
|
||||
get { return 16; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AesCipher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="padding">The padding.</param>
|
||||
public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
this._encryptionKey = this.GenerateWorkingKey(true, key);
|
||||
this._decryptionKey = this.GenerateWorkingKey(false, key);
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AesCipher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="padding">The padding.</param>
|
||||
public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input data to encrypt.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>
|
||||
/// The number of bytes encrypted.
|
||||
/// </returns>
|
||||
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("input buffer too short");
|
||||
}
|
||||
if (!(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");
|
||||
}
|
||||
/// <summary>
|
||||
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input data to encrypt.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>
|
||||
/// The number of bytes encrypted.
|
||||
/// </returns>
|
||||
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("input buffer too short");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input data to decrypt.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>
|
||||
/// The number of bytes decrypted.
|
||||
/// </returns>
|
||||
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("input buffer too short");
|
||||
}
|
||||
return this.BlockSize;
|
||||
}
|
||||
|
||||
if ((outputOffset + (32 / 2)) > outputBuffer.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("output buffer too short");
|
||||
}
|
||||
/// <summary>
|
||||
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
|
||||
/// </summary>
|
||||
/// <param name="inputBuffer">The input data to decrypt.</param>
|
||||
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
|
||||
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
|
||||
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
|
||||
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
|
||||
/// <returns>
|
||||
/// The number of bytes decrypted.
|
||||
/// </returns>
|
||||
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("input buffer too short");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize == 256 ||
|
||||
keySize == 192 ||
|
||||
keySize == 128)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,5 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
public BlowfishCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
if (keySize < 1 || keySize > 448)
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
|
||||
// TODO: Refactor this algorithm
|
||||
|
||||
S0 = new uint[SBOX_SK];
|
||||
@@ -399,21 +404,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
return this.BlockSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize >= 1 && keySize <= 448)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private uint F(uint x)
|
||||
{
|
||||
return (((S0[x >> 24] + S1[(x >> 16) & 0xff]) ^ S2[(x >> 8) & 0xff]) + S3[x & 0xff]);
|
||||
|
||||
@@ -36,8 +36,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="padding">The padding.</param>
|
||||
public CastCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
if (!(keySize >= 40 && keySize <= 128 && keySize % 8 == 0))
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
|
||||
// TODO: Refactor this algorithm
|
||||
this.SetKey(key);
|
||||
}
|
||||
@@ -101,21 +106,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
return this.BlockSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize >= 40 && keySize <= 128 && keySize % 8 == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Static Definition Tables
|
||||
|
||||
internal static readonly uint[] S1 =
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
/// </summary>
|
||||
public class DesCipher : BlockCipher
|
||||
{
|
||||
private readonly int[] _encryptionKey;
|
||||
private int[] _encryptionKey;
|
||||
|
||||
private readonly int[] _decryptionKey;
|
||||
private int[] _decryptionKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the block in bytes.
|
||||
@@ -238,8 +238,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
public DesCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
this._encryptionKey = GenerateWorkingKey(true, key);
|
||||
this._decryptionKey = GenerateWorkingKey(false, key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -261,6 +259,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
|
||||
throw new IndexOutOfRangeException("output buffer too short");
|
||||
|
||||
if (this._encryptionKey == null)
|
||||
{
|
||||
this._encryptionKey = GenerateWorkingKey(true, this.Key);
|
||||
}
|
||||
|
||||
DesCipher.DesFunc(this._encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
|
||||
|
||||
return this.BlockSize;
|
||||
@@ -285,25 +288,14 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
|
||||
throw new IndexOutOfRangeException("output buffer too short");
|
||||
|
||||
if (this._decryptionKey == null)
|
||||
{
|
||||
this._decryptionKey = GenerateWorkingKey(false, this.Key);
|
||||
}
|
||||
|
||||
DesCipher.DesFunc(this._decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
|
||||
|
||||
return this.BlockSize;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize == 64)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -312,8 +304,10 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
/// <param name="encrypting">if set to <c>true</c> [encrypting].</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns></returns>
|
||||
protected static int[] GenerateWorkingKey(bool encrypting, byte[] key)
|
||||
protected int[] GenerateWorkingKey(bool encrypting, byte[] key)
|
||||
{
|
||||
this.ValidateKey();
|
||||
|
||||
int[] newKey = new int[32];
|
||||
bool[] pc1m = new bool[56];
|
||||
bool[] pcr = new bool[56];
|
||||
@@ -391,22 +385,33 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
i1 = newKey[i];
|
||||
i2 = newKey[i + 1];
|
||||
|
||||
newKey[i] = (int)((uint)((i1 & 0x00fc0000) << 6) |
|
||||
newKey[i] = (int) ((uint)((i1 & 0x00fc0000) << 6) |
|
||||
(uint)((i1 & 0x00000fc0) << 10) |
|
||||
((uint)(i2 & 0x00fc0000) >> 10) |
|
||||
((uint)(i2 & 0x00000fc0) >> 6));
|
||||
|
||||
newKey[i + 1] = (int)((uint)((i1 & 0x0003f000) << 12) |
|
||||
(uint)((i1 & 0x0000003f) << 16) |
|
||||
((uint)(i2 & 0x0003f000) >> 4) |
|
||||
(uint)(i2 & 0x0000003f));
|
||||
(uint)((i1 & 0x0000003f) << 16) |
|
||||
((uint)(i2 & 0x0003f000) >> 4) |
|
||||
(uint)(i2 & 0x0000003f));
|
||||
}
|
||||
|
||||
return newKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the key.
|
||||
/// </summary>
|
||||
protected virtual void ValidateKey()
|
||||
{
|
||||
var keySize = this.Key.Length * 8;
|
||||
|
||||
if (!(keySize == 64))
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perfoms DES function.
|
||||
/// Performs DES function.
|
||||
/// </summary>
|
||||
/// <param name="wKey">The w key.</param>
|
||||
/// <param name="input">The input.</param>
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
{
|
||||
// TODO: Refactor this algorithm
|
||||
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
if (!(keySize == 128 || keySize == 192 || keySize == 256))
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
|
||||
this._workingKey = this.MakeWorkingKey(key);
|
||||
}
|
||||
|
||||
@@ -197,21 +202,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
return this.BlockSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize == 128 || keySize == 192 || keySize == 256)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a user-supplied key material into a session key.
|
||||
*
|
||||
|
||||
@@ -10,13 +10,13 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
/// </summary>
|
||||
public class TripleDesCipher : DesCipher
|
||||
{
|
||||
private readonly int[] _encryptionKey1;
|
||||
private readonly int[] _encryptionKey2;
|
||||
private readonly int[] _encryptionKey3;
|
||||
private int[] _encryptionKey1;
|
||||
private int[] _encryptionKey2;
|
||||
private int[] _encryptionKey3;
|
||||
|
||||
private readonly int[] _decryptionKey1;
|
||||
private readonly int[] _decryptionKey2;
|
||||
private readonly int[] _decryptionKey3;
|
||||
private int[] _decryptionKey1;
|
||||
private int[] _decryptionKey2;
|
||||
private int[] _decryptionKey3;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TripleDesCipher"/> class.
|
||||
@@ -27,32 +27,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
public TripleDesCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
var part1 = new byte[8];
|
||||
var part2 = new byte[8];
|
||||
|
||||
Array.Copy(key, 0, part1, 0, 8);
|
||||
Array.Copy(key, 8, part2, 0, 8);
|
||||
|
||||
this._encryptionKey1 = GenerateWorkingKey(true, part1);
|
||||
this._decryptionKey1 = GenerateWorkingKey(false, part1);
|
||||
|
||||
this._encryptionKey2 = GenerateWorkingKey(false, part2);
|
||||
this._decryptionKey2 = GenerateWorkingKey(true, part2);
|
||||
|
||||
if (key.Length == 24)
|
||||
{
|
||||
var part3 = new byte[8];
|
||||
Array.Copy(key, 16, part3, 0, 8);
|
||||
|
||||
this._encryptionKey3 = GenerateWorkingKey(true, part3);
|
||||
this._decryptionKey3 = GenerateWorkingKey(false, part3);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._encryptionKey3 = this._encryptionKey1;
|
||||
this._decryptionKey3 = this._decryptionKey1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,6 +48,31 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
|
||||
throw new IndexOutOfRangeException("output buffer too short");
|
||||
|
||||
if (this._encryptionKey1 == null || this._encryptionKey2 == null || this._encryptionKey3 == null)
|
||||
{
|
||||
var part1 = new byte[8];
|
||||
var part2 = new byte[8];
|
||||
|
||||
Array.Copy(this.Key, 0, part1, 0, 8);
|
||||
Array.Copy(this.Key, 8, part2, 0, 8);
|
||||
|
||||
this._encryptionKey1 = this.GenerateWorkingKey(true, part1);
|
||||
|
||||
this._encryptionKey2 = this.GenerateWorkingKey(false, part2);
|
||||
|
||||
if (this.Key.Length == 24)
|
||||
{
|
||||
var part3 = new byte[8];
|
||||
Array.Copy(this.Key, 16, part3, 0, 8);
|
||||
|
||||
this._encryptionKey3 = this.GenerateWorkingKey(true, part3);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._encryptionKey3 = this._encryptionKey1;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] temp = new byte[this.BlockSize];
|
||||
|
||||
DesCipher.DesFunc(this._encryptionKey1, inputBuffer, inputOffset, temp, 0);
|
||||
@@ -102,6 +101,30 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
|
||||
throw new IndexOutOfRangeException("output buffer too short");
|
||||
|
||||
if (this._decryptionKey1 == null || this._decryptionKey2 == null || this._decryptionKey3 == null)
|
||||
{
|
||||
var part1 = new byte[8];
|
||||
var part2 = new byte[8];
|
||||
|
||||
Array.Copy(this.Key, 0, part1, 0, 8);
|
||||
Array.Copy(this.Key, 8, part2, 0, 8);
|
||||
|
||||
this._decryptionKey1 = this.GenerateWorkingKey(false, part1);
|
||||
this._decryptionKey2 = this.GenerateWorkingKey(true, part2);
|
||||
|
||||
if (this.Key.Length == 24)
|
||||
{
|
||||
var part3 = new byte[8];
|
||||
Array.Copy(this.Key, 16, part3, 0, 8);
|
||||
|
||||
this._decryptionKey3 = this.GenerateWorkingKey(false, part3);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._decryptionKey3 = this._decryptionKey1;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] temp = new byte[this.BlockSize];
|
||||
|
||||
DesCipher.DesFunc(this._decryptionKey3, inputBuffer, inputOffset, temp, 0);
|
||||
@@ -112,18 +135,14 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// Validates the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
protected override void ValidateKey()
|
||||
{
|
||||
if (keySize == 128 || keySize == 128 + 64)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
var keySize = this.Key.Length * 8;
|
||||
|
||||
if (!(keySize == 128 || keySize == 128 + 64))
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding)
|
||||
: base(key, mode, padding)
|
||||
{
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
if (!(keySize == 128 || keySize == 192 || keySize == 256))
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
|
||||
// TODO: Refactor this algorithm
|
||||
|
||||
// calculate the MDS matrix
|
||||
@@ -50,20 +55,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
mX[1] = Mx_X(j) & 0xff;
|
||||
mY[1] = Mx_Y(j) & 0xff;
|
||||
|
||||
gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
|
||||
mY[P_00] << 16 | mY[P_00] << 24;
|
||||
gMDS0[i] = m1[P_00] | mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24;
|
||||
|
||||
gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
|
||||
mX[P_10] << 16 | m1[P_10] << 24;
|
||||
gMDS1[i] = mY[P_10] | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24;
|
||||
|
||||
gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
|
||||
m1[P_20] << 16 | mY[P_20] << 24;
|
||||
gMDS2[i] = mX[P_20] | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24;
|
||||
|
||||
gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
|
||||
mY[P_30] << 16 | mX[P_30] << 24;
|
||||
gMDS3[i] = mX[P_30] | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24;
|
||||
}
|
||||
|
||||
this.k64Cnt = (key.Length / 8); // pre-padded ?
|
||||
this.k64Cnt = key.Length / 8; // pre-padded ?
|
||||
this.SetKey(key);
|
||||
}
|
||||
|
||||
@@ -153,21 +154,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
return this.BlockSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>
|
||||
/// true if keySize is valid; otherwise false
|
||||
/// </returns>
|
||||
protected override bool ValidateKeySize(int keySize)
|
||||
{
|
||||
if (keySize == 128 || keySize == 192 || keySize == 256)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Static Definition Tables
|
||||
|
||||
private static readonly byte[,] P = {
|
||||
@@ -488,9 +474,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
{
|
||||
case 1:
|
||||
result = gMDS0[(P[P_01, b0] & 0xff) ^ M_b0(k0)] ^
|
||||
gMDS1[(P[P_11, b1] & 0xff) ^ M_b1(k0)] ^
|
||||
gMDS2[(P[P_21, b2] & 0xff) ^ M_b2(k0)] ^
|
||||
gMDS3[(P[P_31, b3] & 0xff) ^ M_b3(k0)];
|
||||
gMDS1[(P[P_11, b1] & 0xff) ^ M_b1(k0)] ^
|
||||
gMDS2[(P[P_21, b2] & 0xff) ^ M_b2(k0)] ^
|
||||
gMDS3[(P[P_31, b3] & 0xff) ^ M_b3(k0)];
|
||||
break;
|
||||
case 0: /* 256 bits of key */
|
||||
b0 = (P[P_04, b0] & 0xff) ^ M_b0(k3);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <summary>
|
||||
/// Implements DSA digital signature algorithm.
|
||||
/// </summary>
|
||||
public class DsaDigitalSignature : DigitalSignature
|
||||
public class DsaDigitalSignature : DigitalSignature, IDisposable
|
||||
{
|
||||
private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
|
||||
|
||||
@@ -138,5 +138,60 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
// The signature is (r, s)
|
||||
return r.ToByteArray().Reverse().TrimLeadingZero().Concat(s.ToByteArray().Reverse().TrimLeadingZero()).ToArray();
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Check to see if Dispose has already been called.
|
||||
if (!this._isDisposed)
|
||||
{
|
||||
// If disposing equals true, dispose all managed
|
||||
// and unmanaged ResourceMessages.
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed ResourceMessages.
|
||||
if (this._hash != null)
|
||||
{
|
||||
this._hash.Dispose();
|
||||
this._hash = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Note disposing has been done.
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources and performs other cleanup operations before the
|
||||
/// <see cref="SshCommand"/> is reclaimed by garbage collection.
|
||||
/// </summary>
|
||||
~DsaDigitalSignature()
|
||||
{
|
||||
// Do not re-create Dispose clean-up code here.
|
||||
// Calling Dispose(false) is optimal in terms of
|
||||
// readability and maintainability.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,34 +10,64 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Contains DSA private and public key
|
||||
/// </summary>
|
||||
public class DsaKey : Key
|
||||
public class DsaKey : Key, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets public key Y.
|
||||
/// Gets the P.
|
||||
/// </summary>
|
||||
public BigInteger Y { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets private key X.
|
||||
/// </summary>
|
||||
public BigInteger X { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the G.
|
||||
/// </summary>
|
||||
public BigInteger G { get; private set; }
|
||||
public BigInteger P
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
/// </summary>
|
||||
public BigInteger Q { get; private set; }
|
||||
public BigInteger Q
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
/// Gets the G.
|
||||
/// </summary>
|
||||
public BigInteger P { get; private set; }
|
||||
public BigInteger G
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[2];
|
||||
}
|
||||
}
|
||||
|
||||
private DigitalSignature _digitalSignature;
|
||||
/// <summary>
|
||||
/// Gets public key Y.
|
||||
/// </summary>
|
||||
public BigInteger Y
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[3];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets private key X.
|
||||
/// </summary>
|
||||
public BigInteger X
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[4];
|
||||
}
|
||||
}
|
||||
|
||||
private DsaDigitalSignature _digitalSignature;
|
||||
/// <summary>
|
||||
/// Gets the digital signature.
|
||||
/// </summary>
|
||||
@@ -69,37 +99,8 @@ namespace Renci.SshNet.Security
|
||||
{
|
||||
if (value.Length != 4)
|
||||
throw new InvalidOperationException("Invalid public key.");
|
||||
|
||||
this.P = value[0];
|
||||
this.Q = value[1];
|
||||
this.G = value[2];
|
||||
this.Y = value[3];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
protected override BigInteger[] Private
|
||||
{
|
||||
get
|
||||
{
|
||||
//return new BigInteger[] { this.P, this.Q, this.G, this.Y, this.X };
|
||||
return new BigInteger[] { this.P, this.Q, this.G, this.X };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 5)
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
|
||||
this.P = value[0];
|
||||
this.Q = value[1];
|
||||
this.G = value[2];
|
||||
this.Y = value[3];
|
||||
this.X = value[4];
|
||||
|
||||
this._privateKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ namespace Renci.SshNet.Security
|
||||
public DsaKey()
|
||||
: base()
|
||||
{
|
||||
|
||||
this._privateKey = new BigInteger[5];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +120,62 @@ namespace Renci.SshNet.Security
|
||||
public DsaKey(byte[] data)
|
||||
: base(data)
|
||||
{
|
||||
|
||||
if (this._privateKey.Length != 5)
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Check to see if Dispose has already been called.
|
||||
if (!this._isDisposed)
|
||||
{
|
||||
// If disposing equals true, dispose all managed
|
||||
// and unmanaged ResourceMessages.
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed ResourceMessages.
|
||||
if (this._digitalSignature != null)
|
||||
{
|
||||
this._digitalSignature.Dispose();
|
||||
this._digitalSignature = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Note disposing has been done.
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources and performs other cleanup operations before the
|
||||
/// <see cref="SshCommand"/> is reclaimed by garbage collection.
|
||||
/// </summary>
|
||||
~DsaKey()
|
||||
{
|
||||
// Do not re-create Dispose clean-up code here.
|
||||
// Calling Dispose(false) is optimal in terms of
|
||||
// readability and maintainability.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
private bool _isHashing;
|
||||
private byte[] _innerPadding;
|
||||
private byte[] _outerPadding;
|
||||
private byte[] _key;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the block.
|
||||
@@ -42,9 +43,9 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
|
||||
this.HashSizeValue = this._hash.HashSize;
|
||||
|
||||
this.Key = key;
|
||||
this._key = key;
|
||||
|
||||
this.Initialize();
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,38 +53,13 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public override byte[] Key
|
||||
{
|
||||
get { return (byte[])KeyValue.Clone(); }
|
||||
get
|
||||
{
|
||||
return (byte[])KeyValue.Clone();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this._isHashing)
|
||||
{
|
||||
throw new Exception("Cannot change key during hash operation");
|
||||
}
|
||||
if (value.Length > this.BlockSize)
|
||||
{
|
||||
this.KeyValue = this._hash.ComputeHash(value);
|
||||
// No need to call Initialize, ComputeHash does it automatically.
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeyValue = value.Clone() as byte[];
|
||||
}
|
||||
|
||||
this._innerPadding = new byte[this.BlockSize];
|
||||
this._outerPadding = new byte[this.BlockSize];
|
||||
|
||||
// Compute inner and outer padding.
|
||||
int i = 0;
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
this._innerPadding[i] = 0x36;
|
||||
this._outerPadding[i] = 0x5C;
|
||||
}
|
||||
for (i = 0; i < this.KeyValue.Length; i++)
|
||||
{
|
||||
this._innerPadding[i] ^= this.KeyValue[i];
|
||||
this._outerPadding[i] ^= this.KeyValue[i];
|
||||
}
|
||||
this.SetKey(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +68,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
this._isHashing = false;
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,6 +113,45 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
this._isHashing = false;
|
||||
|
||||
return this._hash.Hash;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalInitialize()
|
||||
{
|
||||
this._isHashing = false;
|
||||
this.SetKey(this._key);
|
||||
}
|
||||
|
||||
private void SetKey(byte[] value)
|
||||
{
|
||||
if (this._isHashing)
|
||||
{
|
||||
throw new Exception("Cannot change key during hash operation");
|
||||
}
|
||||
if (value.Length > this.BlockSize)
|
||||
{
|
||||
this.KeyValue = this._hash.ComputeHash(value);
|
||||
// No need to call Initialize, ComputeHash does it automatically.
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeyValue = value.Clone() as byte[];
|
||||
}
|
||||
|
||||
this._innerPadding = new byte[this.BlockSize];
|
||||
this._outerPadding = new byte[this.BlockSize];
|
||||
|
||||
// Compute inner and outer padding.
|
||||
int i = 0;
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
this._innerPadding[i] = 0x36;
|
||||
this._outerPadding[i] = 0x5C;
|
||||
}
|
||||
for (i = 0; i < this.KeyValue.Length; i++)
|
||||
{
|
||||
this._innerPadding[i] ^= this.KeyValue[i];
|
||||
this._outerPadding[i] ^= this.KeyValue[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public MD5Hash()
|
||||
{
|
||||
this.Initialize();
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -164,6 +164,11 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
private void InternalInitialize()
|
||||
{
|
||||
this._byteCount = 0;
|
||||
this._bufferOffset = 0;
|
||||
|
||||
@@ -96,8 +96,8 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
public SHA1Hash()
|
||||
{
|
||||
this._buffer = new byte[4];
|
||||
this.Initialize();
|
||||
}
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes data written to the object into the hash algorithm for computing the hash.
|
||||
@@ -181,21 +181,25 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
this._byteCount = 0;
|
||||
this._bufferOffset = 0;
|
||||
Array.Clear(this._buffer, 0, this._buffer.Length);
|
||||
|
||||
H1 = 0x67452301;
|
||||
H2 = 0xefcdab89;
|
||||
H3 = 0x98badcfe;
|
||||
H4 = 0x10325476;
|
||||
H5 = 0xc3d2e1f0;
|
||||
|
||||
this._offset = 0;
|
||||
Array.Clear(_hashValue, 0, _hashValue.Length);
|
||||
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
private void InternalInitialize()
|
||||
{
|
||||
this._byteCount = 0;
|
||||
this._bufferOffset = 0;
|
||||
Array.Clear(this._buffer, 0, this._buffer.Length);
|
||||
|
||||
H1 = 0x67452301;
|
||||
H2 = 0xefcdab89;
|
||||
H3 = 0x98badcfe;
|
||||
H4 = 0x10325476;
|
||||
H5 = 0xc3d2e1f0;
|
||||
|
||||
this._offset = 0;
|
||||
Array.Clear(_hashValue, 0, _hashValue.Length);
|
||||
}
|
||||
|
||||
private void Update(byte input)
|
||||
{
|
||||
this._buffer[this._bufferOffset++] = input;
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
public SHA256Hash()
|
||||
{
|
||||
this._buffer = new byte[4];
|
||||
this.Initialize();
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -179,24 +179,28 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
//this.Reset();
|
||||
this._byteCount = 0;
|
||||
this._bufferOffset = 0;
|
||||
Array.Clear(this._buffer, 0, this._buffer.Length);
|
||||
|
||||
H1 = 0x6a09e667;
|
||||
H2 = 0xbb67ae85;
|
||||
H3 = 0x3c6ef372;
|
||||
H4 = 0xa54ff53a;
|
||||
H5 = 0x510e527f;
|
||||
H6 = 0x9b05688c;
|
||||
H7 = 0x1f83d9ab;
|
||||
H8 = 0x5be0cd19;
|
||||
|
||||
this._offset = 0;
|
||||
Array.Clear(X, 0, X.Length);
|
||||
this.InternalInitialize();
|
||||
}
|
||||
|
||||
private void InternalInitialize()
|
||||
{
|
||||
this._byteCount = 0;
|
||||
this._bufferOffset = 0;
|
||||
Array.Clear(this._buffer, 0, this._buffer.Length);
|
||||
|
||||
H1 = 0x6a09e667;
|
||||
H2 = 0xbb67ae85;
|
||||
H3 = 0x3c6ef372;
|
||||
H4 = 0xa54ff53a;
|
||||
H5 = 0x510e527f;
|
||||
H6 = 0x9b05688c;
|
||||
H7 = 0x1f83d9ab;
|
||||
H8 = 0x5be0cd19;
|
||||
|
||||
this._offset = 0;
|
||||
Array.Clear(X, 0, X.Length);
|
||||
}
|
||||
|
||||
private void Update(byte input)
|
||||
{
|
||||
this._buffer[this._bufferOffset++] = input;
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace Renci.SshNet.Security
|
||||
/// </summary>
|
||||
public abstract class Key
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies array of big integers that represent private key
|
||||
/// </summary>
|
||||
protected BigInteger[] _privateKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key specific digital signature.
|
||||
/// </summary>
|
||||
@@ -25,14 +30,6 @@ namespace Renci.SshNet.Security
|
||||
/// </value>
|
||||
public abstract BigInteger[] Public { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
protected abstract BigInteger[] Private { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
@@ -51,7 +48,7 @@ namespace Renci.SshNet.Security
|
||||
keys.Add(der.ReadBigInteger());
|
||||
}
|
||||
|
||||
this.Private = keys.ToArray();
|
||||
this._privateKey = keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,15 +11,81 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <summary>
|
||||
/// Implements RSA digital signature algorithm.
|
||||
/// </summary>
|
||||
public class RsaDigitalSignature : CipherDigitalSignature
|
||||
public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
|
||||
{
|
||||
private HashAlgorithm _hash = new SHA1Hash();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
|
||||
/// </summary>
|
||||
/// <param name="rsaKey">The RSA key.</param>
|
||||
public RsaDigitalSignature(RsaKey rsaKey)
|
||||
: base(new SHA1Hash(), new ObjectIdentifier(1, 3, 14, 3, 2, 26), new RsaCipher(rsaKey))
|
||||
: base(new ObjectIdentifier(1, 3, 14, 3, 2, 26), new RsaCipher(rsaKey))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the specified input.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
protected override byte[] Hash(byte[] input)
|
||||
{
|
||||
return this._hash.ComputeHash(input);
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Check to see if Dispose has already been called.
|
||||
if (!this._isDisposed)
|
||||
{
|
||||
// If disposing equals true, dispose all managed
|
||||
// and unmanaged ResourceMessages.
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed ResourceMessages.
|
||||
if (this._hash != null)
|
||||
{
|
||||
this._hash.Dispose();
|
||||
this._hash = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Note disposing has been done.
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources and performs other cleanup operations before the
|
||||
/// <see cref="SshCommand"/> is reclaimed by garbage collection.
|
||||
/// </summary>
|
||||
~RsaDigitalSignature()
|
||||
{
|
||||
// Do not re-create Dispose clean-up code here.
|
||||
// Calling Dispose(false) is optimal in terms of
|
||||
// readability and maintainability.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,49 +10,115 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Contains RSA private and public key
|
||||
/// </summary>
|
||||
public class RsaKey : Key
|
||||
public class RsaKey : Key, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the modulus.
|
||||
/// </summary>
|
||||
public BigInteger Modulus { get; private set; }
|
||||
public BigInteger Modulus
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exponent.
|
||||
/// </summary>
|
||||
public BigInteger Exponent { get; private set; }
|
||||
public BigInteger Exponent
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._privateKey[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the D.
|
||||
/// </summary>
|
||||
public BigInteger D { get; private set; }
|
||||
public BigInteger D
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 2)
|
||||
return this._privateKey[2];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
/// </summary>
|
||||
public BigInteger P { get; private set; }
|
||||
public BigInteger P
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 3)
|
||||
return this._privateKey[3];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
/// </summary>
|
||||
public BigInteger Q { get; private set; }
|
||||
public BigInteger Q
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 4)
|
||||
return this._privateKey[4];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DP.
|
||||
/// </summary>
|
||||
public BigInteger DP { get; private set; }
|
||||
public BigInteger DP
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 5)
|
||||
return this._privateKey[5];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DQ.
|
||||
/// </summary>
|
||||
public BigInteger DQ { get; private set; }
|
||||
public BigInteger DQ
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 6)
|
||||
return this._privateKey[6];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inverse Q.
|
||||
/// </summary>
|
||||
public BigInteger InverseQ { get; private set; }
|
||||
public BigInteger InverseQ
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._privateKey.Length > 7)
|
||||
return this._privateKey[7];
|
||||
else
|
||||
return BigInteger.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private DigitalSignature _digitalSignature;
|
||||
private RsaDigitalSignature _digitalSignature;
|
||||
/// <summary>
|
||||
/// Gets the digital signature.
|
||||
/// </summary>
|
||||
@@ -85,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];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources
|
||||
/// </summary>
|
||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Check to see if Dispose has already been called.
|
||||
if (!this._isDisposed)
|
||||
{
|
||||
// If disposing equals true, dispose all managed
|
||||
// and unmanaged ResourceMessages.
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed ResourceMessages.
|
||||
if (this._digitalSignature != null)
|
||||
{
|
||||
this._digitalSignature.Dispose();
|
||||
this._digitalSignature = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Note disposing has been done.
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged resources and performs other cleanup operations before the
|
||||
/// <see cref="SshCommand"/> is reclaimed by garbage collection.
|
||||
/// </summary>
|
||||
~RsaKey()
|
||||
{
|
||||
// Do not re-create Dispose clean-up code here.
|
||||
// Calling Dispose(false) is optimal in terms of
|
||||
// readability and maintainability.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,9 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
public abstract class SymmetricCipher : Cipher
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the size of the key in bits.
|
||||
/// Gets the key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the key in bits.
|
||||
/// </value>
|
||||
public int KeySize { get; private set; }
|
||||
protected byte[] Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SymmetricCipher"/> class.
|
||||
@@ -24,16 +21,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="key">The key.</param>
|
||||
protected SymmetricCipher(byte[] key)
|
||||
{
|
||||
var keySize = key.Length * 8;
|
||||
|
||||
if (this.ValidateKeySize(keySize))
|
||||
{
|
||||
this.KeySize = keySize;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
|
||||
}
|
||||
this.Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,12 +49,5 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// The number of bytes decrypted.
|
||||
/// </returns>
|
||||
public abstract int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the size of the key.
|
||||
/// </summary>
|
||||
/// <param name="keySize">Size of the key.</param>
|
||||
/// <returns>true if keySize is valid; otherwise false</returns>
|
||||
protected abstract bool ValidateKeySize(int keySize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,8 +283,10 @@ namespace Renci.SshNet.Security
|
||||
/// <summary>
|
||||
/// Hashes the specified data bytes.
|
||||
/// </summary>
|
||||
/// <param name="hashBytes">Data to hash.</param>
|
||||
/// <returns>Hashed bytes</returns>
|
||||
/// <param name="hashData">The hash data.</param>
|
||||
/// <returns>
|
||||
/// Hashed bytes
|
||||
/// </returns>
|
||||
protected virtual byte[] Hash(byte[] hashData)
|
||||
{
|
||||
using (var sha1 = new Renci.SshNet.Security.Cryptography.SHA1Hash())
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user