/OpenRA.Mods.Cnc/FileFormats/BlowfishKeyProvider.cs
C# | 493 lines | 412 code | 72 blank | 9 comment | 75 complexity | b6a215ccf40a263bf3a09a4b44788ae1 MD5 | raw file
Possible License(s): GPL-3.0
- #region Copyright & License Information
- /*
- * Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
- * This file is part of OpenRA, which is free software. It is made
- * available to you under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version. For more
- * information, see COPYING.
- */
- #endregion
- using System;
- using System.Linq;
- namespace OpenRA.Mods.Cnc.FileFormats
- {
- /* TODO: Convert this direct C port into readable code. */
- class BlowfishKeyProvider
- {
- const string PublicKeyString = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V";
- class PublicKey
- {
- public uint[] KeyOne = new uint[64];
- public uint[] KeyTwo = new uint[64];
- public uint Len;
- }
- PublicKey pubkey = new PublicKey();
- uint[] globOne = new uint[64];
- uint globOneBitLen, globOneLenXTwo;
- uint[] globTwo = new uint[130];
- uint[] globOneHigh = new uint[4];
- uint[] globOneHighInv = new uint[4];
- uint globOneHighBitLen;
- uint globOneHighInvLow, globOneHighInvHigh;
- static void InitBigNum(uint[] n, uint val, uint len)
- {
- for (var i = 0; i < len; i++) n[i] = 0;
- n[0] = val;
- }
- static void MoveKeyToBig(uint[] n, byte[] key, uint klen, uint blen)
- {
- byte sign;
- if ((key[0] & 0x80) != 0) sign = 0xff;
- else sign = 0;
- unsafe
- {
- fixed (uint* tempPn = &n[0])
- {
- var pn = (byte*)tempPn;
- var i = blen * 4;
- for (; i > klen; i--) pn[i - 1] = sign;
- for (; i > 0; i--) pn[i - 1] = key[klen - i];
- }
- }
- }
- static void KeyToBigNum(uint[] n, byte[] key, uint len)
- {
- uint keylen;
- int i;
- var j = 0;
- if (key[j] != 2) return;
- j++;
- if ((key[j] & 0x80) != 0)
- {
- keylen = 0;
- for (i = 0; i < (key[j] & 0x7f); i++) keylen = (keylen << 8) | key[j + i + 1];
- j += (key[j] & 0x7f) + 1;
- }
- else
- {
- keylen = key[j];
- j++;
- }
- if (keylen <= len * 4)
- MoveKeyToBig(n, key.Skip(j).ToArray(), keylen, len);
- }
- static uint LenBigNum(uint[] n, uint len)
- {
- uint i;
- i = len - 1;
- while ((i >= 0) && (n[i] == 0)) i--;
- return i + 1;
- }
- static uint BitLenBigNum(uint[] n, uint len)
- {
- uint ddlen, bitlen, mask;
- ddlen = LenBigNum(n, len);
- if (ddlen == 0) return 0;
- bitlen = ddlen * 32;
- mask = 0x80000000;
- while ((mask & n[ddlen - 1]) == 0)
- {
- mask >>= 1;
- bitlen--;
- }
- return bitlen;
- }
- void InitPublicKey()
- {
- InitBigNum(pubkey.KeyTwo, 0x10001, 64);
- KeyToBigNum(pubkey.KeyOne, Convert.FromBase64String(PublicKeyString), 64);
- pubkey.Len = BitLenBigNum(pubkey.KeyOne, 64) - 1;
- }
- static int CompareBigNum(uint[] n1, uint[] n2, uint len)
- {
- while (len > 0)
- {
- --len;
- if (n1[len] < n2[len]) return -1;
- if (n1[len] > n2[len]) return 1;
- }
- return 0;
- }
- static void MoveBigNum(uint[] dest, uint[] src, uint len)
- {
- Array.Copy(src, dest, len);
- }
- static void ShrBigNum(uint[] n, int bits, int len)
- {
- int i; var i2 = bits / 32;
- if (i2 > 0)
- {
- for (i = 0; i < len - i2; i++) n[i] = n[i + i2];
- for (; i < len; i++) n[i] = 0;
- bits = bits % 32;
- }
- if (bits == 0) return;
- for (i = 0; i < len - 1; i++) n[i] = (n[i] >> bits) | (n[i + 1] << (32 - bits));
- n[i] = n[i] >> bits;
- }
- static void ShlBigNum(uint[] n, int bits, int len)
- {
- int i, i2;
- i2 = bits / 32;
- if (i2 > 0)
- {
- for (i = len - 1; i > i2; i--) n[i] = n[i - i2];
- for (; i > 0; i--) n[i] = 0;
- bits = bits % 32;
- }
- if (bits == 0) return;
- for (i = len - 1; i > 0; i--) n[i] = (n[i] << bits) | (n[i - 1] >> (32 - bits));
- n[0] <<= bits;
- }
- static uint SubBigNum(uint[] dest, uint[] src1, uint[] src2, uint carry, int len)
- {
- uint i1, i2;
- len += len;
- unsafe
- {
- fixed (uint* tempPs1 = &src1[0])
- fixed (uint* tempPs2 = &src2[0])
- fixed (uint* tempPd = &dest[0])
- {
- var ps1 = (ushort*)tempPs1;
- var ps2 = (ushort*)tempPs2;
- var pd = (ushort*)tempPd;
- while (--len != -1)
- {
- i1 = *ps1++;
- i2 = *ps2++;
- *pd++ = (ushort)(i1 - i2 - carry);
- if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0;
- }
- }
- }
- return carry;
- }
- static unsafe uint SubBigNum(uint* dest, uint* src1, uint* src2, uint carry, int len)
- {
- uint i1, i2;
- len += len;
- var ps1 = (ushort*)src1;
- var ps2 = (ushort*)src2;
- var pd = (ushort*)dest;
- while (--len != -1)
- {
- i1 = *ps1++;
- i2 = *ps2++;
- *pd++ = (ushort)(i1 - i2 - carry);
- if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0;
- }
- return carry;
- }
- static void InvertBigNum(uint[] n1, uint[] n2, uint len)
- {
- var nTmp = new uint[64];
- uint nTwoByteLen, bit;
- int nTwoBitLen;
- var j = 0;
- InitBigNum(nTmp, 0, len);
- InitBigNum(n1, 0, len);
- nTwoBitLen = (int)BitLenBigNum(n2, len);
- bit = ((uint)1) << (nTwoBitLen % 32);
- j = ((nTwoBitLen + 32) / 32) - 1;
- nTwoByteLen = (uint)((nTwoBitLen - 1) / 32) * 4;
- nTmp[nTwoByteLen / 4] |= ((uint)1) << ((nTwoBitLen - 1) & 0x1f);
- while (nTwoBitLen > 0)
- {
- nTwoBitLen--;
- ShlBigNum(nTmp, 1, (int)len);
- if (CompareBigNum(nTmp, n2, len) != -1)
- {
- SubBigNum(nTmp, nTmp, n2, 0, (int)len);
- n1[j] |= bit;
- }
- bit >>= 1;
- if (bit == 0)
- {
- j--;
- bit = 0x80000000;
- }
- }
- InitBigNum(nTmp, 0, len);
- }
- static void IncrementBigNum(uint[] n, uint len)
- {
- var i = 0;
- while ((++n[i] == 0) && (--len > 0)) i++;
- }
- void InitTwoDw(uint[] n, uint len)
- {
- MoveBigNum(globOne, n, len);
- globOneBitLen = BitLenBigNum(globOne, len);
- globOneLenXTwo = (globOneBitLen + 15) / 16;
- MoveBigNum(globOneHigh, globOne.Skip((int)LenBigNum(globOne, len) - 2).ToArray(), 2);
- globOneHighBitLen = BitLenBigNum(globOneHigh, 2) - 32;
- ShrBigNum(globOneHigh, (int)globOneHighBitLen, 2);
- InvertBigNum(globOneHighInv, globOneHigh, 2);
- ShrBigNum(globOneHighInv, 1, 2);
- globOneHighBitLen = (globOneHighBitLen + 15) % 16 + 1;
- IncrementBigNum(globOneHighInv, 2);
- if (BitLenBigNum(globOneHighInv, 2) > 32)
- {
- ShrBigNum(globOneHighInv, 1, 2);
- globOneHighBitLen--;
- }
- globOneHighInvLow = (ushort)globOneHighInv[0];
- globOneHighInvHigh = (ushort)(globOneHighInv[0] >> 16);
- }
- static unsafe void MulBignumWord(ushort* pn1, uint[] n2, uint mul, uint len)
- {
- uint i, tmp;
- unsafe
- {
- fixed (uint* tempPn2 = &n2[0])
- {
- var pn2 = (ushort*)tempPn2;
- tmp = 0;
- for (i = 0; i < len; i++)
- {
- tmp = mul * (*pn2) + (*pn1) + tmp;
- *pn1 = (ushort)tmp;
- pn1++;
- pn2++;
- tmp >>= 16;
- }
- *pn1 += (ushort)tmp;
- }
- }
- }
- static void MulBigNum(uint[] dest, uint[] src1, uint[] src2, uint len)
- {
- uint i;
- unsafe
- {
- fixed (uint* tempSrc2 = &src2[0])
- fixed (uint* tempPdest = &dest[0])
- {
- var psrc2 = (ushort*)tempSrc2;
- var pdest = (ushort*)tempPdest;
- InitBigNum(dest, 0, len * 2);
- for (i = 0; i < len * 2; i++)
- MulBignumWord(pdest++, src1, *psrc2++, len * 2);
- }
- }
- }
- static void NotBigNum(uint[] n, uint len)
- {
- uint i;
- for (i = 0; i < len; i++) n[i] = ~n[i];
- }
- static void NegBigNum(uint[] n, uint len)
- {
- NotBigNum(n, len);
- IncrementBigNum(n, len);
- }
- unsafe uint GetMulWord(uint* n)
- {
- var wn = (ushort*)n;
- var i = (uint)((((((((((*(wn - 1) ^ 0xffff) & 0xffff) * globOneHighInvLow + 0x10000) >> 1)
- + (((*(wn - 2) ^ 0xffff) * globOneHighInvHigh + globOneHighInvHigh) >> 1) + 1)
- >> 16) + ((((*(wn - 1) ^ 0xffff) & 0xffff) * globOneHighInvHigh) >> 1) +
- (((*wn ^ 0xffff) * globOneHighInvLow) >> 1) + 1) >> 14) + globOneHighInvHigh
- * (*wn ^ 0xffff) * 2) >> (int)globOneHighBitLen);
- if (i > 0xffff) i = 0xffff;
- return i & 0xffff;
- }
- static void DecBigNum(uint[] n, uint len)
- {
- var i = 0;
- while ((--n[i] == 0xffffffff) && (--len > 0))
- i++;
- }
- void CalcBigNum(uint[] n1, uint[] n2, uint[] n3, uint len)
- {
- uint globTwoXtwo, lenDiff;
- unsafe
- {
- fixed (uint* g1 = &globOne[0])
- fixed (uint* g2 = &globTwo[0])
- {
- MulBigNum(globTwo, n2, n3, len);
- globTwo[len * 2] = 0;
- globTwoXtwo = LenBigNum(globTwo, len * 2 + 1) * 2;
- if (globTwoXtwo >= globOneLenXTwo)
- {
- IncrementBigNum(globTwo, len * 2 + 1);
- NegBigNum(globTwo, len * 2 + 1);
- lenDiff = globTwoXtwo + 1 - globOneLenXTwo;
- var esi = ((ushort*)g2) + (1 + globTwoXtwo - globOneLenXTwo);
- var edi = ((ushort*)g2) + (globTwoXtwo + 1);
- for (; lenDiff != 0; lenDiff--)
- {
- edi--;
- var tmp = GetMulWord((uint*)edi);
- esi--;
- if (tmp > 0)
- {
- MulBignumWord(esi, globOne, tmp, 2 * len);
- if ((*edi & 0x8000) == 0)
- {
- if (0 != SubBigNum((uint*)esi, (uint*)esi, g1, 0, (int)len))
- (*edi)--;
- }
- }
- }
- NegBigNum(globTwo, len);
- DecBigNum(globTwo, len);
- }
- MoveBigNum(n1, globTwo, len);
- }
- }
- }
- void ClearTempVars(uint len)
- {
- InitBigNum(globOne, 0, len);
- InitBigNum(globTwo, 0, len);
- InitBigNum(globOneHighInv, 0, 4);
- InitBigNum(globOneHigh, 0, 4);
- globOneBitLen = 0;
- globOneHighBitLen = 0;
- globOneLenXTwo = 0;
- globOneHighInvLow = 0;
- globOneHighInvHigh = 0;
- }
- void CalcKey(uint[] n1, uint[] n2, uint[] n3, uint[] n4, uint len)
- {
- var n_tmp = new uint[64];
- uint n3_len, n4_len;
- int n3_bitlen;
- uint bit_mask;
- unsafe
- {
- fixed (uint* tempPn3 = &n3[0])
- {
- var pn3 = tempPn3;
- InitBigNum(n1, 1, len);
- n4_len = LenBigNum(n4, len);
- InitTwoDw(n4, n4_len);
- n3_bitlen = (int)BitLenBigNum(n3, n4_len);
- n3_len = (uint)((n3_bitlen + 31) / 32);
- bit_mask = (((uint)1) << ((n3_bitlen - 1) % 32)) >> 1;
- pn3 += n3_len - 1;
- n3_bitlen--;
- MoveBigNum(n1, n2, n4_len);
- while (--n3_bitlen != -1)
- {
- if (bit_mask == 0)
- {
- bit_mask = 0x80000000;
- pn3--;
- }
- CalcBigNum(n_tmp, n1, n1, n4_len);
- if ((*pn3 & bit_mask) != 0)
- CalcBigNum(n1, n_tmp, n2, n4_len);
- else
- MoveBigNum(n1, n_tmp, n4_len);
- bit_mask >>= 1;
- }
- InitBigNum(n_tmp, 0, n4_len);
- ClearTempVars(len);
- }
- }
- }
- byte[] ProcessPredata(byte[] src)
- {
- var dest = new byte[256];
- var n2 = new uint[64];
- var n3 = new uint[64];
- var a = (int)((pubkey.Len - 1) / 8);
- var pre_len = (55 / a + 1) * (a + 1);
- var srcOffset = 0;
- var destOffset = 0;
- while (a + 1 <= pre_len)
- {
- InitBigNum(n2, 0, 64);
- Buffer.BlockCopy(src, srcOffset, n2, 0, a + 1);
- CalcKey(n3, n2, pubkey.KeyTwo, pubkey.KeyOne, 64);
- Buffer.BlockCopy(n3, 0, dest, destOffset, a);
- pre_len -= a + 1;
- srcOffset += a + 1;
- destOffset += a;
- }
- return dest;
- }
- public byte[] DecryptKey(byte[] src)
- {
- InitPublicKey();
- return ProcessPredata(src).Take(56).ToArray();
- }
- }
- }