Skip to content

Commit c0da2c1

Browse files
committed
Make key exchange more efficient by using byte[] in our internal structures, and convert to BigInteger when necessary.
Fixes #643. Introduce base classes for DiffieHelman group key exchange. Eliminate code duplication.
1 parent 93f092c commit c0da2c1

20 files changed

+362
-399
lines changed

src/Renci.SshNet/Common/Extensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ internal static BigInteger ToBigInteger(this byte[] data)
7272
return new BigInteger(reversed.Reverse());
7373
}
7474

75+
/// <summary>
76+
/// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format
77+
/// </summary>
78+
public static byte[] ToBigNum2(this byte[] data)
79+
{
80+
if ((data[0] & (1 << 7)) != 0)
81+
{
82+
var buf = new byte[data.Length + 1];
83+
Buffer.BlockCopy(data, 0, buf, 1, data.Length);
84+
data = buf;
85+
}
86+
87+
return data;
88+
}
89+
7590
/// <summary>
7691
/// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format
7792
/// </summary>

src/Renci.SshNet/ConnectionInfo.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,6 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
331331
{"diffie-hellman-group-exchange-sha1", typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)},
332332
{"diffie-hellman-group14-sha1", typeof (KeyExchangeDiffieHellmanGroup14Sha1)},
333333
{"diffie-hellman-group1-sha1", typeof (KeyExchangeDiffieHellmanGroup1Sha1)},
334-
//"gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD
335-
//"gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD
336334
};
337335

338336
Encryptions = new Dictionary<string, CipherInfo>

