HMac.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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.Utilities;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs
  7. {
  8. /**
  9. * HMAC implementation based on RFC2104
  10. *
  11. * H(K XOR opad, H(K XOR ipad, text))
  12. */
  13. public class HMac
  14. : IMac
  15. {
  16. private const byte IPAD = (byte)0x36;
  17. private const byte OPAD = (byte)0x5C;
  18. private readonly IDigest digest;
  19. private readonly int digestSize;
  20. private readonly int blockLength;
  21. private IMemoable ipadState;
  22. private IMemoable opadState;
  23. private readonly byte[] inputPad;
  24. private readonly byte[] outputBuf;
  25. public HMac(IDigest digest)
  26. {
  27. this.digest = digest;
  28. this.digestSize = digest.GetDigestSize();
  29. this.blockLength = digest.GetByteLength();
  30. this.inputPad = new byte[blockLength];
  31. this.outputBuf = new byte[blockLength + digestSize];
  32. }
  33. public virtual string AlgorithmName
  34. {
  35. get { return digest.AlgorithmName + "/HMAC"; }
  36. }
  37. public virtual IDigest GetUnderlyingDigest()
  38. {
  39. return digest;
  40. }
  41. public virtual void Init(ICipherParameters parameters)
  42. {
  43. digest.Reset();
  44. byte[] key = ((KeyParameter)parameters).GetKey();
  45. int keyLength = key.Length;
  46. if (keyLength > blockLength)
  47. {
  48. digest.BlockUpdate(key, 0, keyLength);
  49. digest.DoFinal(inputPad, 0);
  50. keyLength = digestSize;
  51. }
  52. else
  53. {
  54. Array.Copy(key, 0, inputPad, 0, keyLength);
  55. }
  56. Array.Clear(inputPad, keyLength, blockLength - keyLength);
  57. Array.Copy(inputPad, 0, outputBuf, 0, blockLength);
  58. XorPad(inputPad, blockLength, IPAD);
  59. XorPad(outputBuf, blockLength, OPAD);
  60. if (digest is IMemoable)
  61. {
  62. opadState = ((IMemoable)digest).Copy();
  63. ((IDigest)opadState).BlockUpdate(outputBuf, 0, blockLength);
  64. }
  65. digest.BlockUpdate(inputPad, 0, inputPad.Length);
  66. if (digest is IMemoable)
  67. {
  68. ipadState = ((IMemoable)digest).Copy();
  69. }
  70. }
  71. public virtual int GetMacSize()
  72. {
  73. return digestSize;
  74. }
  75. public virtual void Update(byte input)
  76. {
  77. digest.Update(input);
  78. }
  79. public virtual void BlockUpdate(byte[] input, int inOff, int len)
  80. {
  81. digest.BlockUpdate(input, inOff, len);
  82. }
  83. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  84. public virtual void BlockUpdate(ReadOnlySpan<byte> input)
  85. {
  86. digest.BlockUpdate(input);
  87. }
  88. #endif
  89. public virtual int DoFinal(byte[] output, int outOff)
  90. {
  91. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  92. return DoFinal(output.AsSpan(outOff));
  93. #else
  94. digest.DoFinal(outputBuf, blockLength);
  95. if (opadState != null)
  96. {
  97. ((IMemoable)digest).Reset(opadState);
  98. digest.BlockUpdate(outputBuf, blockLength, digestSize);
  99. }
  100. else
  101. {
  102. digest.BlockUpdate(outputBuf, 0, outputBuf.Length);
  103. }
  104. int len = digest.DoFinal(output, outOff);
  105. Array.Clear(outputBuf, blockLength, digestSize);
  106. if (ipadState != null)
  107. {
  108. ((IMemoable)digest).Reset(ipadState);
  109. }
  110. else
  111. {
  112. digest.BlockUpdate(inputPad, 0, inputPad.Length);
  113. }
  114. return len;
  115. #endif
  116. }
  117. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  118. public virtual int DoFinal(Span<byte> output)
  119. {
  120. digest.DoFinal(outputBuf.AsSpan(blockLength));
  121. if (opadState != null)
  122. {
  123. ((IMemoable)digest).Reset(opadState);
  124. digest.BlockUpdate(outputBuf.AsSpan(blockLength, digestSize));
  125. }
  126. else
  127. {
  128. digest.BlockUpdate(outputBuf);
  129. }
  130. int len = digest.DoFinal(output);
  131. Array.Clear(outputBuf, blockLength, digestSize);
  132. if (ipadState != null)
  133. {
  134. ((IMemoable)digest).Reset(ipadState);
  135. }
  136. else
  137. {
  138. digest.BlockUpdate(inputPad);
  139. }
  140. return len;
  141. }
  142. #endif
  143. /**
  144. * Reset the mac generator.
  145. */
  146. public virtual void Reset()
  147. {
  148. if (ipadState != null)
  149. {
  150. ((IMemoable)digest).Reset(ipadState);
  151. }
  152. else
  153. {
  154. digest.Reset();
  155. digest.BlockUpdate(inputPad, 0, inputPad.Length);
  156. }
  157. }
  158. private static void XorPad(byte[] pad, int len, byte n)
  159. {
  160. for (int i = 0; i < len; ++i)
  161. {
  162. pad[i] ^= n;
  163. }
  164. }
  165. }
  166. }
  167. #pragma warning restore
  168. #endif