KDFFeedbackBytesGenerator.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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.Macs;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  7. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators
  8. {
  9. public sealed class KdfFeedbackBytesGenerator
  10. : IMacDerivationFunction
  11. {
  12. // please refer to the standard for the meaning of the variable names
  13. // all field lengths are in bytes, not in bits as specified by the standard
  14. // fields set by the constructor
  15. private readonly IMac prf;
  16. private readonly int h;
  17. // fields set by init
  18. private byte[] fixedInputData;
  19. private int maxSizeExcl;
  20. // ios is i defined as an octet string (the binary representation)
  21. private byte[] ios;
  22. private byte[] iv;
  23. private bool useCounter;
  24. // operational
  25. private int generatedBytes;
  26. // k is used as buffer for all K(i) values
  27. private byte[] k;
  28. public KdfFeedbackBytesGenerator(IMac prf)
  29. {
  30. this.prf = prf;
  31. this.h = prf.GetMacSize();
  32. this.k = new byte[h];
  33. }
  34. public void Init(IDerivationParameters parameters)
  35. {
  36. if (!(parameters is KdfFeedbackParameters feedbackParams))
  37. throw new ArgumentException("Wrong type of arguments given");
  38. // --- init mac based PRF ---
  39. this.prf.Init(new KeyParameter(feedbackParams.Ki));
  40. // --- set arguments ---
  41. this.fixedInputData = feedbackParams.FixedInputData;
  42. int r = feedbackParams.R;
  43. this.ios = new byte[r / 8];
  44. if (feedbackParams.UseCounter)
  45. {
  46. // this is more conservative than the spec
  47. BigInteger maxSize = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h));
  48. this.maxSizeExcl = maxSize.BitLength > 31 ? int.MaxValue : maxSize.IntValueExact;
  49. }
  50. else
  51. {
  52. this.maxSizeExcl = int.MaxValue;
  53. }
  54. this.iv = feedbackParams.Iv;
  55. this.useCounter = feedbackParams.UseCounter;
  56. // --- set operational state ---
  57. generatedBytes = 0;
  58. }
  59. public IDigest Digest
  60. {
  61. get { return (prf as HMac)?.GetUnderlyingDigest(); }
  62. }
  63. public int GenerateBytes(byte[] output, int outOff, int length)
  64. {
  65. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  66. return GenerateBytes(output.AsSpan(outOff, length));
  67. #else
  68. if (generatedBytes >= maxSizeExcl - length)
  69. throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
  70. int toGenerate = length;
  71. int posInK = generatedBytes % h;
  72. if (posInK != 0)
  73. {
  74. // copy what is left in the currentT (1..hash
  75. int toCopy = System.Math.Min(h - posInK, toGenerate);
  76. Array.Copy(k, posInK, output, outOff, toCopy);
  77. generatedBytes += toCopy;
  78. toGenerate -= toCopy;
  79. outOff += toCopy;
  80. }
  81. while (toGenerate > 0)
  82. {
  83. GenerateNext();
  84. int toCopy = System.Math.Min(h, toGenerate);
  85. Array.Copy(k, 0, output, outOff, toCopy);
  86. generatedBytes += toCopy;
  87. toGenerate -= toCopy;
  88. outOff += toCopy;
  89. }
  90. return length;
  91. #endif
  92. }
  93. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  94. public int GenerateBytes(Span<byte> output)
  95. {
  96. int length = output.Length;
  97. if (generatedBytes >= maxSizeExcl - length)
  98. throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
  99. int posInK = generatedBytes % h;
  100. if (posInK != 0)
  101. {
  102. // copy what is left in the currentT (1..hash
  103. int toCopy = System.Math.Min(h - posInK, output.Length);
  104. k.AsSpan(posInK, toCopy).CopyTo(output);
  105. generatedBytes += toCopy;
  106. output = output[toCopy..];
  107. }
  108. while (!output.IsEmpty)
  109. {
  110. GenerateNext();
  111. int toCopy = System.Math.Min(h, output.Length);
  112. k.AsSpan(0, toCopy).CopyTo(output);
  113. generatedBytes += toCopy;
  114. output = output[toCopy..];
  115. }
  116. return length;
  117. }
  118. #endif
  119. private void GenerateNext()
  120. {
  121. // TODO enable IV
  122. if (generatedBytes == 0)
  123. {
  124. prf.BlockUpdate(iv, 0, iv.Length);
  125. }
  126. else
  127. {
  128. prf.BlockUpdate(k, 0, k.Length);
  129. }
  130. if (useCounter)
  131. {
  132. int i = generatedBytes / h + 1;
  133. // encode i into counter buffer
  134. switch (ios.Length)
  135. {
  136. case 4:
  137. ios[0] = (byte)(i >> 24);
  138. // fall through
  139. goto case 3;
  140. case 3:
  141. ios[ios.Length - 3] = (byte)(i >> 16);
  142. // fall through
  143. goto case 2;
  144. case 2:
  145. ios[ios.Length - 2] = (byte)(i >> 8);
  146. // fall through
  147. goto case 1;
  148. case 1:
  149. ios[ios.Length - 1] = (byte)i;
  150. break;
  151. default:
  152. throw new InvalidOperationException("Unsupported size of counter i");
  153. }
  154. prf.BlockUpdate(ios, 0, ios.Length);
  155. }
  156. prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length);
  157. prf.DoFinal(k, 0);
  158. }
  159. public IMac Mac => prf;
  160. }
  161. }
  162. #pragma warning restore
  163. #endif