| | | 1 | | using System; |
| | | 2 | | using Renci.SshNet.Common; |
| | | 3 | | using Renci.SshNet.Messages.Transport; |
| | | 4 | | |
| | | 5 | | using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; |
| | | 6 | | using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement; |
| | | 7 | | using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Generators; |
| | | 8 | | using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters; |
| | | 9 | | using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; |
| | | 10 | | using Renci.SshNet.Security.Org.BouncyCastle.Security; |
| | | 11 | | |
| | | 12 | | namespace Renci.SshNet.Security |
| | | 13 | | { |
| | | 14 | | internal abstract class KeyExchangeECDH : KeyExchangeEC |
| | | 15 | | { |
| | | 16 | | /// <summary> |
| | | 17 | | /// Gets the parameter of the curve. |
| | | 18 | | /// </summary> |
| | | 19 | | /// <value> |
| | | 20 | | /// The parameter of the curve. |
| | | 21 | | /// </value> |
| | | 22 | | protected abstract X9ECParameters CurveParameter { get; } |
| | | 23 | | |
| | | 24 | | private ECDHCBasicAgreement _keyAgreement; |
| | | 25 | | private ECDomainParameters _domainParameters; |
| | | 26 | | |
| | | 27 | | /// <summary> |
| | | 28 | | /// Starts key exchange algorithm. |
| | | 29 | | /// </summary> |
| | | 30 | | /// <param name="session">The session.</param> |
| | | 31 | | /// <param name="message">Key exchange init message.</param> |
| | | 32 | | public override void Start(Session session, KeyExchangeInitMessage message) |
| | 9 | 33 | | { |
| | 9 | 34 | | base.Start(session, message); |
| | | 35 | | |
| | 9 | 36 | | Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); |
| | | 37 | | |
| | 9 | 38 | | Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; |
| | | 39 | | |
| | 9 | 40 | | _domainParameters = new ECDomainParameters(CurveParameter.Curve, |
| | 9 | 41 | | CurveParameter.G, |
| | 9 | 42 | | CurveParameter.N, |
| | 9 | 43 | | CurveParameter.H, |
| | 9 | 44 | | CurveParameter.GetSeed()); |
| | | 45 | | |
| | 9 | 46 | | var g = new ECKeyPairGenerator(); |
| | 9 | 47 | | g.Init(new ECKeyGenerationParameters(_domainParameters, new SecureRandom())); |
| | | 48 | | |
| | 9 | 49 | | var aKeyPair = g.GenerateKeyPair(); |
| | 9 | 50 | | _keyAgreement = new ECDHCBasicAgreement(); |
| | 9 | 51 | | _keyAgreement.Init(aKeyPair.Private); |
| | 9 | 52 | | _clientExchangeValue = ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded(); |
| | | 53 | | |
| | 9 | 54 | | SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); |
| | 9 | 55 | | } |
| | | 56 | | |
| | | 57 | | /// <summary> |
| | | 58 | | /// Finishes key exchange algorithm. |
| | | 59 | | /// </summary> |
| | | 60 | | public override void Finish() |
| | 9 | 61 | | { |
| | 9 | 62 | | base.Finish(); |
| | | 63 | | |
| | 9 | 64 | | Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; |
| | 9 | 65 | | } |
| | | 66 | | |
| | | 67 | | private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs<KeyExchangeEcdhReplyMes |
| | 9 | 68 | | { |
| | 9 | 69 | | var message = e.Message; |
| | | 70 | | |
| | | 71 | | // Unregister message once received |
| | 9 | 72 | | Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); |
| | | 73 | | |
| | 9 | 74 | | HandleServerEcdhReply(message.KS, message.QS, message.Signature); |
| | | 75 | | |
| | | 76 | | // When SSH_MSG_KEXDH_REPLY received key exchange is completed |
| | 9 | 77 | | Finish(); |
| | 9 | 78 | | } |
| | | 79 | | |
| | | 80 | | /// <summary> |
| | | 81 | | /// Handles the server DH reply message. |
| | | 82 | | /// </summary> |
| | | 83 | | /// <param name="hostKey">The host key.</param> |
| | | 84 | | /// <param name="serverExchangeValue">The server exchange value.</param> |
| | | 85 | | /// <param name="signature">The signature.</param> |
| | | 86 | | private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) |
| | 9 | 87 | | { |
| | 9 | 88 | | _serverExchangeValue = serverExchangeValue; |
| | 9 | 89 | | _hostKey = hostKey; |
| | 9 | 90 | | _signature = signature; |
| | | 91 | | |
| | 9 | 92 | | var cordSize = (serverExchangeValue.Length - 1) / 2; |
| | 9 | 93 | | var x = new byte[cordSize]; |
| | 9 | 94 | | Buffer.BlockCopy(serverExchangeValue, 1, x, 0, x.Length); // first byte is format. should be checked and pas |
| | 9 | 95 | | var y = new byte[cordSize]; |
| | 9 | 96 | | Buffer.BlockCopy(serverExchangeValue, cordSize + 1, y, 0, y.Length); |
| | | 97 | | |
| | 9 | 98 | | var c = (FpCurve)_domainParameters.Curve; |
| | 9 | 99 | | var q = c.CreatePoint(new Org.BouncyCastle.Math.BigInteger(1, x), new Org.BouncyCastle.Math.BigInteger(1, y) |
| | 9 | 100 | | var publicKey = new ECPublicKeyParameters("ECDH", q, _domainParameters); |
| | | 101 | | |
| | 9 | 102 | | var k1 = _keyAgreement.CalculateAgreement(publicKey); |
| | 9 | 103 | | SharedKey = k1.ToByteArray().ToBigInteger2().ToByteArray().Reverse(); |
| | 9 | 104 | | } |
| | | 105 | | } |
| | | 106 | | } |