src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
1-
using Renci.SshNet.Common;
2-
3-
namespace Renci.SshNet.Messages.Transport
1+
namespace Renci.SshNet.Messages.Transport
42
{
53
/// <summary>
64
/// Represents SSH_MSG_KEX_DH_GEX_INIT message.
75
/// </summary>
86
[Message("SSH_MSG_KEX_DH_GEX_INIT", 32)]
97
internal class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed
108
{
11-
private byte[] _eBytes;
12-
139
/// <summary>
1410
/// Gets the E value.
1511
/// </summary>
16-
public BigInteger E
17-
{
18-
get { return _eBytes.ToBigInteger(); }
19-
}
12+
public byte[] E { get; private set; }
2013

2114
/// <summary>
2215
/// Gets the size of the message in bytes.
@@ -30,7 +23,7 @@ protected override int BufferCapacity
3023
{
3124
var capacity = base.BufferCapacity;
3225
capacity += 4; // E length
33-
capacity += _eBytes.Length; // E
26+
capacity += E.Length; // E
3427
return capacity;
3528
}
3629
}
@@ -39,25 +32,25 @@ protected override int BufferCapacity
3932
/// Initializes a new instance of the <see cref="KeyExchangeDhGroupExchangeInit"/> class.
4033
/// </summary>
4134
/// <param name="clientExchangeValue">The client exchange value.</param>
42-
public KeyExchangeDhGroupExchangeInit(BigInteger clientExchangeValue)
35+
public KeyExchangeDhGroupExchangeInit(byte[] clientExchangeValue)
4336
{
44-
_eBytes = clientExchangeValue.ToByteArray().Reverse();
37+
E = clientExchangeValue;
4538
}
4639

4740
/// <summary>
4841
/// Called when type specific data need to be loaded.
4942
/// </summary>
5043
protected override void LoadData()
5144
{
52-
_eBytes = ReadBinary();
45+
E = ReadBinary();
5346
}
5447

5548
/// <summary>
5649
/// Called when type specific data need to be saved.
5750
/// </summary>
5851
protected override void SaveData()
5952
{
60-
WriteBinaryString(_eBytes);
53+
WriteBinaryString(E);
6154
}
6255

6356
internal override void Process(Session session)

src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ internal class KeyExchangeDhGroupExchangeReply : Message
1010
{
1111
internal const byte MessageNumber = 33;
1212

13-
private byte[] _fBytes;
14-
1513
/// <summary>
1614
/// Gets server public host key and certificates
1715
/// </summary>
@@ -21,10 +19,7 @@ internal class KeyExchangeDhGroupExchangeReply : Message
2119
/// <summary>
2220
/// Gets the F value.
2321
/// </summary>
24-
public BigInteger F
25-
{
26-
get { return _fBytes.ToBigInteger(); }
27-
}
22+
public byte[] F { get; private set; }
2823

2924
/// <summary>
3025
/// Gets the signature of H.
@@ -46,7 +41,7 @@ protected override int BufferCapacity
4641
capacity += 4; // HostKey length
4742
capacity += HostKey.Length; // HostKey
4843
capacity += 4; // F length
49-
capacity += _fBytes.Length; // F
44+
capacity += F.Length; // F
5045
capacity += 4; // Signature length
5146
capacity += Signature.Length; // Signature
5247
return capacity;
@@ -59,7 +54,7 @@ protected override int BufferCapacity
5954
protected override void LoadData()
6055
{
6156
HostKey = ReadBinary();
62-
_fBytes = ReadBinary();
57+
F = ReadBinary();
6358
Signature = ReadBinary();
6459
}
6560

@@ -69,7 +64,7 @@ protected override void LoadData()
6964
protected override void SaveData()
7065
{
7166
WriteBinaryString(HostKey);
72-
WriteBinaryString(_fBytes);
67+
WriteBinaryString(F);
7368
WriteBinaryString(Signature);
7469
}
7570

src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
1-
using Renci.SshNet.Common;
2-
3-
namespace Renci.SshNet.Messages.Transport
1+
namespace Renci.SshNet.Messages.Transport
42
{
53
/// <summary>
64
/// Represents SSH_MSG_KEXDH_INIT message.
75
/// </summary>
86
[Message("SSH_MSG_KEXDH_INIT", 30)]
97
internal class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed
108
{
11-
private byte[] _eBytes;
12-
139
/// <summary>
1410
/// Gets the E value.
1511
/// </summary>
16-
public BigInteger E
17-
{
18-
get { return _eBytes.ToBigInteger(); }
19-
}
12+
public byte[] E { get; private set; }
2013

2114
/// <summary>
2215
/// Gets the size of the message in bytes.
@@ -30,7 +23,7 @@ protected override int BufferCapacity
3023
{
3124
var capacity = base.BufferCapacity;
3225
capacity += 4; // E length
33-
capacity += _eBytes.Length; // E
26+
capacity += E.Length; // E
3427
return capacity;
3528
}
3629
}
@@ -39,25 +32,25 @@ protected override int BufferCapacity
3932
/// Initializes a new instance of the <see cref="KeyExchangeDhInitMessage"/> class.
4033
/// </summary>
4134
/// <param name="clientExchangeValue">The client exchange value.</param>
42-
public KeyExchangeDhInitMessage(BigInteger clientExchangeValue)
35+
public KeyExchangeDhInitMessage(byte[] clientExchangeValue)
4336
{
44-
_eBytes = clientExchangeValue.ToByteArray().Reverse();
37+
E = clientExchangeValue;
4538
}
4639

4740
/// <summary>
4841
/// Called when type specific data need to be loaded.
4942
/// </summary>
5043
protected override void LoadData()
5144
{
52-
_eBytes = ReadBinary();
45+
E = ReadBinary();
5346
}
5447

5548
/// <summary>
5649
/// Called when type specific data need to be saved.
5750
/// </summary>
5851
protected override void SaveData()
5952
{
60-
WriteBinaryString(_eBytes);
53+
WriteBinaryString(E);
6154
}
6255

6356
internal override void Process(Session session)

src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
using Renci.SshNet.Common;
2-
3-
namespace Renci.SshNet.Messages.Transport
1+
namespace Renci.SshNet.Messages.Transport
42
{
53
/// <summary>
64
/// Represents SSH_MSG_KEXDH_REPLY message.
75
/// </summary>
86
[Message("SSH_MSG_KEXDH_REPLY", 31)]
97
public class KeyExchangeDhReplyMessage : Message
108
{
11-
private byte[] _fBytes;
12-
139
/// <summary>
1410
/// Gets server public host key and certificates
1511
/// </summary>
@@ -19,10 +15,7 @@ public class KeyExchangeDhReplyMessage : Message
1915
/// <summary>
2016
/// Gets the F value.
2117
/// </summary>
22-
public BigInteger F
23-
{
24-
get { return _fBytes.ToBigInteger(); }
25-
}
18+
public byte[] F { get; private set; }
2619

2720
/// <summary>
2821
/// Gets the signature of H.
@@ -44,7 +37,7 @@ protected override int BufferCapacity
4437
capacity += 4; // HostKey length
4538
capacity += HostKey.Length; // HostKey
4639
capacity += 4; // F length
47-
capacity += _fBytes.Length; // F
40+
capacity += F.Length; // F
4841
capacity += 4; // Signature length
4942
capacity += Signature.Length; // Signature
5043
return capacity;
@@ -57,7 +50,7 @@ protected override int BufferCapacity
5750
protected override void LoadData()
5851
{
5952
HostKey = ReadBinary();
60-
_fBytes = ReadBinary();
53+
F = ReadBinary();
6154
Signature = ReadBinary();
6255
}
6356

@@ -67,7 +60,7 @@ protected override void LoadData()
6760
protected override void SaveData()
6861
{
6962
WriteBinaryString(HostKey);
70-
WriteBinaryString(_fBytes);
63+
WriteBinaryString(F);
7164
WriteBinaryString(Signature);
7265
}
7366

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' ">
3232
<PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
33-
<PackageReference Include="System.Security.Cryptography.Cng" Version="4.7.0" />
3433
</ItemGroup>
3534

3635
<PropertyGroup Condition=" '$(TargetFramework)' == 'net35' ">

src/Renci.SshNet/Security/GroupExchangeHashData.cs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ internal class GroupExchangeHashData : SshData
99
private byte[] _clientVersion;
1010
private byte[] _prime;
1111
private byte[] _subGroup;
12-
private byte[] _clientExchangeValue;
13-
private byte[] _serverExchangeValue;
14-
private byte[] _sharedKey;
1512

1613
public string ServerVersion
1714
{
@@ -50,23 +47,11 @@ public BigInteger SubGroup
5047
set { _subGroup = value.ToByteArray().Reverse(); }
5148
}
5249

53-
public BigInteger ClientExchangeValue
54-
{
55-
private get { return _clientExchangeValue.ToBigInteger(); }
56-
set { _clientExchangeValue = value.ToByteArray().Reverse(); }
57-
}
50+
public byte[] ClientExchangeValue { get; set; }
5851

59-
public BigInteger ServerExchangeValue
60-
{
61-
private get { return _serverExchangeValue.ToBigInteger(); }
62-
set { _serverExchangeValue = value.ToByteArray().Reverse(); }
63-
}
52+
public byte[] ServerExchangeValue { get; set; }
6453

65-
public BigInteger SharedKey
66-
{
67-
private get { return _sharedKey.ToBigInteger(); }
68-
set { _sharedKey = value.ToByteArray().Reverse(); }
69-
}
54+
public byte[] SharedKey { get; set; }
7055

7156
/// <summary>
7257
/// Gets the size of the message in bytes.
@@ -97,11 +82,11 @@ protected override int BufferCapacity
9782
capacity += 4; // SubGroup length
9883
capacity += _subGroup.Length; // SubGroup
9984
capacity += 4; // ClientExchangeValue length
100-
capacity += _clientExchangeValue.Length; // ClientExchangeValue
85+
capacity += ClientExchangeValue.Length; // ClientExchangeValue
10186
capacity += 4; // ServerExchangeValue length
102-
capacity += _serverExchangeValue.Length; // ServerExchangeValue
87+
capacity += ServerExchangeValue.Length; // ServerExchangeValue
10388
capacity += 4; // SharedKey length
104-
capacity += _sharedKey.Length; // SharedKey
89+
capacity += SharedKey.Length; // SharedKey
10590
return capacity;
10691
}
10792
}
@@ -123,9 +108,9 @@ protected override void SaveData()
123108
Write(MaximumGroupSize);
124109
WriteBinaryString(_prime);
125110
WriteBinaryString(_subGroup);
126-
WriteBinaryString(_clientExchangeValue);
127-
WriteBinaryString(_serverExchangeValue);
128-
WriteBinaryString(_sharedKey);
111+
WriteBinaryString(ClientExchangeValue);
112+
WriteBinaryString(ServerExchangeValue);
113+
WriteBinaryString(SharedKey);
129114
}
130115
}
131116
}

0 commit comments

Comments
 (0)