|  | @@ -1,7 +1,6 @@
 | 
	
		
			
				|  |  |  using System.Globalization;
 | 
	
		
			
				|  |  |  using System.Linq;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -using Org.BouncyCastle.Crypto.Agreement;
 | 
	
		
			
				|  |  |  using Org.BouncyCastle.Crypto.Generators;
 | 
	
		
			
				|  |  |  using Org.BouncyCastle.Crypto.Kems;
 | 
	
		
			
				|  |  |  using Org.BouncyCastle.Crypto.Parameters;
 | 
	
	
		
			
				|  | @@ -12,10 +11,9 @@ using Renci.SshNet.Messages.Transport;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace Renci.SshNet.Security
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    internal sealed class KeyExchangeMLKem768X25519Sha256 : KeyExchangeEC
 | 
	
		
			
				|  |  | +    internal sealed class KeyExchangeMLKem768X25519Sha256 : KeyExchangeECCurve25519
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          private MLKemDecapsulator _mlkemDecapsulator;
 | 
	
		
			
				|  |  | -        private X25519Agreement _x25519Agreement;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// Gets algorithm name.
 | 
	
	
		
			
				|  | @@ -37,10 +35,8 @@ namespace Renci.SshNet.Security
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <inheritdoc/>
 | 
	
		
			
				|  |  | -        public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage)
 | 
	
		
			
				|  |  | +        protected override void StartImpl()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            base.Start(session, message, sendClientInitMessage);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              Session.RegisterMessage("SSH_MSG_KEX_HYBRID_REPLY");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              Session.KeyExchangeHybridReplyMessageReceived += Session_KeyExchangeHybridReplyMessageReceived;
 | 
	
	
		
			
				|  | @@ -52,28 +48,18 @@ namespace Renci.SshNet.Security
 | 
	
		
			
				|  |  |              _mlkemDecapsulator = new MLKemDecapsulator(MLKemParameters.ml_kem_768);
 | 
	
		
			
				|  |  |              _mlkemDecapsulator.Init(mlkem768KeyPair.Private);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var x25519KeyPairGenerator = new X25519KeyPairGenerator();
 | 
	
		
			
				|  |  | -            x25519KeyPairGenerator.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
 | 
	
		
			
				|  |  | -            var x25519KeyPair = x25519KeyPairGenerator.GenerateKeyPair();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            _x25519Agreement = new X25519Agreement();
 | 
	
		
			
				|  |  | -            _x25519Agreement.Init(x25519KeyPair.Private);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              var mlkem768PublicKey = ((MLKemPublicKeyParameters)mlkem768KeyPair.Public).GetEncoded();
 | 
	
		
			
				|  |  | -            var x25519PublicKey = ((X25519PublicKeyParameters)x25519KeyPair.Public).GetEncoded();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var x25519PublicKey = _impl.GenerateClientPublicKey();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              _clientExchangeValue = mlkem768PublicKey.Concat(x25519PublicKey);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              SendMessage(new KeyExchangeHybridInitMessage(_clientExchangeValue));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Finishes key exchange algorithm.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        public override void Finish()
 | 
	
		
			
				|  |  | +        /// <inheritdoc/>
 | 
	
		
			
				|  |  | +        protected override void FinishImpl()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            base.Finish();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              Session.KeyExchangeHybridReplyMessageReceived -= Session_KeyExchangeHybridReplyMessageReceived;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -114,21 +100,20 @@ namespace Renci.SshNet.Security
 | 
	
		
			
				|  |  |              _hostKey = hostKey;
 | 
	
		
			
				|  |  |              _signature = signature;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (serverExchangeValue.Length != _mlkemDecapsulator.EncapsulationLength + _x25519Agreement.AgreementSize)
 | 
	
		
			
				|  |  | +            if (serverExchangeValue.Length != _mlkemDecapsulator.EncapsulationLength + X25519PublicKeyParameters.KeySize)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  throw new SshConnectionException(
 | 
	
		
			
				|  |  |                      string.Format(CultureInfo.CurrentCulture, "Bad S_Reply length: {0}.", serverExchangeValue.Length),
 | 
	
		
			
				|  |  |                      DisconnectReason.KeyExchangeFailed);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var secret = new byte[_mlkemDecapsulator.SecretLength + _x25519Agreement.AgreementSize];
 | 
	
		
			
				|  |  | +            var mlkemSecret = new byte[_mlkemDecapsulator.SecretLength];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            _mlkemDecapsulator.Decapsulate(serverExchangeValue, 0, _mlkemDecapsulator.EncapsulationLength, secret, 0, _mlkemDecapsulator.SecretLength);
 | 
	
		
			
				|  |  | +            _mlkemDecapsulator.Decapsulate(serverExchangeValue, 0, _mlkemDecapsulator.EncapsulationLength, mlkemSecret, 0, _mlkemDecapsulator.SecretLength);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var x25519PublicKey = new X25519PublicKeyParameters(serverExchangeValue, _mlkemDecapsulator.EncapsulationLength);
 | 
	
		
			
				|  |  | -            _x25519Agreement.CalculateAgreement(x25519PublicKey, secret, _mlkemDecapsulator.SecretLength);
 | 
	
		
			
				|  |  | +            var x25519Agreement = _impl.CalculateAgreement(serverExchangeValue.Take(_mlkemDecapsulator.EncapsulationLength, X25519PublicKeyParameters.KeySize));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            SharedKey = CryptoAbstraction.HashSHA256(secret);
 | 
	
		
			
				|  |  | +            SharedKey = CryptoAbstraction.HashSHA256(mlkemSecret.Concat(x25519Agreement));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |