2
0

KeyExchangeDiffieHellman.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using System;
  2. using System.Numerics;
  3. using Renci.SshNet.Abstractions;
  4. using Renci.SshNet.Common;
  5. using Renci.SshNet.Messages.Transport;
  6. namespace Renci.SshNet.Security
  7. {
  8. /// <summary>
  9. /// Represents base class for Diffie Hellman key exchange algorithm.
  10. /// </summary>
  11. internal abstract class KeyExchangeDiffieHellman : KeyExchange
  12. {
  13. #pragma warning disable SA1401 // Fields should be private
  14. /// <summary>
  15. /// Specifies key exchange group number.
  16. /// </summary>
  17. protected BigInteger _group;
  18. /// <summary>
  19. /// Specifies key exchange prime number.
  20. /// </summary>
  21. protected BigInteger _prime;
  22. /// <summary>
  23. /// Specifies client payload.
  24. /// </summary>
  25. protected byte[] _clientPayload;
  26. /// <summary>
  27. /// Specifies server payload.
  28. /// </summary>
  29. protected byte[] _serverPayload;
  30. /// <summary>
  31. /// Specifies client exchange number.
  32. /// </summary>
  33. protected byte[] _clientExchangeValue;
  34. /// <summary>
  35. /// Specifies server exchange number.
  36. /// </summary>
  37. protected byte[] _serverExchangeValue;
  38. /// <summary>
  39. /// Specifies random generated number.
  40. /// </summary>
  41. protected BigInteger _privateExponent;
  42. /// <summary>
  43. /// Specifies host key data.
  44. /// </summary>
  45. protected byte[] _hostKey;
  46. /// <summary>
  47. /// Specifies signature data.
  48. /// </summary>
  49. protected byte[] _signature;
  50. #pragma warning restore SA1401 // Fields should be private
  51. /// <summary>
  52. /// Gets the size, in bits, of the computed hash code.
  53. /// </summary>
  54. /// <value>
  55. /// The size, in bits, of the computed hash code.
  56. /// </value>
  57. protected abstract int HashSize { get; }
  58. /// <summary>
  59. /// Validates the exchange hash.
  60. /// </summary>
  61. /// <returns>
  62. /// true if exchange hash is valid; otherwise false.
  63. /// </returns>
  64. protected override bool ValidateExchangeHash()
  65. {
  66. return ValidateExchangeHash(_hostKey, _signature);
  67. }
  68. /// <inheritdoc/>
  69. public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage)
  70. {
  71. base.Start(session, message, sendClientInitMessage);
  72. _serverPayload = message.GetBytes();
  73. _clientPayload = Session.ClientInitMessage.GetBytes();
  74. }
  75. /// <summary>
  76. /// Populates the client exchange value.
  77. /// </summary>
  78. protected void PopulateClientExchangeValue()
  79. {
  80. if (_group.IsZero)
  81. {
  82. throw new ArgumentNullException("_group");
  83. }
  84. if (_prime.IsZero)
  85. {
  86. throw new ArgumentNullException("_prime");
  87. }
  88. // generate private exponent that is twice the hash size (RFC 4419) with a minimum
  89. // of 1024 bits (whatever is less)
  90. var privateExponentSize = Math.Max(HashSize * 2, 1024);
  91. BigInteger clientExchangeValue;
  92. do
  93. {
  94. // Create private component
  95. _privateExponent = RandomBigInt(privateExponentSize);
  96. // Generate public component
  97. clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime);
  98. }
  99. while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1));
  100. _clientExchangeValue = clientExchangeValue.ToByteArray(isBigEndian: true);
  101. }
  102. /// <summary>
  103. /// Generates a new, random <see cref="BigInteger"/> of the specified length.
  104. /// </summary>
  105. /// <param name="bitLength">The number of bits for the new number.</param>
  106. /// <returns>A random number of the specified length.</returns>
  107. private static BigInteger RandomBigInt(int bitLength)
  108. {
  109. var bytesArray = CryptoAbstraction.GenerateRandom((bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0));
  110. bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value
  111. return new BigInteger(bytesArray);
  112. }
  113. /// <summary>
  114. /// Handles the server DH reply message.
  115. /// </summary>
  116. /// <param name="hostKey">The host key.</param>
  117. /// <param name="serverExchangeValue">The server exchange value.</param>
  118. /// <param name="signature">The signature.</param>
  119. protected virtual void HandleServerDhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature)
  120. {
  121. _serverExchangeValue = serverExchangeValue;
  122. _hostKey = hostKey;
  123. SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray(isBigEndian: true);
  124. _signature = signature;
  125. }
  126. }
  127. }