CMac.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Paddings;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  7. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs
  8. {
  9. /**
  10. * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
  11. * <p>
  12. * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
  13. * </p><p>
  14. * CMAC is a NIST recomendation - see
  15. * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
  16. * </p><p>
  17. * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
  18. * analyzed by Tetsu Iwata and Kaoru Kurosawa.
  19. * </p><p>
  20. * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message
  21. * Authentication Code). OMAC stands for One-Key CBC MAC.
  22. * </p><p>
  23. * It supports 128- or 64-bits block ciphers, with any key size, and returns
  24. * a MAC with dimension less or equal to the block size of the underlying
  25. * cipher.
  26. * </p>
  27. */
  28. public class CMac
  29. : IMac
  30. {
  31. private const byte CONSTANT_128 = (byte)0x87;
  32. private const byte CONSTANT_64 = (byte)0x1b;
  33. private byte[] ZEROES;
  34. private byte[] mac;
  35. private byte[] buf;
  36. private int bufOff;
  37. private IBlockCipher cipher;
  38. private int macSize;
  39. private byte[] L, Lu, Lu2;
  40. /**
  41. * create a standard MAC based on a CBC block cipher (64 or 128 bit block).
  42. * This will produce an authentication code the length of the block size
  43. * of the cipher.
  44. *
  45. * @param cipher the cipher to be used as the basis of the MAC generation.
  46. */
  47. public CMac(
  48. IBlockCipher cipher)
  49. : this(cipher, cipher.GetBlockSize() * 8)
  50. {
  51. }
  52. /**
  53. * create a standard MAC based on a block cipher with the size of the
  54. * MAC been given in bits.
  55. * <p/>
  56. * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
  57. * or 16 bits if being used as a data authenticator (FIPS Publication 113),
  58. * and in general should be less than the size of the block cipher as it reduces
  59. * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
  60. *
  61. * @param cipher the cipher to be used as the basis of the MAC generation.
  62. * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and @lt;= 128.
  63. */
  64. public CMac(
  65. IBlockCipher cipher,
  66. int macSizeInBits)
  67. {
  68. if ((macSizeInBits % 8) != 0)
  69. throw new ArgumentException("MAC size must be multiple of 8");
  70. if (macSizeInBits > (cipher.GetBlockSize() * 8))
  71. {
  72. throw new ArgumentException(
  73. "MAC size must be less or equal to "
  74. + (cipher.GetBlockSize() * 8));
  75. }
  76. if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16)
  77. {
  78. throw new ArgumentException(
  79. "Block size must be either 64 or 128 bits");
  80. }
  81. this.cipher = new CbcBlockCipher(cipher);
  82. this.macSize = macSizeInBits / 8;
  83. mac = new byte[cipher.GetBlockSize()];
  84. buf = new byte[cipher.GetBlockSize()];
  85. ZEROES = new byte[cipher.GetBlockSize()];
  86. bufOff = 0;
  87. }
  88. public string AlgorithmName
  89. {
  90. get { return cipher.AlgorithmName; }
  91. }
  92. private static int ShiftLeft(byte[] block, byte[] output)
  93. {
  94. int i = block.Length;
  95. uint bit = 0;
  96. while (--i >= 0)
  97. {
  98. uint b = block[i];
  99. output[i] = (byte)((b << 1) | bit);
  100. bit = (b >> 7) & 1;
  101. }
  102. return (int)bit;
  103. }
  104. private static byte[] DoubleLu(byte[] input)
  105. {
  106. byte[] ret = new byte[input.Length];
  107. int carry = ShiftLeft(input, ret);
  108. int xor = input.Length == 16 ? CONSTANT_128 : CONSTANT_64;
  109. /*
  110. * NOTE: This construction is an attempt at a constant-time implementation.
  111. */
  112. ret[input.Length - 1] ^= (byte)(xor >> ((1 - carry) << 3));
  113. return ret;
  114. }
  115. public void Init(
  116. ICipherParameters parameters)
  117. {
  118. if (parameters is KeyParameter)
  119. {
  120. cipher.Init(true, parameters);
  121. //initializes the L, Lu, Lu2 numbers
  122. L = new byte[ZEROES.Length];
  123. cipher.ProcessBlock(ZEROES, 0, L, 0);
  124. Lu = DoubleLu(L);
  125. Lu2 = DoubleLu(Lu);
  126. }
  127. else if (parameters != null)
  128. {
  129. // CMAC mode does not permit IV to underlying CBC mode
  130. throw new ArgumentException("CMac mode only permits key to be set.", "parameters");
  131. }
  132. Reset();
  133. }
  134. public int GetMacSize()
  135. {
  136. return macSize;
  137. }
  138. public void Update(
  139. byte input)
  140. {
  141. if (bufOff == buf.Length)
  142. {
  143. cipher.ProcessBlock(buf, 0, mac, 0);
  144. bufOff = 0;
  145. }
  146. buf[bufOff++] = input;
  147. }
  148. public void BlockUpdate(
  149. byte[] inBytes,
  150. int inOff,
  151. int len)
  152. {
  153. if (len < 0)
  154. throw new ArgumentException("Can't have a negative input length!");
  155. int blockSize = cipher.GetBlockSize();
  156. int gapLen = blockSize - bufOff;
  157. if (len > gapLen)
  158. {
  159. Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
  160. cipher.ProcessBlock(buf, 0, mac, 0);
  161. bufOff = 0;
  162. len -= gapLen;
  163. inOff += gapLen;
  164. while (len > blockSize)
  165. {
  166. cipher.ProcessBlock(inBytes, inOff, mac, 0);
  167. len -= blockSize;
  168. inOff += blockSize;
  169. }
  170. }
  171. Array.Copy(inBytes, inOff, buf, bufOff, len);
  172. bufOff += len;
  173. }
  174. public int DoFinal(
  175. byte[] outBytes,
  176. int outOff)
  177. {
  178. int blockSize = cipher.GetBlockSize();
  179. byte[] lu;
  180. if (bufOff == blockSize)
  181. {
  182. lu = Lu;
  183. }
  184. else
  185. {
  186. new ISO7816d4Padding().AddPadding(buf, bufOff);
  187. lu = Lu2;
  188. }
  189. for (int i = 0; i < mac.Length; i++)
  190. {
  191. buf[i] ^= lu[i];
  192. }
  193. cipher.ProcessBlock(buf, 0, mac, 0);
  194. Array.Copy(mac, 0, outBytes, outOff, macSize);
  195. Reset();
  196. return macSize;
  197. }
  198. /**
  199. * Reset the mac generator.
  200. */
  201. public void Reset()
  202. {
  203. /*
  204. * clean the buffer.
  205. */
  206. Array.Clear(buf, 0, buf.Length);
  207. bufOff = 0;
  208. /*
  209. * Reset the underlying cipher.
  210. */
  211. cipher.Reset();
  212. }
  213. }
  214. }
  215. #pragma warning restore
  216. #endif