Пример #1
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            uint arc_key = ArcKey;

            ulong hash = 0xA73C5F9DA73C5F9Dul;
            ulong xor  = ((uint)length + arc_key) ^ 0xFEC9753Eu;

            xor |= xor << 32;
            unsafe
            {
                fixed(byte *raw = data)
                {
                    ulong *encoded = (ulong *)(raw + offset);

                    for (int i = 0; i < length / 8; ++i)
                    {
                        hash = MMX.PAddD(hash, 0xCE24F523CE24F523ul) ^ xor;
                        xor  = *encoded ^ hash;
                        *encoded++ = xor;
                    }
                }
            }
        }
Пример #2
0
        public override uint CalculateHash(byte[] data, int length)
        {
            if (length > data.Length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            unsafe
            {
                fixed(byte *data8 = data)
                {
                    ulong  hash   = 0;
                    ulong  key    = 0;
                    ulong *data64 = (ulong *)data8;

                    for (int i = length / 8; i > 0; --i)
                    {
                        hash = MMX.PAddW(hash, 0xA35793A7A35793A7ul);
                        key  = MMX.PAddW(key, *data64++ ^ hash);
                        key  = MMX.PSllD(key, 3) | MMX.PSrlD(key, 29);
                    }
                    // MMX.PMAddWD (key, key >> 32);
                    return((uint)((short)key * (short)(key >> 32) + (short)(key >> 16) * (short)(key >> 48)));
                }
            }
        }
Пример #3
0
        unsafe void DecryptV1(byte *data, int length, QlieEntry entry)
        {
            var  file_name = entry.Name;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);
            var    table        = GenerateTable(0x20, seed); // originally 0x2C, 12 dwords not used
            ulong *data64       = (ulong *)data;
            int    qword_length = length / 8;
            uint   k            = 2 * (table[0xD] & 0xF);
            ulong  hash64       = table[6] | (ulong)table[7] << 32;

            for (int i = 0; i < qword_length; ++i)
            {
                ulong t = table[k] | (ulong)table[k + 1] << 32;
                hash64 = MMX.PAddD(hash64 ^ t, t);

                ulong d = data64[i] ^ hash64;
                data64[i] = d;

                hash64 = MMX.PAddB(hash64, d) ^ d;
                hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                k = (k + 2) & 0x1F;
            }
        }
Пример #4
0
        public void Decrypt(uint hash, byte[] buf, int offset, int length)
        {
            if (offset < 0 || offset > buf.Length)
            {
                throw new ArgumentException("offset");
            }
            int count = Math.Min(length, buf.Length - offset) / 8;

            if (0 == count)
            {
                return;
            }
            ulong key = KeyFromHash(hash);

            unsafe
            {
                fixed(byte *data = buf)
                {
                    ulong *first = (ulong *)(data + offset);
                    ulong *last  = first + count;

                    while (first != last)
                    {
                        ulong v = *first ^ key;
                        key = MMX.PAddW(key, v);
                        *first++ = v;
                    }
                }
            }
        }
Пример #5
0
        private void Decrypt(byte[] buffer, int offset, int length, uint key)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > buffer.Length || offset > buffer.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            ulong hash = 0xA73C5F9DA73C5F9Dul;
            ulong xor  = ((uint)length + key) ^ 0xFEC9753Eu;

            xor |= xor << 32;
            unsafe
            {
                fixed(byte *raw = buffer)
                {
                    ulong *encoded = (ulong *)(raw + offset);

                    for (int i = 0; i < length / 8; ++i)
                    {
                        hash = MMX.PAddD(hash, 0xCE24F523CE24F523ul) ^ xor;
                        xor  = *encoded ^ hash;
                        *encoded++ = xor;
                    }
                }
            }
        }
Пример #6
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            if (length < 8)
            {
                return;
            }

            var  file_name = entry.Name;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);
            var table = GenerateTable(0x20, seed);  // originally 0x2C, 12 dwords not used

            unsafe
            {
                fixed(byte *raw_data = &data[offset])
                {
                    ulong *data64       = (ulong *)raw_data;
                    int    qword_length = length / 8;
                    uint   k            = 2 * (table[0xD] & 0xF);
                    ulong  hash64       = table[6] | (ulong)table[7] << 32;

                    for (int i = 0; i < qword_length; ++i)
                    {
                        ulong t = table[k] | (ulong)table[k + 1] << 32;
                        hash64 = MMX.PAddD(hash64 ^ t, t);

                        ulong d = data64[i] ^ hash64;
                        data64[i] = d;

                        hash64 = MMX.PAddB(hash64, d) ^ d;
                        hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                        k = (k + 2) & 0x1F;
                    }
                }
            }
        }
Пример #7
0
        uint GenerateKey(byte[] key_data)
        {
            ulong hash = 0;
            ulong key  = 0;

            unsafe
            {
                fixed(byte *data = key_data)
                {
                    ulong *data64 = (ulong *)data;

                    for (int i = key_data.Length / 8; i > 0; --i)
                    {
                        hash = MMX.PAddW(hash, 0x0307030703070307);
                        key  = MMX.PAddW(key, *data64++ ^ hash);
                    }
                }
            }
            return((uint)(key ^ (key >> 32)));
        }
