Skip to content

Commit 085dead

Browse files
authored
Add a plaintext receive buffer (#1752)
Continuing from previous changes, add a persistent buffer into which the message payload is decrypted, rather than allocating a new array each time.
1 parent 1a97749 commit 085dead

File tree

2 files changed

+24
-19
lines changed

2 files changed

+24
-19
lines changed

src/Renci.SshNet/Security/Cryptography/Ciphers/AesGcmCipher.BclImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public override void Decrypt(byte[] input, int cipherTextOffset, int cipherTextL
3939

4040
try
4141
{
42-
_aesGcm.Decrypt(_nonce, cipherText, tag, output.AsSpan(plainTextOffset), associatedData);
42+
_aesGcm.Decrypt(_nonce, cipherText, tag, output.AsSpan(plainTextOffset, cipherTextLength), associatedData);
4343
}
4444
catch (AuthenticationTagMismatchException ex)
4545
{

src/Renci.SshNet/Session.cs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ public sealed class Session : ISession
200200
private Socket _socket;
201201

202202
private ArrayBuffer _receiveBuffer = new(4 * 1024);
203+
private byte[] _plaintextReceiveBuffer = new byte[4 * 1024];
203204

204205
/// <summary>
205206
/// Gets the session semaphore that controls session channels.
@@ -1319,19 +1320,24 @@ private Message ReceiveMessage(Socket socket)
13191320

13201321
// Construct buffer for holding the payload and the inbound packet sequence as we need both in order
13211322
// to generate the hash.
1322-
var data = new byte[4 + totalPacketLength - serverMacLength];
1323+
var plaintextLength = 4 + totalPacketLength - serverMacLength;
13231324

1324-
BinaryPrimitives.WriteUInt32BigEndian(data, _inboundPacketSequence);
1325+
if (_plaintextReceiveBuffer.Length < plaintextLength)
1326+
{
1327+
Array.Resize(ref _plaintextReceiveBuffer, Math.Max(plaintextLength, 2 * _plaintextReceiveBuffer.Length));
1328+
}
1329+
1330+
BinaryPrimitives.WriteUInt32BigEndian(_plaintextReceiveBuffer, _inboundPacketSequence);
13251331

1326-
plainFirstBlock.AsSpan().CopyTo(data.AsSpan(4));
1332+
plainFirstBlock.AsSpan().CopyTo(_plaintextReceiveBuffer.AsSpan(4));
13271333

13281334
if (_serverMac != null && _serverEtm)
13291335
{
13301336
// ETM mac = MAC(key, sequence_number || packet_length || encrypted_packet)
13311337

13321338
// sequence_number
13331339
_ = _serverMac.TransformBlock(
1334-
inputBuffer: data,
1340+
inputBuffer: _plaintextReceiveBuffer,
13351341
inputOffset: 0,
13361342
inputCount: 4,
13371343
outputBuffer: null,
@@ -1363,21 +1369,23 @@ private Message ReceiveMessage(Socket socket)
13631369
input: _receiveBuffer.DangerousGetUnderlyingBuffer(),
13641370
offset: _receiveBuffer.ActiveStartOffset + blockSize,
13651371
length: numberOfBytesToDecrypt,
1366-
output: data,
1372+
output: _plaintextReceiveBuffer,
13671373
outputOffset: 4 + blockSize);
13681374

13691375
Debug.Assert(numberOfBytesDecrypted == numberOfBytesToDecrypt);
13701376
}
13711377
else
13721378
{
1373-
_receiveBuffer.ActiveReadOnlySpan.Slice(blockSize, numberOfBytesToDecrypt).CopyTo(data.AsSpan(4 + blockSize));
1379+
_receiveBuffer.ActiveReadOnlySpan
1380+
.Slice(blockSize, numberOfBytesToDecrypt)
1381+
.CopyTo(_plaintextReceiveBuffer.AsSpan(4 + blockSize));
13741382
}
13751383

13761384
if (_serverMac != null && !_serverEtm)
13771385
{
13781386
// non-ETM mac = MAC(key, sequence_number || unencrypted_packet)
13791387

1380-
var clientHash = _serverMac.ComputeHash(data);
1388+
var clientHash = _serverMac.ComputeHash(_plaintextReceiveBuffer, 0, plaintextLength);
13811389

13821390
if (!CryptoAbstraction.FixedTimeEquals(clientHash, _receiveBuffer.ActiveSpan.Slice(totalPacketLength - serverMacLength, serverMacLength)))
13831391
{
@@ -1387,19 +1395,16 @@ private Message ReceiveMessage(Socket socket)
13871395

13881396
_receiveBuffer.Discard(totalPacketLength);
13891397

1390-
var paddingLength = data[inboundPacketSequenceLength + packetLengthFieldLength];
1391-
var messagePayloadLength = packetLength - paddingLength - paddingLengthFieldLength;
1392-
var messagePayloadOffset = inboundPacketSequenceLength + packetLengthFieldLength + paddingLengthFieldLength;
1398+
var paddingLength = _plaintextReceiveBuffer[inboundPacketSequenceLength + packetLengthFieldLength];
1399+
1400+
ArraySegment<byte> payload = new(
1401+
_plaintextReceiveBuffer,
1402+
offset: inboundPacketSequenceLength + packetLengthFieldLength + paddingLengthFieldLength,
1403+
count: packetLength - paddingLength - paddingLengthFieldLength);
13931404

13941405
if (_serverDecompression != null)
13951406
{
1396-
data = _serverDecompression.Decompress(data, messagePayloadOffset, messagePayloadLength);
1397-
1398-
// Data now only contains the decompressed payload, and as such the offset is reset to zero
1399-
messagePayloadOffset = 0;
1400-
1401-
// The length of the payload is now the complete decompressed content
1402-
messagePayloadLength = data.Length;
1407+
payload = new(_serverDecompression.Decompress(payload.Array, payload.Offset, payload.Count));
14031408
}
14041409

14051410
_inboundPacketSequence++;
@@ -1411,7 +1416,7 @@ private Message ReceiveMessage(Socket socket)
14111416
throw new SshConnectionException("Inbound packet sequence number is about to wrap during initial key exchange.", DisconnectReason.KeyExchangeFailed);
14121417
}
14131418

1414-
return LoadMessage(data, messagePayloadOffset, messagePayloadLength);
1419+
return LoadMessage(payload.Array, payload.Offset, payload.Count);
14151420
}
14161421

14171422
private void TrySendDisconnect(DisconnectReason reasonCode, string message)

0 commit comments

Comments
 (0)