KeyExchangeEllipticCurveDiffieHellman.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using System;
  2. using System.Linq;
  3. using Renci.SshNet.Messages.Transport;
  4. using Renci.SshNet.Messages;
  5. using Renci.SshNet.Common;
  6. using System.Globalization;
  7. namespace Renci.SshNet.Security
  8. {
  9. /// <summary>
  10. /// Represents base class for Diffie Hellman key exchange algorithm
  11. /// </summary>
  12. public class KeyExchangeEllipticCurveDiffieHellman : KeyExchange
  13. {
  14. /// <summary>
  15. /// Specifies client payload
  16. /// </summary>
  17. protected byte[] _clientPayload;
  18. /// <summary>
  19. /// Specifies server payload
  20. /// </summary>
  21. protected byte[] _serverPayload;
  22. /// <summary>
  23. /// Specifies client exchange number.
  24. /// </summary>
  25. protected BigInteger _clientExchangeValue;
  26. /// <summary>
  27. /// Specifies server exchange number.
  28. /// </summary>
  29. protected BigInteger _serverExchangeValue;
  30. /// <summary>
  31. /// Specifies random generated number.
  32. /// </summary>
  33. protected BigInteger _randomValue;
  34. /// <summary>
  35. /// Specifies host key data.
  36. /// </summary>
  37. protected byte[] _hostKey;
  38. /// <summary>
  39. /// Specifies signature data.
  40. /// </summary>
  41. protected byte[] _signature;
  42. //// 256
  43. //p = FFFFFFFF 00000001 00000000 00000000 00000000 FFFFFFFF FFFFFFFF FFFFFFFF
  44. //a = FFFFFFFF 00000001 00000000 00000000 00000000 FFFFFFFF FFFFFFFF FFFFFFFC
  45. //b = 5AC635D8 AA3A93E7 B3EBBD55 769886BC 651D06B0 CC53B0F6 3BCE3C3E 27D2604B
  46. //S = C49D3608 86E70493 6A6678E1 139D26B7 819F7E90
  47. //The base point G in compressed form is:
  48. //G = 03 6B17D1F2 E12C4247 F8BCE6E5 63A440F2 77037D81 2DEB33A0 F4A13945 D898C296
  49. //and in uncompressed form is:
  50. //G = 04 6B17D1F2 E12C4247 F8BCE6E5 63A440F2 77037D81 2DEB33A0 F4A13945 D898C296 4FE342E2 FE1A7F9B 8EE7EB4A 7C0F9E16 2BCE3357 6B315ECE CBB64068 37BF51F5
  51. //n = FFFFFFFF 00000000 FFFFFFFF FFFFFFFF BCE6FAAD A7179E84 F3B9CAC2 FC632551
  52. //h = 01
  53. //// 384
  54. //p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFFFF 00000000 00000000 FFFFFFFF
  55. //a = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFFFF 00000000 00000000 FFFFFFFC
  56. //b = B3312FA7 E23EE7E4 988E056B E3F82D19 181D9C6E FE814112 0314088F 5013875A C656398D 8A2ED19D 2A85C8ED D3EC2AEF
  57. //S = A335926A A319A27A 1D00896A 6773A482 7ACDAC73
  58. //The base point G in compressed form is:
  59. //G = 03 AA87CA22 BE8B0537 8EB1C71E F320AD74 6E1D3B62 8BA79B98 59F741E0 82542A38 5502F25D BF55296C 3A545E38 72760AB7
  60. //and in uncompressed form is:
  61. //G = 04 AA87CA22 BE8B0537 8EB1C71E F320AD74 6E1D3B62 8BA79B98 59F741E0 82542A38 5502F25D BF55296C 3A545E38 72760AB7 3617DE4A 96262C6F 5D9E98BF 9292DC29 F8F41DBD 289A147C E9DA3113 B5F0B8C0 0A60B1CE 1D7E819D 7A431D7C 90EA0E5F
  62. //n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF C7634D81 F4372DDF 581A0DB2 48B0A77A ECEC196A CCC52973
  63. //h = 01
  64. public override string Name
  65. {
  66. get { return "ecdh-sha2-nistp256"; }
  67. }
  68. /// <summary>
  69. /// Starts key exchange algorithm
  70. /// </summary>
  71. /// <param name="session">The session.</param>
  72. /// <param name="message">Key exchange init message.</param>
  73. public override void Start(Session session, KeyExchangeInitMessage message)
  74. {
  75. base.Start(session, message);
  76. this._serverPayload = message.GetBytes().ToArray();
  77. this._clientPayload = this.Session.ClientInitMessage.GetBytes().ToArray();
  78. this.Session.RegisterMessage("SSH_MSG_KEXECDH_REPLY");
  79. this.Session.MessageReceived += Session_MessageReceived;
  80. //3.2.1 Elliptic Curve Key Pair Generation Primitive
  81. //Elliptic curve key pairs should be generated as follows:
  82. //Input: Valid elliptic curve domain parameters T = (p, a, b, G, n, h) or (m, f(x), a, b,G, n, h).
  83. //Output: An elliptic curve key pair (d,Q) associated with T.
  84. //Actions: Generate an elliptic curve key pair as follows:
  85. //1. Randomly or pseudorandomly select an integer d in the interval [1, n − 1].
  86. //2. Compute Q = dG.
  87. //3. Output (d,Q).
  88. BigInteger p;
  89. BigInteger.TryParse("00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out p);
  90. BigInteger n;
  91. BigInteger.TryParse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out n);
  92. BigInteger G;
  93. BigInteger.TryParse("00036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out G);
  94. BigInteger d;
  95. do
  96. {
  97. d = BigInteger.Random(n.BitLength);
  98. } while (d < 1 || d > n);
  99. var Q = d * G;
  100. this.SendMessage(new KeyExchangeEcdhInitMessage(d, Q));
  101. }
  102. private void Session_MessageReceived(object sender, MessageEventArgs<Message> e)
  103. {
  104. var message = e.Message as KeyExchangeEcdhReplyMessage;
  105. if (message != null)
  106. {
  107. // Unregister message once received
  108. this.Session.UnRegisterMessage("SSH_MSG_KEXECDH_REPLY");
  109. this.HandleServerEcdhReply();
  110. // When SSH_MSG_KEXDH_REPLY received key exchange is completed
  111. this.Finish();
  112. }
  113. }
  114. /// <summary>
  115. /// Validates the exchange hash.
  116. /// </summary>
  117. /// <returns>
  118. /// true if exchange hash is valid; otherwise false.
  119. /// </returns>
  120. protected override bool ValidateExchangeHash()
  121. {
  122. //var exchangeHash = this.CalculateHash();
  123. //var length = (uint)(this._hostKey[0] << 24 | this._hostKey[1] << 16 | this._hostKey[2] << 8 | this._hostKey[3]);
  124. //var algorithmName = Encoding.UTF8.GetString(this._hostKey, 4, (int)length);
  125. //var key = this.Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](this._hostKey);
  126. //this.Session.ConnectionInfo.CurrentHostKeyAlgorithm = algorithmName;
  127. //if (this.CanTrustHostKey(key))
  128. //{
  129. // return key.VerifySignature(exchangeHash, this._signature);
  130. //}
  131. //else
  132. //{
  133. // return false;
  134. //}
  135. return false;
  136. }
  137. /// <summary>
  138. /// Populates the client exchange value.
  139. /// </summary>
  140. //protected void PopulateClientExchangeValue()
  141. //{
  142. // if (this._group.IsZero)
  143. // throw new ArgumentNullException("_group");
  144. // if (this._prime.IsZero)
  145. // throw new ArgumentNullException("_prime");
  146. // var bitLength = this._prime.BitLength;
  147. // do
  148. // {
  149. // this._randomValue = BigInteger.Random(bitLength);
  150. // this._clientExchangeValue = BigInteger.ModPow(this._group, this._randomValue, this._prime);
  151. // } while (this._clientExchangeValue < 1 || this._clientExchangeValue > ((this._prime - 1)));
  152. //}
  153. protected virtual void HandleServerEcdhReply()
  154. {
  155. //this._serverExchangeValue = serverExchangeValue;
  156. //this._hostKey = hostKey;
  157. //this.SharedKey = BigInteger.ModPow(serverExchangeValue, this._randomValue, this._prime);
  158. //this._signature = signature;
  159. }
  160. protected override byte[] CalculateHash()
  161. {
  162. var hashData = new _ExchangeHashData
  163. {
  164. ClientVersion = this.Session.ClientVersion,
  165. ServerVersion = this.Session.ServerVersion,
  166. ClientPayload = this._clientPayload,
  167. ServerPayload = this._serverPayload,
  168. HostKey = this._hostKey,
  169. SharedKey = this.SharedKey,
  170. }.GetBytes();
  171. //string V_C, client's identification string (CR and LF excluded)
  172. //string V_S, server's identification string (CR and LF excluded)
  173. //string I_C, payload of the client's SSH_MSG_KEXINIT
  174. //string I_S, payload of the server's SSH_MSG_KEXINIT
  175. //string K_S, server's public host key
  176. //string Q_C, client's ephemeral public key octet string
  177. //string Q_S, server's ephemeral public key octet string
  178. //mpint K, shared secret
  179. return this.Hash(hashData);
  180. }
  181. private class _ExchangeHashData : SshData
  182. {
  183. public string ServerVersion { get; set; }
  184. public string ClientVersion { get; set; }
  185. public byte[] ClientPayload { get; set; }
  186. public byte[] ServerPayload { get; set; }
  187. public byte[] HostKey { get; set; }
  188. public UInt32 MinimumGroupSize { get; set; }
  189. public UInt32 PreferredGroupSize { get; set; }
  190. public UInt32 MaximumGroupSize { get; set; }
  191. public BigInteger Prime { get; set; }
  192. public BigInteger SubGroup { get; set; }
  193. public BigInteger ClientExchangeValue { get; set; }
  194. public BigInteger ServerExchangeValue { get; set; }
  195. public BigInteger SharedKey { get; set; }
  196. protected override void LoadData()
  197. {
  198. throw new NotImplementedException();
  199. }
  200. protected override void SaveData()
  201. {
  202. this.Write(this.ClientVersion);
  203. this.Write(this.ServerVersion);
  204. this.WriteBinaryString(this.ClientPayload);
  205. this.WriteBinaryString(this.ServerPayload);
  206. this.WriteBinaryString(this.HostKey);
  207. this.Write(this.MinimumGroupSize);
  208. this.Write(this.PreferredGroupSize);
  209. this.Write(this.MaximumGroupSize);
  210. this.Write(this.Prime);
  211. this.Write(this.SubGroup);
  212. this.Write(this.ClientExchangeValue);
  213. this.Write(this.ServerExchangeValue);
  214. this.Write(this.SharedKey);
  215. }
  216. }
  217. }
  218. }