KDFCounterBytesGenerator.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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 KdfCounterBytesGenerator
  10. : IMacDerivationFunction
  11. {
  12. private readonly IMac prf;
  13. private readonly int h;
  14. private byte[] fixedInputDataCtrPrefix;
  15. private byte[] fixedInputData_afterCtr;
  16. private int maxSizeExcl;
  17. // ios is i defined as an octet string (the binary representation)
  18. private byte[] ios;
  19. // operational
  20. private int generatedBytes;
  21. // k is used as buffer for all K(i) values
  22. private byte[] k;
  23. public KdfCounterBytesGenerator(IMac prf)
  24. {
  25. this.prf = prf;
  26. this.h = prf.GetMacSize();
  27. this.k = new byte[h];
  28. }
  29. public void Init(IDerivationParameters param)
  30. {
  31. if (!(param is KdfCounterParameters kdfParams))
  32. throw new ArgumentException("Wrong type of arguments given");
  33. // --- init mac based PRF ---
  34. this.prf.Init(new KeyParameter(kdfParams.Ki));
  35. // --- set arguments ---
  36. this.fixedInputDataCtrPrefix = kdfParams.FixedInputDataCounterPrefix;
  37. this.fixedInputData_afterCtr = kdfParams.FixedInputDataCounterSuffix;
  38. int r = kdfParams.R;
  39. this.ios = new byte[r / 8];
  40. BigInteger maxSize = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h));
  41. this.maxSizeExcl = maxSize.BitLength > 31 ? int.MaxValue : maxSize.IntValueExact;
  42. // --- set operational state ---
  43. generatedBytes = 0;
  44. }
  45. public IMac Mac => prf;
  46. public IDigest Digest
  47. {
  48. get { return (prf as HMac)?.GetUnderlyingDigest(); }
  49. }
  50. public int GenerateBytes(byte[] output, int outOff, int length)
  51. {
  52. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  53. return GenerateBytes(output.AsSpan(outOff, length));
  54. #else
  55. if (generatedBytes >= maxSizeExcl - length)
  56. throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
  57. int toGenerate = length;
  58. int posInK = generatedBytes % h;
  59. if (posInK != 0)
  60. {
  61. // copy what is left in the currentT (1..hash
  62. int toCopy = System.Math.Min(h - posInK, toGenerate);
  63. Array.Copy(k, posInK, output, outOff, toCopy);
  64. generatedBytes += toCopy;
  65. toGenerate -= toCopy;
  66. outOff += toCopy;
  67. }
  68. while (toGenerate > 0)
  69. {
  70. GenerateNext();
  71. int toCopy = System.Math.Min(h, toGenerate);
  72. Array.Copy(k, 0, output, outOff, toCopy);
  73. generatedBytes += toCopy;
  74. toGenerate -= toCopy;
  75. outOff += toCopy;
  76. }
  77. return length;
  78. #endif
  79. }
  80. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  81. public int GenerateBytes(Span<byte> output)
  82. {
  83. int length = output.Length;
  84. if (generatedBytes >= maxSizeExcl - length)
  85. throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes");
  86. int posInK = generatedBytes % h;
  87. if (posInK != 0)
  88. {
  89. // copy what is left in the currentT (1..hash
  90. int toCopy = System.Math.Min(h - posInK, output.Length);
  91. k.AsSpan(posInK, toCopy).CopyTo(output);
  92. generatedBytes += toCopy;
  93. output = output[toCopy..];
  94. }
  95. while (!output.IsEmpty)
  96. {
  97. GenerateNext();
  98. int toCopy = System.Math.Min(h, output.Length);
  99. k.AsSpan(0, toCopy).CopyTo(output);
  100. generatedBytes += toCopy;
  101. output = output[toCopy..];
  102. }
  103. return length;
  104. }
  105. #endif
  106. private void GenerateNext()
  107. {
  108. int i = generatedBytes / h + 1;
  109. // encode i into counter buffer
  110. switch (ios.Length)
  111. {
  112. case 4:
  113. ios[0] = (byte)(i >> 24);
  114. // fall through
  115. goto case 3;
  116. case 3:
  117. ios[ios.Length - 3] = (byte)(i >> 16);
  118. // fall through
  119. goto case 2;
  120. case 2:
  121. ios[ios.Length - 2] = (byte)(i >> 8);
  122. // fall through
  123. goto case 1;
  124. case 1:
  125. ios[ios.Length - 1] = (byte)i;
  126. break;
  127. default:
  128. throw new InvalidOperationException("Unsupported size of counter i");
  129. }
  130. // special case for K(0): K(0) is empty, so no update
  131. prf.BlockUpdate(fixedInputDataCtrPrefix, 0, fixedInputDataCtrPrefix.Length);
  132. prf.BlockUpdate(ios, 0, ios.Length);
  133. prf.BlockUpdate(fixedInputData_afterCtr, 0, fixedInputData_afterCtr.Length);
  134. prf.DoFinal(k, 0);
  135. }
  136. }
  137. }
  138. #pragma warning restore
  139. #endif