PageRenderTime 30ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenRA.Mods.Cnc/FileFormats/BlowfishKeyProvider.cs

https://github.com/cjshmyr/OpenRA
C# | 493 lines | 412 code | 72 blank | 9 comment | 75 complexity | b6a215ccf40a263bf3a09a4b44788ae1 MD5 | raw file
Possible License(s): GPL-3.0
  1. #region Copyright & License Information
  2. /*
  3. * Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
  4. * This file is part of OpenRA, which is free software. It is made
  5. * available to you under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, either version 3 of
  7. * the License, or (at your option) any later version. For more
  8. * information, see COPYING.
  9. */
  10. #endregion
  11. using System;
  12. using System.Linq;
  13. namespace OpenRA.Mods.Cnc.FileFormats
  14. {
  15. /* TODO: Convert this direct C port into readable code. */
  16. class BlowfishKeyProvider
  17. {
  18. const string PublicKeyString = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V";
  19. class PublicKey
  20. {
  21. public uint[] KeyOne = new uint[64];
  22. public uint[] KeyTwo = new uint[64];
  23. public uint Len;
  24. }
  25. PublicKey pubkey = new PublicKey();
  26. uint[] globOne = new uint[64];
  27. uint globOneBitLen, globOneLenXTwo;
  28. uint[] globTwo = new uint[130];
  29. uint[] globOneHigh = new uint[4];
  30. uint[] globOneHighInv = new uint[4];
  31. uint globOneHighBitLen;
  32. uint globOneHighInvLow, globOneHighInvHigh;
  33. static void InitBigNum(uint[] n, uint val, uint len)
  34. {
  35. for (var i = 0; i < len; i++) n[i] = 0;
  36. n[0] = val;
  37. }
  38. static void MoveKeyToBig(uint[] n, byte[] key, uint klen, uint blen)
  39. {
  40. byte sign;
  41. if ((key[0] & 0x80) != 0) sign = 0xff;
  42. else sign = 0;
  43. unsafe
  44. {
  45. fixed (uint* tempPn = &n[0])
  46. {
  47. var pn = (byte*)tempPn;
  48. var i = blen * 4;
  49. for (; i > klen; i--) pn[i - 1] = sign;
  50. for (; i > 0; i--) pn[i - 1] = key[klen - i];
  51. }
  52. }
  53. }
  54. static void KeyToBigNum(uint[] n, byte[] key, uint len)
  55. {
  56. uint keylen;
  57. int i;
  58. var j = 0;
  59. if (key[j] != 2) return;
  60. j++;
  61. if ((key[j] & 0x80) != 0)
  62. {
  63. keylen = 0;
  64. for (i = 0; i < (key[j] & 0x7f); i++) keylen = (keylen << 8) | key[j + i + 1];
  65. j += (key[j] & 0x7f) + 1;
  66. }
  67. else
  68. {
  69. keylen = key[j];
  70. j++;
  71. }
  72. if (keylen <= len * 4)
  73. MoveKeyToBig(n, key.Skip(j).ToArray(), keylen, len);
  74. }
  75. static uint LenBigNum(uint[] n, uint len)
  76. {
  77. uint i;
  78. i = len - 1;
  79. while ((i >= 0) && (n[i] == 0)) i--;
  80. return i + 1;
  81. }
  82. static uint BitLenBigNum(uint[] n, uint len)
  83. {
  84. uint ddlen, bitlen, mask;
  85. ddlen = LenBigNum(n, len);
  86. if (ddlen == 0) return 0;
  87. bitlen = ddlen * 32;
  88. mask = 0x80000000;
  89. while ((mask & n[ddlen - 1]) == 0)
  90. {
  91. mask >>= 1;
  92. bitlen--;
  93. }
  94. return bitlen;
  95. }
  96. void InitPublicKey()
  97. {
  98. InitBigNum(pubkey.KeyTwo, 0x10001, 64);
  99. KeyToBigNum(pubkey.KeyOne, Convert.FromBase64String(PublicKeyString), 64);
  100. pubkey.Len = BitLenBigNum(pubkey.KeyOne, 64) - 1;
  101. }
  102. static int CompareBigNum(uint[] n1, uint[] n2, uint len)
  103. {
  104. while (len > 0)
  105. {
  106. --len;
  107. if (n1[len] < n2[len]) return -1;
  108. if (n1[len] > n2[len]) return 1;
  109. }
  110. return 0;
  111. }
  112. static void MoveBigNum(uint[] dest, uint[] src, uint len)
  113. {
  114. Array.Copy(src, dest, len);
  115. }
  116. static void ShrBigNum(uint[] n, int bits, int len)
  117. {
  118. int i; var i2 = bits / 32;
  119. if (i2 > 0)
  120. {
  121. for (i = 0; i < len - i2; i++) n[i] = n[i + i2];
  122. for (; i < len; i++) n[i] = 0;
  123. bits = bits % 32;
  124. }
  125. if (bits == 0) return;
  126. for (i = 0; i < len - 1; i++) n[i] = (n[i] >> bits) | (n[i + 1] << (32 - bits));
  127. n[i] = n[i] >> bits;
  128. }
  129. static void ShlBigNum(uint[] n, int bits, int len)
  130. {
  131. int i, i2;
  132. i2 = bits / 32;
  133. if (i2 > 0)
  134. {
  135. for (i = len - 1; i > i2; i--) n[i] = n[i - i2];
  136. for (; i > 0; i--) n[i] = 0;
  137. bits = bits % 32;
  138. }
  139. if (bits == 0) return;
  140. for (i = len - 1; i > 0; i--) n[i] = (n[i] << bits) | (n[i - 1] >> (32 - bits));
  141. n[0] <<= bits;
  142. }
  143. static uint SubBigNum(uint[] dest, uint[] src1, uint[] src2, uint carry, int len)
  144. {
  145. uint i1, i2;
  146. len += len;
  147. unsafe
  148. {
  149. fixed (uint* tempPs1 = &src1[0])
  150. fixed (uint* tempPs2 = &src2[0])
  151. fixed (uint* tempPd = &dest[0])
  152. {
  153. var ps1 = (ushort*)tempPs1;
  154. var ps2 = (ushort*)tempPs2;
  155. var pd = (ushort*)tempPd;
  156. while (--len != -1)
  157. {
  158. i1 = *ps1++;
  159. i2 = *ps2++;
  160. *pd++ = (ushort)(i1 - i2 - carry);
  161. if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0;
  162. }
  163. }
  164. }
  165. return carry;
  166. }
  167. static unsafe uint SubBigNum(uint* dest, uint* src1, uint* src2, uint carry, int len)
  168. {
  169. uint i1, i2;
  170. len += len;
  171. var ps1 = (ushort*)src1;
  172. var ps2 = (ushort*)src2;
  173. var pd = (ushort*)dest;
  174. while (--len != -1)
  175. {
  176. i1 = *ps1++;
  177. i2 = *ps2++;
  178. *pd++ = (ushort)(i1 - i2 - carry);
  179. if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0;
  180. }
  181. return carry;
  182. }
  183. static void InvertBigNum(uint[] n1, uint[] n2, uint len)
  184. {
  185. var nTmp = new uint[64];
  186. uint nTwoByteLen, bit;
  187. int nTwoBitLen;
  188. var j = 0;
  189. InitBigNum(nTmp, 0, len);
  190. InitBigNum(n1, 0, len);
  191. nTwoBitLen = (int)BitLenBigNum(n2, len);
  192. bit = ((uint)1) << (nTwoBitLen % 32);
  193. j = ((nTwoBitLen + 32) / 32) - 1;
  194. nTwoByteLen = (uint)((nTwoBitLen - 1) / 32) * 4;
  195. nTmp[nTwoByteLen / 4] |= ((uint)1) << ((nTwoBitLen - 1) & 0x1f);
  196. while (nTwoBitLen > 0)
  197. {
  198. nTwoBitLen--;
  199. ShlBigNum(nTmp, 1, (int)len);
  200. if (CompareBigNum(nTmp, n2, len) != -1)
  201. {
  202. SubBigNum(nTmp, nTmp, n2, 0, (int)len);
  203. n1[j] |= bit;
  204. }
  205. bit >>= 1;
  206. if (bit == 0)
  207. {
  208. j--;
  209. bit = 0x80000000;
  210. }
  211. }
  212. InitBigNum(nTmp, 0, len);
  213. }
  214. static void IncrementBigNum(uint[] n, uint len)
  215. {
  216. var i = 0;
  217. while ((++n[i] == 0) && (--len > 0)) i++;
  218. }
  219. void InitTwoDw(uint[] n, uint len)
  220. {
  221. MoveBigNum(globOne, n, len);
  222. globOneBitLen = BitLenBigNum(globOne, len);
  223. globOneLenXTwo = (globOneBitLen + 15) / 16;
  224. MoveBigNum(globOneHigh, globOne.Skip((int)LenBigNum(globOne, len) - 2).ToArray(), 2);
  225. globOneHighBitLen = BitLenBigNum(globOneHigh, 2) - 32;
  226. ShrBigNum(globOneHigh, (int)globOneHighBitLen, 2);
  227. InvertBigNum(globOneHighInv, globOneHigh, 2);
  228. ShrBigNum(globOneHighInv, 1, 2);
  229. globOneHighBitLen = (globOneHighBitLen + 15) % 16 + 1;
  230. IncrementBigNum(globOneHighInv, 2);
  231. if (BitLenBigNum(globOneHighInv, 2) > 32)
  232. {
  233. ShrBigNum(globOneHighInv, 1, 2);
  234. globOneHighBitLen--;
  235. }
  236. globOneHighInvLow = (ushort)globOneHighInv[0];
  237. globOneHighInvHigh = (ushort)(globOneHighInv[0] >> 16);
  238. }
  239. static unsafe void MulBignumWord(ushort* pn1, uint[] n2, uint mul, uint len)
  240. {
  241. uint i, tmp;
  242. unsafe
  243. {
  244. fixed (uint* tempPn2 = &n2[0])
  245. {
  246. var pn2 = (ushort*)tempPn2;
  247. tmp = 0;
  248. for (i = 0; i < len; i++)
  249. {
  250. tmp = mul * (*pn2) + (*pn1) + tmp;
  251. *pn1 = (ushort)tmp;
  252. pn1++;
  253. pn2++;
  254. tmp >>= 16;
  255. }
  256. *pn1 += (ushort)tmp;
  257. }
  258. }
  259. }
  260. static void MulBigNum(uint[] dest, uint[] src1, uint[] src2, uint len)
  261. {
  262. uint i;
  263. unsafe
  264. {
  265. fixed (uint* tempSrc2 = &src2[0])
  266. fixed (uint* tempPdest = &dest[0])
  267. {
  268. var psrc2 = (ushort*)tempSrc2;
  269. var pdest = (ushort*)tempPdest;
  270. InitBigNum(dest, 0, len * 2);
  271. for (i = 0; i < len * 2; i++)
  272. MulBignumWord(pdest++, src1, *psrc2++, len * 2);
  273. }
  274. }
  275. }
  276. static void NotBigNum(uint[] n, uint len)
  277. {
  278. uint i;
  279. for (i = 0; i < len; i++) n[i] = ~n[i];
  280. }
  281. static void NegBigNum(uint[] n, uint len)
  282. {
  283. NotBigNum(n, len);
  284. IncrementBigNum(n, len);
  285. }
  286. unsafe uint GetMulWord(uint* n)
  287. {
  288. var wn = (ushort*)n;
  289. var i = (uint)((((((((((*(wn - 1) ^ 0xffff) & 0xffff) * globOneHighInvLow + 0x10000) >> 1)
  290. + (((*(wn - 2) ^ 0xffff) * globOneHighInvHigh + globOneHighInvHigh) >> 1) + 1)
  291. >> 16) + ((((*(wn - 1) ^ 0xffff) & 0xffff) * globOneHighInvHigh) >> 1) +
  292. (((*wn ^ 0xffff) * globOneHighInvLow) >> 1) + 1) >> 14) + globOneHighInvHigh
  293. * (*wn ^ 0xffff) * 2) >> (int)globOneHighBitLen);
  294. if (i > 0xffff) i = 0xffff;
  295. return i & 0xffff;
  296. }
  297. static void DecBigNum(uint[] n, uint len)
  298. {
  299. var i = 0;
  300. while ((--n[i] == 0xffffffff) && (--len > 0))
  301. i++;
  302. }
  303. void CalcBigNum(uint[] n1, uint[] n2, uint[] n3, uint len)
  304. {
  305. uint globTwoXtwo, lenDiff;
  306. unsafe
  307. {
  308. fixed (uint* g1 = &globOne[0])
  309. fixed (uint* g2 = &globTwo[0])
  310. {
  311. MulBigNum(globTwo, n2, n3, len);
  312. globTwo[len * 2] = 0;
  313. globTwoXtwo = LenBigNum(globTwo, len * 2 + 1) * 2;
  314. if (globTwoXtwo >= globOneLenXTwo)
  315. {
  316. IncrementBigNum(globTwo, len * 2 + 1);
  317. NegBigNum(globTwo, len * 2 + 1);
  318. lenDiff = globTwoXtwo + 1 - globOneLenXTwo;
  319. var esi = ((ushort*)g2) + (1 + globTwoXtwo - globOneLenXTwo);
  320. var edi = ((ushort*)g2) + (globTwoXtwo + 1);
  321. for (; lenDiff != 0; lenDiff--)
  322. {
  323. edi--;
  324. var tmp = GetMulWord((uint*)edi);
  325. esi--;
  326. if (tmp > 0)
  327. {
  328. MulBignumWord(esi, globOne, tmp, 2 * len);
  329. if ((*edi & 0x8000) == 0)
  330. {
  331. if (0 != SubBigNum((uint*)esi, (uint*)esi, g1, 0, (int)len))
  332. (*edi)--;
  333. }
  334. }
  335. }
  336. NegBigNum(globTwo, len);
  337. DecBigNum(globTwo, len);
  338. }
  339. MoveBigNum(n1, globTwo, len);
  340. }
  341. }
  342. }
  343. void ClearTempVars(uint len)
  344. {
  345. InitBigNum(globOne, 0, len);
  346. InitBigNum(globTwo, 0, len);
  347. InitBigNum(globOneHighInv, 0, 4);
  348. InitBigNum(globOneHigh, 0, 4);
  349. globOneBitLen = 0;
  350. globOneHighBitLen = 0;
  351. globOneLenXTwo = 0;
  352. globOneHighInvLow = 0;
  353. globOneHighInvHigh = 0;
  354. }
  355. void CalcKey(uint[] n1, uint[] n2, uint[] n3, uint[] n4, uint len)
  356. {
  357. var n_tmp = new uint[64];
  358. uint n3_len, n4_len;
  359. int n3_bitlen;
  360. uint bit_mask;
  361. unsafe
  362. {
  363. fixed (uint* tempPn3 = &n3[0])
  364. {
  365. var pn3 = tempPn3;
  366. InitBigNum(n1, 1, len);
  367. n4_len = LenBigNum(n4, len);
  368. InitTwoDw(n4, n4_len);
  369. n3_bitlen = (int)BitLenBigNum(n3, n4_len);
  370. n3_len = (uint)((n3_bitlen + 31) / 32);
  371. bit_mask = (((uint)1) << ((n3_bitlen - 1) % 32)) >> 1;
  372. pn3 += n3_len - 1;
  373. n3_bitlen--;
  374. MoveBigNum(n1, n2, n4_len);
  375. while (--n3_bitlen != -1)
  376. {
  377. if (bit_mask == 0)
  378. {
  379. bit_mask = 0x80000000;
  380. pn3--;
  381. }
  382. CalcBigNum(n_tmp, n1, n1, n4_len);
  383. if ((*pn3 & bit_mask) != 0)
  384. CalcBigNum(n1, n_tmp, n2, n4_len);
  385. else
  386. MoveBigNum(n1, n_tmp, n4_len);
  387. bit_mask >>= 1;
  388. }
  389. InitBigNum(n_tmp, 0, n4_len);
  390. ClearTempVars(len);
  391. }
  392. }
  393. }
  394. byte[] ProcessPredata(byte[] src)
  395. {
  396. var dest = new byte[256];
  397. var n2 = new uint[64];
  398. var n3 = new uint[64];
  399. var a = (int)((pubkey.Len - 1) / 8);
  400. var pre_len = (55 / a + 1) * (a + 1);
  401. var srcOffset = 0;
  402. var destOffset = 0;
  403. while (a + 1 <= pre_len)
  404. {
  405. InitBigNum(n2, 0, 64);
  406. Buffer.BlockCopy(src, srcOffset, n2, 0, a + 1);
  407. CalcKey(n3, n2, pubkey.KeyTwo, pubkey.KeyOne, 64);
  408. Buffer.BlockCopy(n3, 0, dest, destOffset, a);
  409. pre_len -= a + 1;
  410. srcOffset += a + 1;
  411. destOffset += a;
  412. }
  413. return dest;
  414. }
  415. public byte[] DecryptKey(byte[] src)
  416. {
  417. InitPublicKey();
  418. return ProcessPredata(src).Take(56).ToArray();
  419. }
  420. }
  421. }