DHKekGenerator.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.IO;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement.Kdf
  9. {
  10. /**
  11. * RFC 2631 Diffie-hellman KEK derivation function.
  12. */
  13. public sealed class DHKekGenerator
  14. : IDerivationFunction
  15. {
  16. private readonly IDigest m_digest;
  17. private DerObjectIdentifier algorithm;
  18. private int keySize;
  19. private byte[] z;
  20. private byte[] partyAInfo;
  21. public DHKekGenerator(IDigest digest)
  22. {
  23. m_digest = digest;
  24. }
  25. public void Init(IDerivationParameters param)
  26. {
  27. DHKdfParameters parameters = (DHKdfParameters)param;
  28. this.algorithm = parameters.Algorithm;
  29. this.keySize = parameters.KeySize;
  30. this.z = parameters.GetZ(); // TODO Clone?
  31. this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
  32. }
  33. public IDigest Digest => m_digest;
  34. public int GenerateBytes(byte[] outBytes, int outOff, int length)
  35. {
  36. Check.OutputLength(outBytes, outOff, length, "output buffer too small");
  37. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  38. return GenerateBytes(outBytes.AsSpan(outOff, length));
  39. #else
  40. long oBytes = length;
  41. int digestSize = m_digest.GetDigestSize();
  42. //
  43. // this is at odds with the standard implementation, the
  44. // maximum value should be hBits * (2^32 - 1) where hBits
  45. // is the digest output size in bits. We can't have an
  46. // array with a long index at the moment...
  47. //
  48. if (oBytes > ((2L << 32) - 1))
  49. throw new ArgumentException("Output length too large");
  50. int cThreshold = (int)((oBytes + digestSize - 1) / digestSize);
  51. byte[] dig = new byte[digestSize];
  52. uint counter = 1;
  53. for (int i = 0; i < cThreshold; i++)
  54. {
  55. // KeySpecificInfo
  56. DerSequence keyInfo = new DerSequence(algorithm, new DerOctetString(Pack.UInt32_To_BE(counter)));
  57. // OtherInfo
  58. Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
  59. if (partyAInfo != null)
  60. {
  61. v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
  62. }
  63. v1.Add(new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
  64. byte[] other = new DerSequence(v1).GetDerEncoded();
  65. m_digest.BlockUpdate(z, 0, z.Length);
  66. m_digest.BlockUpdate(other, 0, other.Length);
  67. m_digest.DoFinal(dig, 0);
  68. if (length > digestSize)
  69. {
  70. Array.Copy(dig, 0, outBytes, outOff, digestSize);
  71. outOff += digestSize;
  72. length -= digestSize;
  73. }
  74. else
  75. {
  76. Array.Copy(dig, 0, outBytes, outOff, length);
  77. }
  78. counter++;
  79. }
  80. m_digest.Reset();
  81. return (int)oBytes;
  82. #endif
  83. }
  84. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  85. public int GenerateBytes(Span<byte> output)
  86. {
  87. long oBytes = output.Length;
  88. int digestSize = m_digest.GetDigestSize();
  89. //
  90. // this is at odds with the standard implementation, the
  91. // maximum value should be hBits * (2^32 - 1) where hBits
  92. // is the digest output size in bits. We can't have an
  93. // array with a long index at the moment...
  94. //
  95. if (oBytes > ((2L << 32) - 1))
  96. throw new ArgumentException("Output length too large");
  97. int cThreshold = (int)((oBytes + digestSize - 1) / digestSize);
  98. Span<byte> dig = digestSize <= 128
  99. ? stackalloc byte[digestSize]
  100. : new byte[digestSize];
  101. uint counter = 1;
  102. for (int i = 0; i < cThreshold; i++)
  103. {
  104. // KeySpecificInfo
  105. DerSequence keyInfo = new DerSequence(algorithm, new DerOctetString(Pack.UInt32_To_BE(counter)));
  106. // OtherInfo
  107. Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
  108. if (partyAInfo != null)
  109. {
  110. v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
  111. }
  112. v1.Add(new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
  113. byte[] other = new DerSequence(v1).GetDerEncoded();
  114. m_digest.BlockUpdate(z);
  115. m_digest.BlockUpdate(other);
  116. m_digest.DoFinal(dig);
  117. int remaining = output.Length;
  118. if (remaining > digestSize)
  119. {
  120. dig.CopyTo(output);
  121. output = output[digestSize..];
  122. }
  123. else
  124. {
  125. dig[..remaining].CopyTo(output);
  126. }
  127. counter++;
  128. }
  129. m_digest.Reset();
  130. return (int)oBytes;
  131. }
  132. #endif
  133. }
  134. }
  135. #pragma warning restore
  136. #endif