Пример #1
0
/**
 * Decodes RA/TS Style MIX headers. Assumes you have already checked if
 *  header is encrypted and that mix is seeked to the start of the WSKey
 *
 * @param mix pointer to vfile for the mixfile
 * @param header pointer to header object that will store the mix's header
 * @param tscheck if equal to check_ts, will check if mix is from Tiberian Sun.
 * @return pointer to MixRecord
 */
MixRecord* MIXFiles::decodeHeader(VFile* mix, MixHeader* header, tscheck_ tscheck)
{
    Uint8 WSKey[80];        // 80-byte Westwood key
    Uint8 BFKey[56];        // 56-byte blow fish key
    Uint8 Block[8];         // 8-byte block to store blowfish stuff in
    Cblowfish bf;
    Uint8 *e;
    MixRecord* mindex;
    //bool aligned = true;

    mix->readByte(WSKey, 80);
    get_blowfish_key((const Uint8 *)&WSKey, (Uint8 *)&BFKey);
    bf.set_key((const Uint8 *)&BFKey, 56);
    mix->readByte(Block, 8);

    bf.decipher(&Block, &Block, 8);

    // Extract the header from Block
    memcpy(&header->c_files, &Block[0], sizeof(Uint16));
    memcpy(&header->size, &Block[sizeof(Uint16)], sizeof(Uint32));
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    header->c_files = SDL_Swap16(header->c_files);
    header->size = SDL_Swap32(header->size);
#endif

    // Decrypt all indexes
    const int m_size = sizeof(MixRecord) * header->c_files;
    const int m_f = (m_size + 5) & ~7;
    mindex = new MixRecord[header->c_files];
    e = new Uint8[m_f];
    //fread(e, m_f, 1, mix);
    mix->readByte(e, m_f);
    memcpy(mindex, &Block[6], 2);
    bf.decipher(e, e, m_f);

    memcpy(reinterpret_cast<Uint8 *>(mindex) + 2, e, m_size - 2);
    delete[] e;

    for (int i = 0; i < header->c_files; i++) {
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
        mindex[i].id = SDL_Swap32(mindex[i].id);
        mindex[i].offset = SDL_Swap32(mindex[i].offset);
        mindex[i].size = SDL_Swap32(mindex[i].size);
#endif
#if 0
        if (check_ts == tscheck) {
            if (mindex[i].offset & 0xf)
                aligned = false;
            if (mindex[i].id == TS_ID)
                game = game_ts;
        }
#endif
        /* 92 = 4 byte flag + 6 byte header + 80 byte key + 2 bytes (?) */
        mindex[i].offset += 92 + m_f; /* re-center offset to be absolute offset */
    }
    /*
     if (aligned) game = game_ts;
    */
    return mindex;
}
Пример #2
0
bool MixHeader::readEncrypted(std::fstream& fh)
{
    t_mix_entry entry;
    std::pair<t_mix_index_iter,bool> rv;

    Cblowfish blfish;
    int block_count;
    char pblkbuf[8];

    //header is at least 84 bytes long at this point due to key source
    m_header_size = 84;

    //read keysource to obtain blowfish key
    //fh.seekg(4, std::ios::beg);
    readKeySource(fh);
    blfish.set_key(reinterpret_cast<uint8_t*>(m_key), 56);

    //read first block to get file count, needed to calculate header size
    fh.read(pblkbuf, 8);
    blfish.decipher(reinterpret_cast<void*>(pblkbuf),
                    reinterpret_cast<void*>(pblkbuf), 8);
    memcpy(reinterpret_cast<char*>(&m_file_count), pblkbuf, 2);
    memcpy(reinterpret_cast<char*>(&m_body_size), pblkbuf + 2 , 4);

    //workout size of our header and how much we need to decrypt
    //take into account 2 bytes left from getting the file count
    block_count = ((m_file_count * 12) - 2) / 8;
    if (((m_file_count * 12) - 2) % 8) block_count++;
    //add 8 to compensate for block we already decrypted
    m_header_size += block_count * 8 + 8;

    //prepare our buffer and copy in first 2 bytes we got from first block
    //index_buffer.resize(block_count * 8 + 2);
    char pindbuf[block_count * 8 + 2];
    memcpy(pindbuf, pblkbuf + 6 , 2);

    //loop to decrypt index into index buffer
    for(int i = 0; i < block_count; i++) {
        fh.read(pblkbuf, 8);
        blfish.decipher(reinterpret_cast<void*>(pblkbuf),
                        reinterpret_cast<void*>(pblkbuf), 8);
        memcpy(pindbuf + 2 + 8 * i, pblkbuf, 8);
    }

    //read entries
    for (uint16_t i = 0; i < m_file_count; i++) {
        memcpy(reinterpret_cast<char*>(&entry.first), pindbuf + i * 12,
               sizeof(int32_t));
        memcpy(reinterpret_cast<char*>(&entry.second), pindbuf + 4 + i * 12,
               sizeof(t_index_info));
        rv = m_index.insert(entry);
        if(!rv.second) {
            std::cout << "Error reading header, duplicate ID" << std::endl;
            return false;
        }
    }

    return true;
}
Пример #3
0
bool MixHeader::writeEncrypted(std::fstream& fh)
{
    Cblowfish blfish;
    //std::vector<char> block_buff(8);
    //std::vector<char> index_buffer(8);
    int block_count;
    int offset = 0;
    //char* pindbuf = &index_buffer[0];
    //char* pblkbuf = &block_buff[0];
    char pblkbuf[8];

    //always write flags if encrypted.
    fh.write(reinterpret_cast<char*>(&m_header_flags), 4);
    //encrypted file needs its key_source
    fh.write(m_keysource, 80);

    //work out how much data needs encrypting, set vector size
    block_count = ((m_file_count * 12) + 6) / 8;
    if(((m_file_count * 12) + 6) % 8) block_count++;
    //index_buffer.resize(block_count * 8);
    char pindbuf[block_count * 8];

    //fill the buffer
    memcpy(pindbuf + offset, reinterpret_cast<char*>(&m_file_count), 2);
    offset += 2;
    memcpy(pindbuf + offset, reinterpret_cast<char*>(&m_body_size), 4);
    offset += 4;

    for(t_mix_index_iter it = m_index.begin(); it != m_index.end(); ++it) {
        memcpy(pindbuf + offset, reinterpret_cast<const char*>(&(it->first)), 4);
        offset += 4;
        memcpy(pindbuf + offset, reinterpret_cast<const char*>(&(it->second)), 8);
        offset += 8;
    }

    //prepare blowfish
    blfish.set_key(reinterpret_cast<const uint8_t*>(m_key), 56);

    //encrypt and write to file.
    offset = 0;
    while(block_count--) {
        memcpy(pblkbuf, pindbuf + offset, 8);
        blfish.encipher(pblkbuf, pblkbuf, 8);
        fh.write(pblkbuf, 8);
        offset += 8;
    }

    return true;
}