<PackageReference Include="SSH.NET" Version="2024.2.0" />

KeyExchangeECCurve25519

using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Agreement; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Security { internal sealed class KeyExchangeECCurve25519 : KeyExchangeEC { private X25519Agreement _keyAgreement; public override string Name => "curve25519-sha256"; protected override int HashSize => 256; public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { base.Start(session, message, sendClientInitMessage); base.Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); base.Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; X25519KeyPairGenerator val = new X25519KeyPairGenerator(); val.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom)); AsymmetricCipherKeyPair val2 = val.GenerateKeyPair(); _keyAgreement = new X25519Agreement(); _keyAgreement.Init(val2.get_Private()); _clientExchangeValue = val2.get_Public().GetEncoded(); SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); } public override void Finish() { base.Finish(); base.Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; } protected override byte[] Hash(byte[] hashData) { return CryptoAbstraction.HashSHA256(hashData); } private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeEcdhReplyMessage> e) { KeyExchangeEcdhReplyMessage message = e.Message; base.Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); HandleServerEcdhReply(message.KS, message.QS, message.Signature); Finish(); } private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) { _serverExchangeValue = serverExchangeValue; _hostKey = hostKey; _signature = signature; X25519PublicKeyParameters val = new X25519PublicKeyParameters(serverExchangeValue); byte[] array = new byte[_keyAgreement.get_AgreementSize()]; _keyAgreement.CalculateAgreement(val, array, 0); base.SharedKey = Extensions.ToByteArray(array.ToBigInteger2(), false, true); } } }