MIX Format (Westwood)
Westwood's MIX Format is a simple group file used in their games from 1995-2001. It only stores file name hashes so some file names will result in the same hash and as a result will not be able to be stored together if they differ in content. Position and size of files are stored so size does not need to be inferred. It does not support compression. There are 2 versions of the header, basic and advanced. The basic one only stores the file count and the total data size (not including the header or file index). The advanced one supports additional optional features such as encryption of the header and index and a sha1 checksum tailer to verify the data integrity. An additional flag field is used to indicate which features are present. The hash algorithm used for the file name is a rolling hash in Command & Conquer and Red Alert and was replaced with crc32 in Tiberian Sun and later. There is nothing to indicate which hash scheme is used. Other games may use other hash methods.
Apart from the original Command & Conquer, all the games can read both types of header provided the hash format is correct for that game.
MIX files have no signature. Usually they will have the extension .mix
The header consists of an optional flags section 4 bytes in size. The first 2 bytes are 0 in this case to distinguish between a mix without feature flags where this stores the file count as UNIT16LE. The flags are stored in the 3rd byte as a bit field with bit 0 indicating a checksum is present and bit 1 indicating that the header is encrypted.
If the flags indicate encryption, an 80 byte block follows the flag section. This block is encrypted with an RSA private key with the public key used to decrypt being embedded in the games code. This block decrypts to a 56 byte Blowfish key that is used to decrypt the rest of the header.
The standard header follows with a file count and a size which is the size of the data only. C&C games use this when caching a mix file. XCC uses this to validate the format and can be abused by making it larger to prevent XCC reading it correctly at the cost of the games reading additional garbage when caching them. This is used in so called "protection" schemes some mods use to prevent others using their assets.
|UINT32LE||Flags||An optional field that specifies additional optional features that the archive uses.|
|BYTE||Key||An optional 80 byte block containing an RSA encrypted Blowfish key to use to decode the rest of the header.|
|UINT16LE||FileCount||The number of files in the archive. Can be used to calculate the size of the file entry index.|
|UINT32LE||DataSize||Size of the data section.|
The indexes file entries contain a hash of the filename, the offset of the file within the data section (header size needs to be added for absolute position in the archive) and the size of the file in bytes.
|INT32LE||Id||Hash of the filename. Hash algorithm varies between games.|
|UINT32LE||Offset||File's starting offset within the data section.|
In order to quickly locate files from their file name hashes, the index is sorted according to the hashes taken as signed integers.
Header encryption can be detected by checking Flags & 0x00020000 does not equal zero. If it doesn't, then the next 80 bytes are two RSA encrypted blocks that need to be decrypted with the Westwood public key. For the purposes of the RSA algorithm, the blocks should be treated as 2 40 byte "big" integers in little endian byte order. 0x10001 should be used as the public exponent for the decryption.
The result is a 56 byte block padded with zeros to use with the Blowfish algorithm in ECB mode. Blocks are 8 bytes long and you need to decode the first block to get the standard header. From that you can calculate the length of the index and thus how many additional blocks you need to decode to get the rest of the index. If the header and index together are not perfectly divisible by 8, then it is padded with zeros since blowfish operates on 8 byte blocks.
Creating an encrypted header is the reverse of this process, a Blowfish key is generated somehow and used to encrypt the header and index and is itself padded with zeros and encrypted using the Westwood private key.
The public key is encoded in the game binaries while the private key was leaked in the form of keys.ini included in one of the Tiberian Sun MIX files. Presumably this was a mistake as it cannot be used from that location. The full contents of the file are as follows.
[PublicKey] 1=AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V [PrivateKey] 1=AigKVje8mROcR8QixnxUEF5b29Curkq01DNDWCdOG99XBqH79OaCiTCB
The keys are Base64 encoded and DER encoded big endian "big" integers and represent the modulus and the private exponent respectively in the RSA encryption scheme.
Data checksum presence can be detected by checking Flags & 0x00010000 does not equal zero. If it doesn't, then the last 20 bytes of the file are a SHA1 hash of the data contents of the file, not including the header.
The following tools are able to work with files in this format.
|Name||Platform||Extract files?||Decompress on extract?||Create new?||Modify?||Compress on insert?||Access hidden data?||Edit metadata?||Notes|
|OpenRA Utility||Windows, Linux, Mac||Yes||N/A||No||No||N/A||No||N/A|