ISO9797Alg3Mac.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using Org.BouncyCastle.Crypto.Engines;
  4. using Org.BouncyCastle.Crypto.Modes;
  5. using Org.BouncyCastle.Crypto.Paddings;
  6. using Org.BouncyCastle.Crypto.Parameters;
  7. namespace Org.BouncyCastle.Crypto.Macs
  8. {
  9. /**
  10. * DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC)
  11. *
  12. * This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
  13. * class must be changed to protected
  14. */
  15. public class ISO9797Alg3Mac : IMac
  16. {
  17. private byte[] mac;
  18. private byte[] buf;
  19. private int bufOff;
  20. private IBlockCipher cipher;
  21. private IBlockCipherPadding padding;
  22. private int macSize;
  23. private KeyParameter lastKey2;
  24. private KeyParameter lastKey3;
  25. /**
  26. * create a Retail-MAC based on a CBC block cipher. This will produce an
  27. * authentication code of the length of the block size of the cipher.
  28. *
  29. * @param cipher the cipher to be used as the basis of the MAC generation. This must
  30. * be DESEngine.
  31. */
  32. public ISO9797Alg3Mac(
  33. IBlockCipher cipher)
  34. : this(cipher, cipher.GetBlockSize() * 8, null)
  35. {
  36. }
  37. /**
  38. * create a Retail-MAC based on a CBC block cipher. This will produce an
  39. * authentication code of the length of the block size of the cipher.
  40. *
  41. * @param cipher the cipher to be used as the basis of the MAC generation.
  42. * @param padding the padding to be used to complete the last block.
  43. */
  44. public ISO9797Alg3Mac(
  45. IBlockCipher cipher,
  46. IBlockCipherPadding padding)
  47. : this(cipher, cipher.GetBlockSize() * 8, padding)
  48. {
  49. }
  50. /**
  51. * create a Retail-MAC based on a block cipher with the size of the
  52. * MAC been given in bits. This class uses single DES CBC mode as the basis for the
  53. * MAC generation.
  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. * </p>
  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.
  62. */
  63. public ISO9797Alg3Mac(
  64. IBlockCipher cipher,
  65. int macSizeInBits)
  66. : this(cipher, macSizeInBits, null)
  67. {
  68. }
  69. /**
  70. * create a standard MAC based on a block cipher with the size of the
  71. * MAC been given in bits. This class uses single DES CBC mode as the basis for the
  72. * MAC generation. The final block is decrypted and then encrypted using the
  73. * middle and right part of the key.
  74. * <p>
  75. * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
  76. * or 16 bits if being used as a data authenticator (FIPS Publication 113),
  77. * and in general should be less than the size of the block cipher as it reduces
  78. * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
  79. * </p>
  80. * @param cipher the cipher to be used as the basis of the MAC generation.
  81. * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
  82. * @param padding the padding to be used to complete the last block.
  83. */
  84. public ISO9797Alg3Mac(
  85. IBlockCipher cipher,
  86. int macSizeInBits,
  87. IBlockCipherPadding padding)
  88. {
  89. if ((macSizeInBits % 8) != 0)
  90. throw new ArgumentException("MAC size must be multiple of 8");
  91. if (!(cipher is DesEngine))
  92. throw new ArgumentException("cipher must be instance of DesEngine");
  93. this.cipher = new CbcBlockCipher(cipher);
  94. this.padding = padding;
  95. this.macSize = macSizeInBits / 8;
  96. mac = new byte[cipher.GetBlockSize()];
  97. buf = new byte[cipher.GetBlockSize()];
  98. bufOff = 0;
  99. }
  100. public string AlgorithmName
  101. {
  102. get { return "ISO9797Alg3"; }
  103. }
  104. public void Init(
  105. ICipherParameters parameters)
  106. {
  107. Reset();
  108. if (!(parameters is KeyParameter || parameters is ParametersWithIV))
  109. throw new ArgumentException("parameters must be an instance of KeyParameter or ParametersWithIV");
  110. // KeyParameter must contain a double or triple length DES key,
  111. // however the underlying cipher is a single DES. The middle and
  112. // right key are used only in the final step.
  113. KeyParameter kp;
  114. if (parameters is KeyParameter)
  115. {
  116. kp = (KeyParameter)parameters;
  117. }
  118. else
  119. {
  120. kp = (KeyParameter)((ParametersWithIV)parameters).Parameters;
  121. }
  122. KeyParameter key1;
  123. byte[] keyvalue = kp.GetKey();
  124. if (keyvalue.Length == 16)
  125. { // Double length DES key
  126. key1 = new KeyParameter(keyvalue, 0, 8);
  127. this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
  128. this.lastKey3 = key1;
  129. }
  130. else if (keyvalue.Length == 24)
  131. { // Triple length DES key
  132. key1 = new KeyParameter(keyvalue, 0, 8);
  133. this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
  134. this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
  135. }
  136. else
  137. {
  138. throw new ArgumentException("Key must be either 112 or 168 bit long");
  139. }
  140. if (parameters is ParametersWithIV)
  141. {
  142. cipher.Init(true, new ParametersWithIV(key1, ((ParametersWithIV)parameters).GetIV()));
  143. }
  144. else
  145. {
  146. cipher.Init(true, key1);
  147. }
  148. }
  149. public int GetMacSize()
  150. {
  151. return macSize;
  152. }
  153. public void Update(
  154. byte input)
  155. {
  156. if (bufOff == buf.Length)
  157. {
  158. cipher.ProcessBlock(buf, 0, mac, 0);
  159. bufOff = 0;
  160. }
  161. buf[bufOff++] = input;
  162. }
  163. public void BlockUpdate(
  164. byte[] input,
  165. int inOff,
  166. int len)
  167. {
  168. if (len < 0)
  169. throw new ArgumentException("Can't have a negative input length!");
  170. int blockSize = cipher.GetBlockSize();
  171. int resultLen = 0;
  172. int gapLen = blockSize - bufOff;
  173. if (len > gapLen)
  174. {
  175. Array.Copy(input, inOff, buf, bufOff, gapLen);
  176. resultLen += cipher.ProcessBlock(buf, 0, mac, 0);
  177. bufOff = 0;
  178. len -= gapLen;
  179. inOff += gapLen;
  180. while (len > blockSize)
  181. {
  182. resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
  183. len -= blockSize;
  184. inOff += blockSize;
  185. }
  186. }
  187. Array.Copy(input, inOff, buf, bufOff, len);
  188. bufOff += len;
  189. }
  190. public int DoFinal(
  191. byte[] output,
  192. int outOff)
  193. {
  194. int blockSize = cipher.GetBlockSize();
  195. if (padding == null)
  196. {
  197. // pad with zeroes
  198. while (bufOff < blockSize)
  199. {
  200. buf[bufOff++] = 0;
  201. }
  202. }
  203. else
  204. {
  205. if (bufOff == blockSize)
  206. {
  207. cipher.ProcessBlock(buf, 0, mac, 0);
  208. bufOff = 0;
  209. }
  210. padding.AddPadding(buf, bufOff);
  211. }
  212. cipher.ProcessBlock(buf, 0, mac, 0);
  213. // Added to code from base class
  214. DesEngine deseng = new DesEngine();
  215. deseng.Init(false, this.lastKey2);
  216. deseng.ProcessBlock(mac, 0, mac, 0);
  217. deseng.Init(true, this.lastKey3);
  218. deseng.ProcessBlock(mac, 0, mac, 0);
  219. // ****
  220. Array.Copy(mac, 0, output, outOff, macSize);
  221. Reset();
  222. return macSize;
  223. }
  224. /**
  225. * Reset the mac generator.
  226. */
  227. public void Reset()
  228. {
  229. Array.Clear(buf, 0, buf.Length);
  230. bufOff = 0;
  231. // reset the underlying cipher.
  232. cipher.Reset();
  233. }
  234. }
  235. }
  236. #endif