CbcBlockCipherMac.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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.Modes;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Paddings;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs
  7. {
  8. /**
  9. * standard CBC Block Cipher MAC - if no padding is specified the default of
  10. * pad of zeroes is used.
  11. */
  12. public class CbcBlockCipherMac
  13. : IMac
  14. {
  15. private byte[] buf;
  16. private int bufOff;
  17. private IBlockCipherMode m_cipherMode;
  18. private IBlockCipherPadding padding;
  19. private int macSize;
  20. /**
  21. * create a standard MAC based on a CBC block cipher. This will produce an
  22. * authentication code half the length of the block size of the cipher.
  23. *
  24. * @param cipher the cipher to be used as the basis of the MAC generation.
  25. */
  26. public CbcBlockCipherMac(
  27. IBlockCipher cipher)
  28. : this(cipher, (cipher.GetBlockSize() * 8) / 2, null)
  29. {
  30. }
  31. /**
  32. * create a standard MAC based on a CBC block cipher. This will produce an
  33. * authentication code half the length of the block size of the cipher.
  34. *
  35. * @param cipher the cipher to be used as the basis of the MAC generation.
  36. * @param padding the padding to be used to complete the last block.
  37. */
  38. public CbcBlockCipherMac(
  39. IBlockCipher cipher,
  40. IBlockCipherPadding padding)
  41. : this(cipher, (cipher.GetBlockSize() * 8) / 2, padding)
  42. {
  43. }
  44. /**
  45. * create a standard MAC based on a block cipher with the size of the
  46. * MAC been given in bits. This class uses CBC mode as the basis for the
  47. * MAC generation.
  48. * <p>
  49. * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
  50. * or 16 bits if being used as a data authenticator (FIPS Publication 113),
  51. * and in general should be less than the size of the block cipher as it reduces
  52. * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
  53. * </p>
  54. * @param cipher the cipher to be used as the basis of the MAC generation.
  55. * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
  56. */
  57. public CbcBlockCipherMac(
  58. IBlockCipher cipher,
  59. int macSizeInBits)
  60. : this(cipher, macSizeInBits, null)
  61. {
  62. }
  63. /**
  64. * create a standard MAC based on a block cipher with the size of the
  65. * MAC been given in bits. This class uses CBC mode as the basis for the
  66. * MAC generation.
  67. * <p>
  68. * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
  69. * or 16 bits if being used as a data authenticator (FIPS Publication 113),
  70. * and in general should be less than the size of the block cipher as it reduces
  71. * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
  72. * </p>
  73. * @param cipher the cipher to be used as the basis of the MAC generation.
  74. * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
  75. * @param padding the padding to be used to complete the last block.
  76. */
  77. public CbcBlockCipherMac(
  78. IBlockCipher cipher,
  79. int macSizeInBits,
  80. IBlockCipherPadding padding)
  81. {
  82. if ((macSizeInBits % 8) != 0)
  83. throw new ArgumentException("MAC size must be multiple of 8");
  84. this.m_cipherMode = new CbcBlockCipher(cipher);
  85. this.padding = padding;
  86. this.macSize = macSizeInBits / 8;
  87. buf = new byte[cipher.GetBlockSize()];
  88. bufOff = 0;
  89. }
  90. public string AlgorithmName
  91. {
  92. get { return m_cipherMode.AlgorithmName; }
  93. }
  94. public void Init(ICipherParameters parameters)
  95. {
  96. Reset();
  97. m_cipherMode.Init(true, parameters);
  98. }
  99. public int GetMacSize()
  100. {
  101. return macSize;
  102. }
  103. public void Update(byte input)
  104. {
  105. if (bufOff == buf.Length)
  106. {
  107. m_cipherMode.ProcessBlock(buf, 0, buf, 0);
  108. bufOff = 0;
  109. }
  110. buf[bufOff++] = input;
  111. }
  112. public void BlockUpdate(byte[] input, int inOff, int len)
  113. {
  114. if (len < 0)
  115. throw new ArgumentException("Can't have a negative input length!");
  116. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  117. BlockUpdate(input.AsSpan(inOff, len));
  118. #else
  119. int blockSize = m_cipherMode.GetBlockSize();
  120. int gapLen = blockSize - bufOff;
  121. if (len > gapLen)
  122. {
  123. Array.Copy(input, inOff, buf, bufOff, gapLen);
  124. m_cipherMode.ProcessBlock(buf, 0, buf, 0);
  125. bufOff = 0;
  126. len -= gapLen;
  127. inOff += gapLen;
  128. while (len > blockSize)
  129. {
  130. m_cipherMode.ProcessBlock(input, inOff, buf, 0);
  131. len -= blockSize;
  132. inOff += blockSize;
  133. }
  134. }
  135. Array.Copy(input, inOff, buf, bufOff, len);
  136. bufOff += len;
  137. #endif
  138. }
  139. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  140. public void BlockUpdate(ReadOnlySpan<byte> input)
  141. {
  142. int blockSize = m_cipherMode.GetBlockSize();
  143. int gapLen = blockSize - bufOff;
  144. if (input.Length > gapLen)
  145. {
  146. input[..gapLen].CopyTo(buf.AsSpan(bufOff));
  147. m_cipherMode.ProcessBlock(buf, buf);
  148. bufOff = 0;
  149. input = input[gapLen..];
  150. while (input.Length > blockSize)
  151. {
  152. m_cipherMode.ProcessBlock(input, buf);
  153. input = input[blockSize..];
  154. }
  155. }
  156. input.CopyTo(buf.AsSpan(bufOff));
  157. bufOff += input.Length;
  158. }
  159. #endif
  160. public int DoFinal(byte[] output, int outOff)
  161. {
  162. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  163. return DoFinal(output.AsSpan(outOff));
  164. #else
  165. int blockSize = m_cipherMode.GetBlockSize();
  166. if (padding == null)
  167. {
  168. // pad with zeroes
  169. while (bufOff < blockSize)
  170. {
  171. buf[bufOff++] = 0;
  172. }
  173. }
  174. else
  175. {
  176. if (bufOff == blockSize)
  177. {
  178. m_cipherMode.ProcessBlock(buf, 0, buf, 0);
  179. bufOff = 0;
  180. }
  181. padding.AddPadding(buf, bufOff);
  182. }
  183. m_cipherMode.ProcessBlock(buf, 0, buf, 0);
  184. Array.Copy(buf, 0, output, outOff, macSize);
  185. Reset();
  186. return macSize;
  187. #endif
  188. }
  189. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  190. public int DoFinal(Span<byte> output)
  191. {
  192. int blockSize = m_cipherMode.GetBlockSize();
  193. if (padding == null)
  194. {
  195. // pad with zeroes
  196. while (bufOff < blockSize)
  197. {
  198. buf[bufOff++] = 0;
  199. }
  200. }
  201. else
  202. {
  203. if (bufOff == blockSize)
  204. {
  205. m_cipherMode.ProcessBlock(buf, buf);
  206. bufOff = 0;
  207. }
  208. padding.AddPadding(buf, bufOff);
  209. }
  210. m_cipherMode.ProcessBlock(buf, buf);
  211. buf.AsSpan(0, macSize).CopyTo(output);
  212. Reset();
  213. return macSize;
  214. }
  215. #endif
  216. /**
  217. * Reset the mac generator.
  218. */
  219. public void Reset()
  220. {
  221. // Clear the buffer.
  222. Array.Clear(buf, 0, buf.Length);
  223. bufOff = 0;
  224. // Reset the underlying cipher.
  225. m_cipherMode.Reset();
  226. }
  227. }
  228. }
  229. #pragma warning restore
  230. #endif