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; /// /// Gets algorithm name. /// public override string Name { get { return "curve25519-sha256"; } } /// /// Gets the size, in bits, of the computed hash code. /// /// /// The size, in bits, of the computed hash code. /// protected override int HashSize { get { return 256; } } /// public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { base.Start(session, message, sendClientInitMessage); Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; var g = new X25519KeyPairGenerator(); g.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom)); var aKeyPair = g.GenerateKeyPair(); _keyAgreement = new X25519Agreement(); _keyAgreement.Init(aKeyPair.Private); _clientExchangeValue = ((X25519PublicKeyParameters)aKeyPair.Public).GetEncoded(); SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); } /// /// Finishes key exchange algorithm. /// public override void Finish() { base.Finish(); Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; } /// /// Hashes the specified data bytes. /// /// The hash data. /// /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { return CryptoAbstraction.HashSHA256(hashData); } private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs e) { var message = e.Message; // Unregister message once received Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); HandleServerEcdhReply(message.KS, message.QS, message.Signature); // When SSH_MSG_KEXDH_REPLY received key exchange is completed Finish(); } /// /// Handles the server DH reply message. /// /// The host key. /// The server exchange value. /// The signature. private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) { _serverExchangeValue = serverExchangeValue; _hostKey = hostKey; _signature = signature; var publicKey = new X25519PublicKeyParameters(serverExchangeValue); var k1 = new byte[_keyAgreement.AgreementSize]; _keyAgreement.CalculateAgreement(publicKey, k1, 0); SharedKey = k1.ToBigInteger2().ToByteArray(isBigEndian: true); } } }