IdeaEngine.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using Org.BouncyCastle.Crypto.Parameters;
  4. using Org.BouncyCastle.Utilities;
  5. namespace Org.BouncyCastle.Crypto.Engines
  6. {
  7. /**
  8. * A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
  9. * <p>
  10. * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
  11. * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
  12. * end of the mulinv function!).
  13. * </p>
  14. * <p>
  15. * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
  16. * </p>
  17. * <p>
  18. * Note 1: This algorithm is patented in the USA, Japan, and Europe including
  19. * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
  20. * and the United Kingdom. Non-commercial use is free, however any commercial
  21. * products are liable for royalties. Please see
  22. * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for
  23. * further details. This announcement has been included at the request of
  24. * the patent holders.
  25. * </p>
  26. * <p>
  27. * Note 2: Due to the requests concerning the above, this algorithm is now only
  28. * included in the extended assembly. It is not included in the default distributions.
  29. * </p>
  30. */
  31. public class IdeaEngine
  32. : IBlockCipher
  33. {
  34. private const int BLOCK_SIZE = 8;
  35. private int[] workingKey;
  36. /**
  37. * standard constructor.
  38. */
  39. public IdeaEngine()
  40. {
  41. }
  42. /**
  43. * initialise an IDEA cipher.
  44. *
  45. * @param forEncryption whether or not we are for encryption.
  46. * @param parameters the parameters required to set up the cipher.
  47. * @exception ArgumentException if the parameters argument is
  48. * inappropriate.
  49. */
  50. public virtual void Init(
  51. bool forEncryption,
  52. ICipherParameters parameters)
  53. {
  54. if (!(parameters is KeyParameter))
  55. throw new ArgumentException("invalid parameter passed to IDEA init - " + Org.BouncyCastle.Utilities.Platform.GetTypeName(parameters));
  56. workingKey = GenerateWorkingKey(forEncryption,
  57. ((KeyParameter)parameters).GetKey());
  58. }
  59. public virtual string AlgorithmName
  60. {
  61. get { return "IDEA"; }
  62. }
  63. public virtual bool IsPartialBlockOkay
  64. {
  65. get { return false; }
  66. }
  67. public virtual int GetBlockSize()
  68. {
  69. return BLOCK_SIZE;
  70. }
  71. public virtual int ProcessBlock(
  72. byte[] input,
  73. int inOff,
  74. byte[] output,
  75. int outOff)
  76. {
  77. if (workingKey == null)
  78. throw new InvalidOperationException("IDEA engine not initialised");
  79. Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
  80. Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
  81. IdeaFunc(workingKey, input, inOff, output, outOff);
  82. return BLOCK_SIZE;
  83. }
  84. public virtual void Reset()
  85. {
  86. }
  87. private static readonly int MASK = 0xffff;
  88. private static readonly int BASE = 0x10001;
  89. private int BytesToWord(
  90. byte[] input,
  91. int inOff)
  92. {
  93. return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff);
  94. }
  95. private void WordToBytes(
  96. int word,
  97. byte[] outBytes,
  98. int outOff)
  99. {
  100. outBytes[outOff] = (byte)((uint) word >> 8);
  101. outBytes[outOff + 1] = (byte)word;
  102. }
  103. /**
  104. * return x = x * y where the multiplication is done modulo
  105. * 65537 (0x10001) (as defined in the IDEA specification) and
  106. * a zero input is taken to be 65536 (0x10000).
  107. *
  108. * @param x the x value
  109. * @param y the y value
  110. * @return x = x * y
  111. */
  112. private int Mul(
  113. int x,
  114. int y)
  115. {
  116. if (x == 0)
  117. {
  118. x = (BASE - y);
  119. }
  120. else if (y == 0)
  121. {
  122. x = (BASE - x);
  123. }
  124. else
  125. {
  126. int p = x * y;
  127. y = p & MASK;
  128. x = (int) ((uint) p >> 16);
  129. x = y - x + ((y < x) ? 1 : 0);
  130. }
  131. return x & MASK;
  132. }
  133. private void IdeaFunc(
  134. int[] workingKey,
  135. byte[] input,
  136. int inOff,
  137. byte[] outBytes,
  138. int outOff)
  139. {
  140. int x0, x1, x2, x3, t0, t1;
  141. int keyOff = 0;
  142. x0 = BytesToWord(input, inOff);
  143. x1 = BytesToWord(input, inOff + 2);
  144. x2 = BytesToWord(input, inOff + 4);
  145. x3 = BytesToWord(input, inOff + 6);
  146. for (int round = 0; round < 8; round++)
  147. {
  148. x0 = Mul(x0, workingKey[keyOff++]);
  149. x1 += workingKey[keyOff++];
  150. x1 &= MASK;
  151. x2 += workingKey[keyOff++];
  152. x2 &= MASK;
  153. x3 = Mul(x3, workingKey[keyOff++]);
  154. t0 = x1;
  155. t1 = x2;
  156. x2 ^= x0;
  157. x1 ^= x3;
  158. x2 = Mul(x2, workingKey[keyOff++]);
  159. x1 += x2;
  160. x1 &= MASK;
  161. x1 = Mul(x1, workingKey[keyOff++]);
  162. x2 += x1;
  163. x2 &= MASK;
  164. x0 ^= x1;
  165. x3 ^= x2;
  166. x1 ^= t1;
  167. x2 ^= t0;
  168. }
  169. WordToBytes(Mul(x0, workingKey[keyOff++]), outBytes, outOff);
  170. WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2); /* NB: Order */
  171. WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
  172. WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
  173. }
  174. /**
  175. * The following function is used to expand the user key to the encryption
  176. * subkey. The first 16 bytes are the user key, and the rest of the subkey
  177. * is calculated by rotating the previous 16 bytes by 25 bits to the left,
  178. * and so on until the subkey is completed.
  179. */
  180. private int[] ExpandKey(
  181. byte[] uKey)
  182. {
  183. int[] key = new int[52];
  184. if (uKey.Length < 16)
  185. {
  186. byte[] tmp = new byte[16];
  187. Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length);
  188. uKey = tmp;
  189. }
  190. for (int i = 0; i < 8; i++)
  191. {
  192. key[i] = BytesToWord(uKey, i * 2);
  193. }
  194. for (int i = 8; i < 52; i++)
  195. {
  196. if ((i & 7) < 6)
  197. {
  198. key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK;
  199. }
  200. else if ((i & 7) == 6)
  201. {
  202. key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK;
  203. }
  204. else
  205. {
  206. key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK;
  207. }
  208. }
  209. return key;
  210. }
  211. /**
  212. * This function computes multiplicative inverse using Euclid's Greatest
  213. * Common Divisor algorithm. Zero and one are self inverse.
  214. * <p>
  215. * i.e. x * MulInv(x) == 1 (modulo BASE)
  216. * </p>
  217. */
  218. private int MulInv(
  219. int x)
  220. {
  221. int t0, t1, q, y;
  222. if (x < 2)
  223. {
  224. return x;
  225. }
  226. t0 = 1;
  227. t1 = BASE / x;
  228. y = BASE % x;
  229. while (y != 1)
  230. {
  231. q = x / y;
  232. x = x % y;
  233. t0 = (t0 + (t1 * q)) & MASK;
  234. if (x == 1)
  235. {
  236. return t0;
  237. }
  238. q = y / x;
  239. y = y % x;
  240. t1 = (t1 + (t0 * q)) & MASK;
  241. }
  242. return (1 - t1) & MASK;
  243. }
  244. /**
  245. * Return the additive inverse of x.
  246. * <p>
  247. * i.e. x + AddInv(x) == 0
  248. * </p>
  249. */
  250. int AddInv(
  251. int x)
  252. {
  253. return (0 - x) & MASK;
  254. }
  255. /**
  256. * The function to invert the encryption subkey to the decryption subkey.
  257. * It also involves the multiplicative inverse and the additive inverse functions.
  258. */
  259. private int[] InvertKey(
  260. int[] inKey)
  261. {
  262. int t1, t2, t3, t4;
  263. int p = 52; /* We work backwards */
  264. int[] key = new int[52];
  265. int inOff = 0;
  266. t1 = MulInv(inKey[inOff++]);
  267. t2 = AddInv(inKey[inOff++]);
  268. t3 = AddInv(inKey[inOff++]);
  269. t4 = MulInv(inKey[inOff++]);
  270. key[--p] = t4;
  271. key[--p] = t3;
  272. key[--p] = t2;
  273. key[--p] = t1;
  274. for (int round = 1; round < 8; round++)
  275. {
  276. t1 = inKey[inOff++];
  277. t2 = inKey[inOff++];
  278. key[--p] = t2;
  279. key[--p] = t1;
  280. t1 = MulInv(inKey[inOff++]);
  281. t2 = AddInv(inKey[inOff++]);
  282. t3 = AddInv(inKey[inOff++]);
  283. t4 = MulInv(inKey[inOff++]);
  284. key[--p] = t4;
  285. key[--p] = t2; /* NB: Order */
  286. key[--p] = t3;
  287. key[--p] = t1;
  288. }
  289. t1 = inKey[inOff++];
  290. t2 = inKey[inOff++];
  291. key[--p] = t2;
  292. key[--p] = t1;
  293. t1 = MulInv(inKey[inOff++]);
  294. t2 = AddInv(inKey[inOff++]);
  295. t3 = AddInv(inKey[inOff++]);
  296. t4 = MulInv(inKey[inOff]);
  297. key[--p] = t4;
  298. key[--p] = t3;
  299. key[--p] = t2;
  300. key[--p] = t1;
  301. return key;
  302. }
  303. private int[] GenerateWorkingKey(
  304. bool forEncryption,
  305. byte[] userKey)
  306. {
  307. if (forEncryption)
  308. {
  309. return ExpandKey(userKey);
  310. }
  311. else
  312. {
  313. return InvertKey(ExpandKey(userKey));
  314. }
  315. }
  316. }
  317. }
  318. #endif