|
|
@@ -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();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|