HKDFBytesGenerator.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  7. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators
  8. {
  9. /**
  10. * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented
  11. * according to IETF RFC 5869, May 2010 as specified by H. Krawczyk, IBM
  12. * Research & P. Eronen, Nokia. It uses a HMac internally to compute de OKM
  13. * (output keying material) and is likely to have better security properties
  14. * than KDF's based on just a hash function.
  15. */
  16. public class HkdfBytesGenerator
  17. : IDerivationFunction
  18. {
  19. private HMac hMacHash;
  20. private int hashLen;
  21. private byte[] info;
  22. private byte[] currentT;
  23. private int generatedBytes;
  24. /**
  25. * Creates a HKDFBytesGenerator based on the given hash function.
  26. *
  27. * @param hash the digest to be used as the source of generatedBytes bytes
  28. */
  29. public HkdfBytesGenerator(IDigest hash)
  30. {
  31. this.hMacHash = new HMac(hash);
  32. this.hashLen = hash.GetDigestSize();
  33. }
  34. public virtual void Init(IDerivationParameters parameters)
  35. {
  36. if (!(parameters is HkdfParameters))
  37. throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters");
  38. HkdfParameters hkdfParameters = (HkdfParameters)parameters;
  39. if (hkdfParameters.SkipExtract)
  40. {
  41. // use IKM directly as PRK
  42. hMacHash.Init(new KeyParameter(hkdfParameters.GetIkm()));
  43. }
  44. else
  45. {
  46. hMacHash.Init(Extract(hkdfParameters.GetSalt(), hkdfParameters.GetIkm()));
  47. }
  48. info = hkdfParameters.GetInfo();
  49. generatedBytes = 0;
  50. currentT = new byte[hashLen];
  51. }
  52. /**
  53. * Performs the extract part of the key derivation function.
  54. *
  55. * @param salt the salt to use
  56. * @param ikm the input keying material
  57. * @return the PRK as KeyParameter
  58. */
  59. private KeyParameter Extract(byte[] salt, byte[] ikm)
  60. {
  61. if (salt == null)
  62. {
  63. // TODO check if hashLen is indeed same as HMAC size
  64. hMacHash.Init(new KeyParameter(new byte[hashLen]));
  65. }
  66. else
  67. {
  68. hMacHash.Init(new KeyParameter(salt));
  69. }
  70. hMacHash.BlockUpdate(ikm, 0, ikm.Length);
  71. byte[] prk = new byte[hashLen];
  72. hMacHash.DoFinal(prk, 0);
  73. return new KeyParameter(prk);
  74. }
  75. /**
  76. * Performs the expand part of the key derivation function, using currentT
  77. * as input and output buffer.
  78. *
  79. * @throws DataLengthException if the total number of bytes generated is larger than the one
  80. * specified by RFC 5869 (255 * HashLen)
  81. */
  82. private void ExpandNext()
  83. {
  84. int n = generatedBytes / hashLen + 1;
  85. if (n >= 256)
  86. {
  87. throw new DataLengthException(
  88. "HKDF cannot generate more than 255 blocks of HashLen size");
  89. }
  90. // special case for T(0): T(0) is empty, so no update
  91. if (generatedBytes != 0)
  92. {
  93. hMacHash.BlockUpdate(currentT, 0, hashLen);
  94. }
  95. hMacHash.BlockUpdate(info, 0, info.Length);
  96. hMacHash.Update((byte)n);
  97. hMacHash.DoFinal(currentT, 0);
  98. }
  99. public virtual IDigest Digest
  100. {
  101. get { return hMacHash.GetUnderlyingDigest(); }
  102. }
  103. public virtual int GenerateBytes(byte[] output, int outOff, int len)
  104. {
  105. if (generatedBytes + len > 255 * hashLen)
  106. {
  107. throw new DataLengthException(
  108. "HKDF may only be used for 255 * HashLen bytes of output");
  109. }
  110. if (generatedBytes % hashLen == 0)
  111. {
  112. ExpandNext();
  113. }
  114. // copy what is left in the currentT (1..hash
  115. int toGenerate = len;
  116. int posInT = generatedBytes % hashLen;
  117. int leftInT = hashLen - generatedBytes % hashLen;
  118. int toCopy = System.Math.Min(leftInT, toGenerate);
  119. Array.Copy(currentT, posInT, output, outOff, toCopy);
  120. generatedBytes += toCopy;
  121. toGenerate -= toCopy;
  122. outOff += toCopy;
  123. while (toGenerate > 0)
  124. {
  125. ExpandNext();
  126. toCopy = System.Math.Min(hashLen, toGenerate);
  127. Array.Copy(currentT, 0, output, outOff, toCopy);
  128. generatedBytes += toCopy;
  129. toGenerate -= toCopy;
  130. outOff += toCopy;
  131. }
  132. return len;
  133. }
  134. }
  135. }
  136. #pragma warning restore
  137. #endif