ConcatenationKdfGenerator.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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.Parameters;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement.Kdf
  7. {
  8. /// <summary>Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1</summary>
  9. public sealed class ConcatenationKdfGenerator
  10. : IDerivationFunction
  11. {
  12. private readonly IDigest m_digest;
  13. private readonly int m_hLen;
  14. private byte[] m_buffer;
  15. /// <param name="digest">the digest to be used as the source of generated bytes</param>
  16. public ConcatenationKdfGenerator(IDigest digest)
  17. {
  18. m_digest = digest;
  19. m_hLen = digest.GetDigestSize();
  20. }
  21. public void Init(IDerivationParameters param)
  22. {
  23. if (!(param is KdfParameters kdfParameters))
  24. throw new ArgumentException("KDF parameters required for ConcatenationKdfGenerator");
  25. byte[] sharedSecret = kdfParameters.GetSharedSecret();
  26. byte[] otherInfo = kdfParameters.GetIV();
  27. m_buffer = new byte[4 + sharedSecret.Length + otherInfo.Length + m_hLen];
  28. sharedSecret.CopyTo(m_buffer, 4);
  29. otherInfo.CopyTo(m_buffer, 4 + sharedSecret.Length);
  30. }
  31. /// <summary>the underlying digest.</summary>
  32. public IDigest Digest => m_digest;
  33. /// <summary>Fill <c>len</c> bytes of the output buffer with bytes generated from the derivation function.
  34. /// </summary>
  35. public int GenerateBytes(byte[] output, int outOff, int length)
  36. {
  37. Check.OutputLength(output, outOff, length, "output buffer too small");
  38. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  39. return GenerateBytes(output.AsSpan(outOff, length));
  40. #else
  41. int hashPos = m_buffer.Length - m_hLen;
  42. uint counter = 1;
  43. m_digest.Reset();
  44. int end = outOff + length;
  45. int limit = end - m_hLen;
  46. while (outOff <= limit)
  47. {
  48. Pack.UInt32_To_BE(counter++, m_buffer, 0);
  49. m_digest.BlockUpdate(m_buffer, 0, hashPos);
  50. m_digest.DoFinal(output, outOff);
  51. outOff += m_hLen;
  52. }
  53. if (outOff < end)
  54. {
  55. Pack.UInt32_To_BE(counter, m_buffer, 0);
  56. m_digest.BlockUpdate(m_buffer, 0, hashPos);
  57. m_digest.DoFinal(m_buffer, hashPos);
  58. Array.Copy(m_buffer, hashPos, output, outOff, end - outOff);
  59. }
  60. return length;
  61. #endif
  62. }
  63. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  64. public int GenerateBytes(Span<byte> output)
  65. {
  66. int hashPos = m_buffer.Length - m_hLen;
  67. uint counter = 1;
  68. m_digest.Reset();
  69. int pos = 0, length = output.Length, limit = length - m_hLen;
  70. while (pos <= limit)
  71. {
  72. Pack.UInt32_To_BE(counter++, m_buffer.AsSpan());
  73. m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos));
  74. m_digest.DoFinal(output[pos..]);
  75. pos += m_hLen;
  76. }
  77. if (pos < length)
  78. {
  79. Pack.UInt32_To_BE(counter, m_buffer.AsSpan());
  80. m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos));
  81. m_digest.DoFinal(m_buffer.AsSpan(hashPos));
  82. m_buffer.AsSpan(hashPos, length - pos).CopyTo(output[pos..]);
  83. }
  84. return length;
  85. }
  86. #endif
  87. }
  88. }
  89. #pragma warning restore
  90. #endif