Пример #8
0
        unsafe void DecryptV2(byte *data, int length, QlieEntry entry)
        {
            var  file_name = entry.Name;
            uint hash      = 0x86F7E2;
            uint seed      = 0x4437F1;

            for (int i = 0; i < file_name.Length; i++)
            {
                hash += (uint)(file_name[i] << (i & 7));
                seed ^= hash;
            }

            seed += ArcKey ^ (13 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x56E213u));
            seed = 13 * (seed & 0xFFFFFF);
            var table    = GenerateTable(0x20, seed, 0x8A77F473u); // originally 0x40
            var key_data = GenerateKeyData(entry.KeyFile);

            ulong *data64       = (ulong *)data;
            int    qword_length = length / 8;
            int    k            = (8 * ((int)table[8] & 0xD)) & 0x7F;
            ulong  hash64       = table[6] | (ulong)table[7] << 32;

            for (int i = 0; i < qword_length; ++i)
            {
                int   t_index = 2 * (k & 0xF);
                ulong t       = table[t_index] | (ulong)table[t_index + 1] << 32;
                t     ^= LittleEndian.ToUInt64(key_data, 8 * k);
                hash64 = MMX.PAddD(hash64 ^ t, t);

                ulong d = data64[i] ^ hash64;
                data64[i] = d;

                hash64 = MMX.PAddB(hash64, d) ^ d;
                hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                k = (k + 1) & 0x7F;
            }
        }
Пример #9
0
        public override uint CalculateHash(byte[] data, int length)
        {
            if (length > data.Length)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            unsafe
            {
                fixed(byte *data8 = data)
                {
                    ulong  hash   = 0;
                    ulong  key    = 0;
                    ulong *data64 = (ulong *)data8;

                    for (int i = length / 8; i > 0; --i)
                    {
                        hash = MMX.PAddW(hash, 0x0307030703070307);
                        key  = MMX.PAddW(key, *data64++ ^ hash);
                    }
                    return((uint)(key ^ (key >> 32)));
                }
            }
        }
Пример #10
0
        public override void DecryptEntry(byte[] data, int offset, int length, QlieEntry entry)
        {
            var key_file = entry.KeyFile;

            if (null == key_file)
            {
                base.DecryptEntry(data, offset, length, entry);
                return;
            }
            // play it safe with 'unsafe' sections
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length > data.Length || offset > data.Length - length)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            if (length < 8)
            {
                return;
            }

            var  file_name = entry.RawName;
            uint hash      = 0x85F532;
            uint seed      = 0x33F641;

            for (uint i = 0; i < file_name.Length; i++)
            {
                hash += (i & 0xFF) * file_name[i];
                seed ^= hash;
            }

            seed += ArcKey ^ (7 * ((uint)length & 0xFFFFFF) + (uint)length
                              + hash + (hash ^ (uint)length ^ 0x8F32DCu));
            seed = 9 * (seed & 0xFFFFFF);

            if (GameKeyData != null)
            {
                seed ^= 0x453A;
            }

            var mt = new QlieMersenneTwister(seed);

            if (key_file != null)
            {
                mt.XorState(key_file);
            }
            if (GameKeyData != null)
            {
                mt.XorState(GameKeyData);
            }

            // game code fills dword[41] table, but only the first 16 qwords are used
            ulong[] table = new ulong[16];
            for (int i = 0; i < table.Length; ++i)
            {
                table[i] = mt.Rand64();
            }

            // compensate for 9 discarded dwords
            for (int i = 0; i < 9; ++i)
            {
                mt.Rand();
            }

            ulong hash64 = mt.Rand64();
            uint  t      = mt.Rand() & 0xF;

            unsafe
            {
                fixed(byte *raw_data = &data[offset])
                {
                    ulong *data64       = (ulong *)raw_data;
                    int    qword_length = length / 8;

                    for (int i = 0; i < qword_length; ++i)
                    {
                        hash64 = MMX.PAddD(hash64 ^ table[t], table[t]);

                        ulong d = data64[i] ^ hash64;
                        data64[i] = d;

                        hash64 = MMX.PAddB(hash64, d) ^ d;
                        hash64 = MMX.PAddW(MMX.PSllD(hash64, 1), d);

                        t++;
                        t &= 0xF;
                    }
                }
            }
        }
Пример #11
0
 void psubd(int i)
 {
     mm[0] = MMX.PSubD(mm[0], mm[i]);
 }
Пример #12
0
 void psubw(int i)
 {
     mm[0] = MMX.PSubW(mm[0], mm[i]);
 }
Пример #13
0
 void psubb(int i)
 {
     mm[0] = MMX.PSubB(mm[0], mm[i]);
 }
Пример #14
0
 void paddd(int i)
 {
     mm[0] = MMX.PAddD(mm[0], mm[i]);
 }
Пример #15
0
 void paddw(int i)
 {
     mm[0] = MMX.PAddW(mm[0], mm[i]);
 }
Пример #16
0
 void paddb(int i)
 {
     mm[0] = MMX.PAddB(mm[0], mm[i]);
 }