It totally depends on what you mean by "message." If you can add four bytes of delirium to one of the messages. (That is, four bytes that do not make sense in the context of the message.) Then it becomes trivial in the truest sense of the word.
Thinking in terms of bits moving through a CRC32 state machine.
CRC32 is based on the Galois feedback shift register, each bit in its state will be replaced with 32 bits from the payload data. When each bit is entered, the positions indicated by the polynomial will be excluded with the sequence observed from the end of the shift register. This sequence is not affected by the input until the shift register is full.
As an example, imagine that we have a shift register filled with the initial state 10101110, polynomial 10000011 and filling with unknown bits of X.
Polynomial * ** |feedback (End of SR.) State 10101110 0 State X1010111 1 State XX101000 0 State XXX10100 0 State XXXX1010 0 State XXXXX101 1 State XXXXXX01 1 State XXXXXXX1 1 State XXXXXXXX 0
Feedback is not in terms of X until the SR is filled out! Thus, in order to generate a message with a predetermined checksum, you take a new message, generate its CRC and process its next 32 feedback bits. You can do this in 32 steps of the CRC function. Then you need to calculate the effect of this feedback on the contents of the shift register.
To do this, you need to add four zero bytes to the message, and then look at the checksum. (The checksum is the SR state at the end, which, if padded with four zero bytes, is the effect of feedback and empty bytes.)
An exceptional OR that affects the desired checksum value, replace the four-byte trailer with this calculated value and restore the checksum. You can do this with any program that generates CRC32, a hex editor and a calculator that can handle hexadecimal values.
If you want to generate two messages that make full sense and do not contain trailing garbage, things get a little more complicated. Determine the number of sections that you can write plausible alternatives with the same length.
Using English prose as an example. “I think it might work” and “I believe in such an approach” have the same meaning and the same length in general.
Defining enough examples in your message is a tricky bit (unless you want to spoof spaces!) CRC 32 is linear if the data has the correct offset in the message. So CRC ([messagea] [padding]) ^ CRC ([padding] [messageb]) = CRC ([messagea] [messageb]) There are a few caveats with word alignment that you need to deal with as a general hint. You want to expand excerpts on the "fixed" parts of the message. Typically, you want to have alternatives for n * 1.5 passages, where n is the size of the CRC.
Now you can calculate the CRC that has the skeletal message, the impression that each alternate passage will have, and then compile a table comparing the effect that each alternative will have for each passage. Then you need to choose alternatives that will change the CRC of the skeleton to match the CRC that you want. This problem is actually quite funny to solve. First of all, find any alternatives that unambiguously change a little, if this bit needs to be changed for your CRC, select this alternative and add its effect to the CRC, and then go around again. This should reduce the space of the solution you need to look for.
This is a pretty difficult task to encode, but it will lead to collisions in a very short amount of time.