IdeaEngine.cs 9.9 KB

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