Actually you can recover the xor keys with a little bit more then 512+513 = 1025 (+ some extra) bytes of continuous plain text at a random location in the file.

For fun and games let us assume that the plain text we know are all 0x00 (there's a couple of 7 and 10kb blobs of those in the 500d firmware, perfect!)

now to explain how this works, lets scale it down and assume a keysize of 3 for key1 and a keysize of 4 for key2 and data bits between 0 and 3 (keeps brains from exploding)

The cypher stream is 1 1 3 2 3 3 3 0 1 3 1 2

lets map this out in a neat little table mapped to the position in the xor tables key2 vertiaclly key1 horizontaly . is for cypher bits, ? for key bits,

the first byte uses 1,1 as key indexes, second 2,2 etc etc etc

`1 . . ? `

. . . ?

. . . ?

. . . ?

? ? ?

1 . . ?

. 1 . ?

. . . ?

. . . ?

? ? ?

1 . . ?

. 1 . ?

. . 3 ?

. . . ?

? ? ?

1 . . ?

. 1 . ?

. . 3 ?

2 . . ?

? ? ?

1 3 . ?

. 1 3 ?

. . 3 ?

2 . . ?

? ? ? etc etc

and we end up with (I went though enough data to fill the table, but you need a minimum of 2 numbers in every row/column)

`1 3 1 ?`

3 1 3 ?

3 1 3 ?

2 0 2 ?

? ? ?

So lets figure this thing out, lets start in the upper left, assuming all plain text is 0, we get 0 ^ some number ^ some other number is 1,

lots of options here, but here's the fun part, it doesn't really matter!! just guess one and the beauty of this is, you don't have to be right!

lets pick 3 for the first byte in key 2

`1 3 1 3`

3 1 3 ?

3 1 3 ?

2 0 2 ?

? ? ?

now lets fill in some unknowns in key 1 based on the new information we just pulled out of our *ss

let start with the first column : some number ^ 3 = 1 so, some number = 3 ^ 1 , so first byte of key1 = 2,

`1 3 1 3`

3 1 3 ?

3 1 3 ?

2 0 2 ?

2 ? ?

second column 3^3 = 0, so second one is 0

`1 3 1 3`

3 1 3 ?

3 1 3 ?

2 0 2 ?

2 0 ?

third column 1^3 is 2 again

`1 3 1 3`

3 1 3 ?

3 1 3 ?

2 0 2 ?

2 0 2

awesome we just recovered key 1, lets see what else we fill in now, we see that in the second row , last column that key2 pos 2 must be 2 ^ 3 = 1

`1 3 1 3`

3 1 3 1

3 1 3 ?

2 0 2 ?

2 0 2

same goes for pos 3

`1 3 1 3`

3 1 3 1

3 1 3 1

2 0 2 ?

2 0 2

and finally 2 ^ 2 = 0

`1 3 1 3`

3 1 3 1

3 1 3 1

2 0 2 0

2 0 2

Hey look at that, all recovered and the fact that the iniital number we guessed might not be the original number doesn't even matter, and we didn't need all the data in the table either (just 2 values on each row/column)

now how to decrypt the flasher without knowing the keys or plaintext? by hoping for a large block of 0x00's

Step 1 start at offset 0, feed keysize1+keysize2 bytes of data to the key recovery algo.

step 2 at offset 0 decrypt (keysize1*2)+keysize2 bytes using the just recovered keys

step 3 if the decrypted data is all zero's we're done and have got the final keys, if not move to offset 1 and go back to step 1

Attached a small C# app that eats its way though the 500d firmware not the prettiest code ever but it does the job, sadly the 550d lacks the 00's, uses a different algo or keylength so came up empty handed on that one but hey it was still a fun excercise