CMac.cs 7.2 KB

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