|  | @@ -0,0 +1,99 @@
 | 
	
		
			
				|  |  | +using System;
 | 
	
		
			
				|  |  | +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 class KeyExchangeECCurve25519 : KeyExchangeEC
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        private byte[] _privateKey;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Gets algorithm name.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        public override string Name
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get { return "curve25519-sha256"; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Gets the size, in bits, of the computed hash code.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <value>
 | 
	
		
			
				|  |  | +        /// The size, in bits, of the computed hash code.
 | 
	
		
			
				|  |  | +        /// </value>
 | 
	
		
			
				|  |  | +        protected override int HashSize
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get { return 256; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Starts key exchange algorithm
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="session">The session.</param>
 | 
	
		
			
				|  |  | +        /// <param name="message">Key exchange init message.</param>
 | 
	
		
			
				|  |  | +        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;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var rnd = new Random();
 | 
	
		
			
				|  |  | +            _privateKey = new byte[MontgomeryCurve25519.PrivateKeySizeInBytes];
 | 
	
		
			
				|  |  | +            rnd.NextBytes(_privateKey);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            _clientExchangeValue = new byte[MontgomeryCurve25519.PublicKeySizeInBytes];
 | 
	
		
			
				|  |  | +            MontgomeryOperations.scalarmult(_clientExchangeValue, 0, _privateKey, 0, basepoint, 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Finishes key exchange algorithm.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        public override void Finish()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            base.Finish();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeEcdhReplyMessage> 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();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Handles the server DH reply message.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="hostKey">The host key.</param>
 | 
	
		
			
				|  |  | +        /// <param name="serverExchangeValue">The server exchange value.</param>
 | 
	
		
			
				|  |  | +        /// <param name="signature">The signature.</param>
 | 
	
		
			
				|  |  | +        protected override void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            _serverExchangeValue = serverExchangeValue;
 | 
	
		
			
				|  |  | +            _hostKey = hostKey;
 | 
	
		
			
				|  |  | +            _serverExchangeValue = serverExchangeValue;
 | 
	
		
			
				|  |  | +            _signature = signature;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var sharedKey = new byte[MontgomeryCurve25519.PublicKeySizeInBytes];
 | 
	
		
			
				|  |  | +            MontgomeryOperations.scalarmult(sharedKey, 0, _privateKey, 0, serverExchangeValue, 0);
 | 
	
		
			
				|  |  | +            SharedKey = sharedKey.ToBigInteger2();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 |