using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security.Chaos.NaCl; using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10; namespace Renci.SshNet.Security { internal sealed class KeyExchangeECCurve25519 : KeyExchangeEC { private byte[] _privateKey; /// /// 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; } } /// /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. public override void Start(Session session, KeyExchangeInitMessage message) { base.Start(session, message); Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; var basepoint = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; basepoint[0] = 9; _privateKey = CryptoAbstraction.GenerateRandom(MontgomeryCurve25519.PrivateKeySizeInBytes); _clientExchangeValue = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; MontgomeryOperations.scalarmult(_clientExchangeValue, 0, _privateKey, 0, basepoint, 0); 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) { using (var sha256 = CryptoAbstraction.CreateSHA256()) { return sha256.ComputeHash(hashData, 0, hashData.Length); } } 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 sharedKey = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; MontgomeryOperations.scalarmult(sharedKey, 0, _privateKey, 0, serverExchangeValue, 0); SharedKey = sharedKey.ToBigInteger2().ToByteArray().Reverse(); } } }