SRP6Utilities.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  7. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement.Srp
  8. {
  9. public class Srp6Utilities
  10. {
  11. public static BigInteger CalculateK(IDigest digest, BigInteger N, BigInteger g)
  12. {
  13. return HashPaddedPair(digest, N, N, g);
  14. }
  15. public static BigInteger CalculateU(IDigest digest, BigInteger N, BigInteger A, BigInteger B)
  16. {
  17. return HashPaddedPair(digest, N, A, B);
  18. }
  19. public static BigInteger CalculateX(IDigest digest, BigInteger N, byte[] salt, byte[] identity, byte[] password)
  20. {
  21. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  22. return CalculateX(digest, N, salt.AsSpan(), identity.AsSpan(), password.AsSpan());
  23. #else
  24. byte[] output = new byte[digest.GetDigestSize()];
  25. digest.BlockUpdate(identity, 0, identity.Length);
  26. digest.Update((byte)':');
  27. digest.BlockUpdate(password, 0, password.Length);
  28. digest.DoFinal(output, 0);
  29. digest.BlockUpdate(salt, 0, salt.Length);
  30. digest.BlockUpdate(output, 0, output.Length);
  31. digest.DoFinal(output, 0);
  32. return new BigInteger(1, output);
  33. #endif
  34. }
  35. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  36. public static BigInteger CalculateX(IDigest digest, BigInteger N, ReadOnlySpan<byte> salt,
  37. ReadOnlySpan<byte> identity, ReadOnlySpan<byte> password)
  38. {
  39. int digestSize = digest.GetDigestSize();
  40. Span<byte> output = digestSize <= 128
  41. ? stackalloc byte[digestSize]
  42. : new byte[digestSize];
  43. digest.BlockUpdate(identity);
  44. digest.Update((byte)':');
  45. digest.BlockUpdate(password);
  46. digest.DoFinal(output);
  47. digest.BlockUpdate(salt);
  48. digest.BlockUpdate(output);
  49. digest.DoFinal(output);
  50. return new BigInteger(1, output);
  51. }
  52. #endif
  53. public static BigInteger GeneratePrivateValue(IDigest digest, BigInteger N, BigInteger g, SecureRandom random)
  54. {
  55. int minBits = System.Math.Min(256, N.BitLength / 2);
  56. BigInteger min = BigInteger.One.ShiftLeft(minBits - 1);
  57. BigInteger max = N.Subtract(BigInteger.One);
  58. return BigIntegers.CreateRandomInRange(min, max, random);
  59. }
  60. public static BigInteger ValidatePublicValue(BigInteger N, BigInteger val)
  61. {
  62. val = val.Mod(N);
  63. // Check that val % N != 0
  64. if (val.Equals(BigInteger.Zero))
  65. throw new CryptoException("Invalid public value: 0");
  66. return val;
  67. }
  68. /**
  69. * Computes the client evidence message (M1) according to the standard routine:
  70. * M1 = H( A | B | S )
  71. * @param digest The Digest used as the hashing function H
  72. * @param N Modulus used to get the pad length
  73. * @param A The public client value
  74. * @param B The public server value
  75. * @param S The secret calculated by both sides
  76. * @return M1 The calculated client evidence message
  77. */
  78. public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S)
  79. {
  80. BigInteger M1 = HashPaddedTriplet(digest, N, A, B, S);
  81. return M1;
  82. }
  83. /**
  84. * Computes the server evidence message (M2) according to the standard routine:
  85. * M2 = H( A | M1 | S )
  86. * @param digest The Digest used as the hashing function H
  87. * @param N Modulus used to get the pad length
  88. * @param A The public client value
  89. * @param M1 The client evidence message
  90. * @param S The secret calculated by both sides
  91. * @return M2 The calculated server evidence message
  92. */
  93. public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S)
  94. {
  95. BigInteger M2 = HashPaddedTriplet(digest, N, A, M1, S);
  96. return M2;
  97. }
  98. /**
  99. * Computes the final Key according to the standard routine: Key = H(S)
  100. * @param digest The Digest used as the hashing function H
  101. * @param N Modulus used to get the pad length
  102. * @param S The secret calculated by both sides
  103. * @return
  104. */
  105. public static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S)
  106. {
  107. int paddedLength = (N.BitLength + 7) / 8;
  108. int digestSize = digest.GetDigestSize();
  109. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  110. Span<byte> bytes = paddedLength <= 512
  111. ? stackalloc byte[paddedLength]
  112. : new byte[paddedLength];
  113. BigIntegers.AsUnsignedByteArray(S, bytes);
  114. digest.BlockUpdate(bytes);
  115. Span<byte> output = digestSize <= 128
  116. ? stackalloc byte[digestSize]
  117. : new byte[digestSize];
  118. digest.DoFinal(output);
  119. #else
  120. byte[] bytes = new byte[paddedLength];
  121. BigIntegers.AsUnsignedByteArray(S, bytes, 0, bytes.Length);
  122. digest.BlockUpdate(bytes, 0, bytes.Length);
  123. byte[] output = new byte[digestSize];
  124. digest.DoFinal(output, 0);
  125. #endif
  126. return new BigInteger(1, output);
  127. }
  128. private static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3)
  129. {
  130. int paddedLength = (N.BitLength + 7) / 8;
  131. int digestSize = digest.GetDigestSize();
  132. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  133. Span<byte> bytes = paddedLength <= 512
  134. ? stackalloc byte[paddedLength]
  135. : new byte[paddedLength];
  136. BigIntegers.AsUnsignedByteArray(n1, bytes);
  137. digest.BlockUpdate(bytes);
  138. BigIntegers.AsUnsignedByteArray(n2, bytes);
  139. digest.BlockUpdate(bytes);
  140. BigIntegers.AsUnsignedByteArray(n3, bytes);
  141. digest.BlockUpdate(bytes);
  142. Span<byte> output = digestSize <= 128
  143. ? stackalloc byte[digestSize]
  144. : new byte[digestSize];
  145. digest.DoFinal(output);
  146. #else
  147. byte[] bytes = new byte[paddedLength];
  148. BigIntegers.AsUnsignedByteArray(n1, bytes, 0, bytes.Length);
  149. digest.BlockUpdate(bytes, 0, bytes.Length);
  150. BigIntegers.AsUnsignedByteArray(n2, bytes, 0, bytes.Length);
  151. digest.BlockUpdate(bytes, 0, bytes.Length);
  152. BigIntegers.AsUnsignedByteArray(n3, bytes, 0, bytes.Length);
  153. digest.BlockUpdate(bytes, 0, bytes.Length);
  154. byte[] output = new byte[digestSize];
  155. digest.DoFinal(output, 0);
  156. #endif
  157. return new BigInteger(1, output);
  158. }
  159. private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
  160. {
  161. int paddedLength = (N.BitLength + 7) / 8;
  162. int digestSize = digest.GetDigestSize();
  163. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  164. Span<byte> bytes = paddedLength <= 512
  165. ? stackalloc byte[paddedLength]
  166. : new byte[paddedLength];
  167. BigIntegers.AsUnsignedByteArray(n1, bytes);
  168. digest.BlockUpdate(bytes);
  169. BigIntegers.AsUnsignedByteArray(n2, bytes);
  170. digest.BlockUpdate(bytes);
  171. Span<byte> output = digestSize <= 128
  172. ? stackalloc byte[digestSize]
  173. : new byte[digestSize];
  174. digest.DoFinal(output);
  175. #else
  176. byte[] bytes = new byte[paddedLength];
  177. BigIntegers.AsUnsignedByteArray(n1, bytes, 0, bytes.Length);
  178. digest.BlockUpdate(bytes, 0, bytes.Length);
  179. BigIntegers.AsUnsignedByteArray(n2, bytes, 0, bytes.Length);
  180. digest.BlockUpdate(bytes, 0, bytes.Length);
  181. byte[] output = new byte[digestSize];
  182. digest.DoFinal(output, 0);
  183. #endif
  184. return new BigInteger(1, output);
  185. }
  186. }
  187. }
  188. #pragma warning restore
  189. #endif