BaseKdfBytesGenerator.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators
  8. {
  9. /**
  10. * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
  11. * <br/>
  12. * This implementation is based on ISO 18033/P1363a.
  13. */
  14. public abstract class BaseKdfBytesGenerator
  15. : IDerivationFunction
  16. {
  17. private int counterStart;
  18. private IDigest digest;
  19. private byte[] shared;
  20. private byte[] iv;
  21. /**
  22. * Construct a KDF Parameters generator.
  23. *
  24. * @param counterStart value of counter.
  25. * @param digest the digest to be used as the source of derived keys.
  26. */
  27. protected BaseKdfBytesGenerator(int counterStart, IDigest digest)
  28. {
  29. this.counterStart = counterStart;
  30. this.digest = digest;
  31. }
  32. public void Init(IDerivationParameters parameters)
  33. {
  34. if (parameters is KdfParameters kdfParameters)
  35. {
  36. shared = kdfParameters.GetSharedSecret();
  37. iv = kdfParameters.GetIV();
  38. }
  39. else if (parameters is Iso18033KdfParameters iso18033KdfParameters)
  40. {
  41. shared = iso18033KdfParameters.GetSeed();
  42. iv = null;
  43. }
  44. else
  45. {
  46. throw new ArgumentException("KDF parameters required for KDF Generator");
  47. }
  48. }
  49. /**
  50. * return the underlying digest.
  51. */
  52. public IDigest Digest => digest;
  53. /**
  54. * fill len bytes of the output buffer with bytes generated from
  55. * the derivation function.
  56. *
  57. * @throws ArgumentException if the size of the request will cause an overflow.
  58. * @throws DataLengthException if the out buffer is too small.
  59. */
  60. public int GenerateBytes(byte[] output, int outOff, int length)
  61. {
  62. Check.OutputLength(output, outOff, length, "output buffer too small");
  63. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  64. return GenerateBytes(output.AsSpan(outOff, length));
  65. #else
  66. long oBytes = length;
  67. int digestSize = digest.GetDigestSize();
  68. //
  69. // this is at odds with the standard implementation, the
  70. // maximum value should be hBits * (2^32 - 1) where hBits
  71. // is the digest output size in bits. We can't have an
  72. // array with a long index at the moment...
  73. //
  74. if (oBytes > ((2L << 32) - 1))
  75. throw new ArgumentException("Output length too large");
  76. int cThreshold = (int)((oBytes + digestSize - 1) / digestSize);
  77. byte[] dig = new byte[digestSize];
  78. byte[] C = new byte[4];
  79. Pack.UInt32_To_BE((uint)counterStart, C, 0);
  80. uint counterBase = (uint)(counterStart & ~0xFF);
  81. for (int i = 0; i < cThreshold; i++)
  82. {
  83. digest.BlockUpdate(shared, 0, shared.Length);
  84. digest.BlockUpdate(C, 0, 4);
  85. if (iv != null)
  86. {
  87. digest.BlockUpdate(iv, 0, iv.Length);
  88. }
  89. digest.DoFinal(dig, 0);
  90. if (length > digestSize)
  91. {
  92. Array.Copy(dig, 0, output, outOff, digestSize);
  93. outOff += digestSize;
  94. length -= digestSize;
  95. }
  96. else
  97. {
  98. Array.Copy(dig, 0, output, outOff, length);
  99. }
  100. if (++C[3] == 0)
  101. {
  102. counterBase += 0x100;
  103. Pack.UInt32_To_BE(counterBase, C, 0);
  104. }
  105. }
  106. digest.Reset();
  107. return (int)oBytes;
  108. #endif
  109. }
  110. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  111. public int GenerateBytes(Span<byte> output)
  112. {
  113. long oBytes = output.Length;
  114. int digestSize = digest.GetDigestSize();
  115. //
  116. // this is at odds with the standard implementation, the
  117. // maximum value should be hBits * (2^32 - 1) where hBits
  118. // is the digest output size in bits. We can't have an
  119. // array with a long index at the moment...
  120. //
  121. if (oBytes > ((2L << 32) - 1))
  122. throw new ArgumentException("Output length too large");
  123. int cThreshold = (int)((oBytes + digestSize - 1) / digestSize);
  124. Span<byte> dig = digestSize <= 128
  125. ? stackalloc byte[digestSize]
  126. : new byte[digestSize];
  127. Span<byte> C = stackalloc byte[4];
  128. Pack.UInt32_To_BE((uint)counterStart, C);
  129. uint counterBase = (uint)(counterStart & ~0xFF);
  130. for (int i = 0; i < cThreshold; i++)
  131. {
  132. digest.BlockUpdate(shared);
  133. digest.BlockUpdate(C);
  134. if (iv != null)
  135. {
  136. digest.BlockUpdate(iv);
  137. }
  138. digest.DoFinal(dig);
  139. int remaining = output.Length;
  140. if (remaining > digestSize)
  141. {
  142. dig.CopyTo(output);
  143. output = output[digestSize..];
  144. }
  145. else
  146. {
  147. dig[..remaining].CopyTo(output);
  148. }
  149. if (++C[3] == 0)
  150. {
  151. counterBase += 0x100;
  152. Pack.UInt32_To_BE(counterBase, C);
  153. }
  154. }
  155. digest.Reset();
  156. return (int)oBytes;
  157. }
  158. #endif
  159. }
  160. }
  161. #pragma warning restore
  162. #endif