Beispiel #1
0
        void DecryptIndexStage1(byte[] data, uint key, CmvsScheme scheme)
        {
            var secret        = scheme.Cpz5Secret;
            var secret_key    = new uint[24];
            int secret_length = Math.Min(24, secret.Length);

            for (int i = 0; i < secret_length; ++i)
            {
                secret_key[i] = secret[i] - key;
            }

            int shift = (int)(((key >> 24) ^ (key >> 16) ^ (key >> 8) ^ key ^ 0xB) & 0xF) + 7;

            unsafe
            {
                fixed(byte *raw = data)
                {
                    uint *data32 = (uint *)raw;
                    int   i      = 5;

                    for (int n = data.Length / 4; n > 0; --n)
                    {
                        *data32 = Binary.RotR((secret_key[i] ^ *data32) + scheme.IndexAddend, shift) + 0x01010101;
                        ++data32;
                        i = (i + 1) % 24;
                    }
                    byte *data8 = (byte *)data32;

                    for (int n = data.Length & 3; n > 0; --n)
                    {
                        *data8 = (byte)((*data8 ^ (secret_key[i] >> (n * 4))) - scheme.IndexSubtrahend);
                        ++data8;
                        i = (i + 1) % 24;
                    }
                }
            }
        }
Beispiel #2
0
 public Cpz5Decoder(CmvsScheme scheme, uint key, uint summand)
 {
     m_scheme = scheme;
     Init(key, summand);
 }
Beispiel #3
0
 public Cpz5Decoder(CmvsScheme scheme, uint key, uint summand)
 {
     m_scheme = scheme;
     Init (key, summand);
 }
Beispiel #4
0
        ArcFile ReadIndex(ArcView file, CmvsScheme scheme, CpzHeader cpz, byte[] index)
        {
            var cmvs_md5 = Cmvs.MD5.Create(scheme.Md5Variant);

            cmvs_md5.Compute(cpz.CmvsMd5);

            DecryptIndexStage1(index, cpz.MasterKey ^ 0x3795B39A, scheme);

            var decoder = new Cpz5Decoder(scheme, cpz.MasterKey, cpz.CmvsMd5[1]);

            decoder.Decode(index, 0, cpz.DirEntriesSize, 0x3A);

            var key = new uint[4];

            key[0] = cpz.CmvsMd5[0] ^ (cpz.MasterKey + 0x76A3BF29);
            key[1] = cpz.CmvsMd5[1] ^ cpz.MasterKey;
            key[2] = cpz.CmvsMd5[2] ^ (cpz.MasterKey + 0x10000000);
            key[3] = cpz.CmvsMd5[3] ^ cpz.MasterKey;

            DecryptIndexDirectory(index, cpz.DirEntriesSize, key);

            decoder.Init(cpz.MasterKey, cpz.CmvsMd5[2]);
            int base_offset = 0x40 + index.Length;
            int dir_offset  = 0;
            var dir         = new List <Entry>();

            for (int i = 0; i < cpz.DirCount; ++i)
            {
                int dir_size = LittleEndian.ToInt32(index, dir_offset);
                if (dir_size <= 0x10 || dir_size > index.Length)
                {
                    return(null);
                }
                int file_count = LittleEndian.ToInt32(index, dir_offset + 4);
                if (file_count >= 0x10000)
                {
                    return(null);
                }
                int  entries_offset = LittleEndian.ToInt32(index, dir_offset + 8);
                uint dir_key        = LittleEndian.ToUInt32(index, dir_offset + 0xC);
                var  dir_name       = Binary.GetCString(index, dir_offset + 0x10, dir_size - 0x10);

                int next_entries_offset;
                if (i + 1 == cpz.DirCount)
                {
                    next_entries_offset = cpz.FileEntriesSize;
                }
                else
                {
                    next_entries_offset = LittleEndian.ToInt32(index, dir_offset + dir_size + 8);
                }

                int cur_entries_size = next_entries_offset - entries_offset;
                if (cur_entries_size <= 0)
                {
                    return(null);
                }

                int cur_offset      = cpz.DirEntriesSize + entries_offset;
                int cur_entries_end = cur_offset + cur_entries_size;
                decoder.Decode(index, cur_offset, cur_entries_size, 0x7E);

                for (int j = 0; j < 4; ++j)
                {
                    key[j] = cpz.CmvsMd5[j] ^ (dir_key + scheme.DirKeyAddend[j]);
                }

                DecryptIndexEntry(index, cur_offset, cur_entries_size, key, scheme.IndexSeed);
                bool is_root_dir = dir_name == "root";

                dir.Capacity = dir.Count + file_count;
                for (int j = 0; j < file_count; ++j)
                {
                    int entry_size = LittleEndian.ToInt32(index, cur_offset);
                    if (entry_size > index.Length || entry_size <= 0x18)
                    {
                        return(null);
                    }
                    var name = Binary.GetCString(index, cur_offset + 0x18, cur_entries_end - (cur_offset + 0x18));
                    if (!is_root_dir)
                    {
                        name = Path.Combine(dir_name, name);
                    }
                    var entry = FormatCatalog.Instance.Create <CpzEntry> (name);
                    entry.Offset   = LittleEndian.ToInt64(index, cur_offset + 4) + base_offset;
                    entry.Size     = LittleEndian.ToUInt32(index, cur_offset + 0xC);
                    entry.CheckSum = LittleEndian.ToUInt32(index, cur_offset + 0x10);
                    entry.Key      = LittleEndian.ToUInt32(index, cur_offset + 0x14) + dir_key;
                    if (!entry.CheckPlacement(file.MaxOffset))
                    {
                        return(null);
                    }
                    dir.Add(entry);
                    cur_offset += entry_size;
                }
                dir_offset += dir_size;
            }
            if (cpz.IsEncrypted)
            {
                decoder.Init(cpz.CmvsMd5[3], cpz.MasterKey);
            }
            return(new CpzArchive(file, this, dir, cpz, decoder));
        }
