From 89b199b5e2186bd43e949a1962d88623f74ee22a Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Wed, 13 Aug 2025 19:05:34 +0200 Subject: [PATCH] Fix key material extension during key exchange When the key exchange produces less key material than is needed for the cipher or hmac algorithms, there is an iterative procedure to produce more. For example, a SHA-1 key exchange algorithm produces 20 bytes of key material. A SHA-256 hmac uses a 32 byte key, so one iteration of the procedure produces another 20 bytes of key material for a total of 40 which is sufficient for the hmac key. The library works correctly in such cases of one iteration, but the logic is wrong if more than one iteration is needed. In #1660, the connection uses a SHA-1 kex algorithm with a SHA-512 hmac (64 byte key), requiring 3 iterations of the extension procedure and resulting in an error upon connection. This change fixes the logic to use the output of the previous iteration per the spec. closes #1660 --- src/Renci.SshNet/Security/KeyExchange.cs | 9 +++------ test/Renci.SshNet.IntegrationTests/HmacTests.cs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 05b1459c3..834b71e24 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; @@ -530,9 +529,7 @@ protected void SendMessage(Message message) /// private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] key, int size) { - var result = new List(key); - - while (size > result.Count) + while (key.Length < size) { var sessionKeyAdjustment = new SessionKeyAdjustment { @@ -541,10 +538,10 @@ private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] Key = key, }; - result.AddRange(Hash(sessionKeyAdjustment.GetBytes())); + key = key.Concat(Hash(sessionKeyAdjustment.GetBytes())); } - return result.ToArray(); + return key; } /// diff --git a/test/Renci.SshNet.IntegrationTests/HmacTests.cs b/test/Renci.SshNet.IntegrationTests/HmacTests.cs index 261b17a1a..e33f3fa8a 100644 --- a/test/Renci.SshNet.IntegrationTests/HmacTests.cs +++ b/test/Renci.SshNet.IntegrationTests/HmacTests.cs @@ -40,6 +40,22 @@ public void HmacSha2_512() DoTest(MessageAuthenticationCodeAlgorithm.HmacSha2_512); } + [TestMethod] + public void HmacSha2_512_ShortKexOutput() + { + _remoteSshdConfig.ClearMessageAuthenticationCodeAlgorithms() + .AddMessageAuthenticationCodeAlgorithm(MessageAuthenticationCodeAlgorithm.HmacSha2_512) + .ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroupExchangeSha1) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } [TestMethod] public void HmacSha1_Etm()