Beispiel #5
0
        ArcFile ReadIndex(ArcView file, CmvsScheme scheme, CpzHeader cpz, byte[] index)
        {
            var cmvs_md5 = Cmvs.MD5.Create (scheme.Md5Variant);
            cmvs_md5.Compute (cpz.CmvsMd5);

            DecryptIndexStage1 (index, cpz.MasterKey ^ 0x3795B39A, scheme.Cpz5Secret);

            var decoder = new Cpz5Decoder (scheme, cpz.MasterKey, cpz.CmvsMd5[1]);
            decoder.Decode (index, 0, cpz.DirEntriesSize, 0x3A);

            var key = new uint[4];
            key[0] = cpz.CmvsMd5[0] ^ (cpz.MasterKey + 0x76A3BF29);
            key[1] = cpz.CmvsMd5[1] ^  cpz.MasterKey;
            key[2] = cpz.CmvsMd5[2] ^ (cpz.MasterKey + 0x10000000);
            key[3] = cpz.CmvsMd5[3] ^  cpz.MasterKey;

            DecryptIndexDirectory (index, cpz.DirEntriesSize, key);

            decoder.Init (cpz.MasterKey, cpz.CmvsMd5[2]);
            int base_offset = 0x40 + index.Length;
            int dir_offset = 0;
            var dir = new List<Entry>();
            for (int i = 0; i < cpz.DirCount; ++i)
            {
                int dir_size = LittleEndian.ToInt32 (index, dir_offset);
                if (dir_size <= 0x10 || dir_size > index.Length)
                    return null;
                int  file_count     = LittleEndian.ToInt32 (index, dir_offset+4);
                if (file_count >= 0x10000)
                    return null;
                int  entries_offset = LittleEndian.ToInt32 (index, dir_offset+8);
                uint dir_key        = LittleEndian.ToUInt32 (index, dir_offset+0xC);
                var  dir_name       = Binary.GetCString (index, dir_offset+0x10, dir_size-0x10);

                int next_entries_offset;
                if (i + 1 == cpz.DirCount)
                    next_entries_offset = cpz.FileEntriesSize;
                else
                    next_entries_offset = LittleEndian.ToInt32 (index, dir_offset + dir_size + 8);

                int cur_entries_size = next_entries_offset - entries_offset;
                if (cur_entries_size <= 0)
                    return null;

                int cur_offset = cpz.DirEntriesSize + entries_offset;
                int cur_entries_end = cur_offset + cur_entries_size;
                decoder.Decode (index, cur_offset, cur_entries_size, 0x7E);

                key[0] = cpz.CmvsMd5[0] ^ dir_key;
                key[1] = cpz.CmvsMd5[1] ^ (dir_key + 0x112233);
                key[2] = cpz.CmvsMd5[2] ^ dir_key;
                key[3] = cpz.CmvsMd5[3] ^ (dir_key + 0x34258765);

                DecryptIndexEntry (index, cur_offset, cur_entries_size, key);
                bool is_root_dir = dir_name == "root";

                dir.Capacity = dir.Count + file_count;
                for (int j = 0; j < file_count; ++j)
                {
                    int entry_size = LittleEndian.ToInt32 (index, cur_offset);
                    if (entry_size > index.Length || entry_size <= 0x18)
                        return null;
                    var name = Binary.GetCString (index, cur_offset+0x18, cur_entries_end-(cur_offset+0x18));
                    if (!is_root_dir)
                        name = Path.Combine (dir_name, name);
                    var entry = FormatCatalog.Instance.Create<CpzEntry> (name);
                    entry.Offset    = LittleEndian.ToInt64 (index, cur_offset+4) + base_offset;
                    entry.Size      = LittleEndian.ToUInt32 (index, cur_offset+0xC);
                    entry.CheckSum  = LittleEndian.ToUInt32 (index, cur_offset+0x10);
                    entry.Key       = LittleEndian.ToUInt32 (index, cur_offset+0x14);
                    entry.DirKey    = dir_key;
                    if (!entry.CheckPlacement (file.MaxOffset))
                        return null;
                    dir.Add (entry);
                    cur_offset += entry_size;
                }
                dir_offset += dir_size;
            }
            if (cpz.IsEncrypted)
                decoder.Init (cpz.CmvsMd5[3], cpz.MasterKey);
            return new CpzArchive (file, this, dir, cpz, decoder);
        }