When I originally wrote the key searching program, that was on the assumption that the key for the second Feistel network was 96 bits long.<br /><br />Each (E,D) pair reduces the key space by a factor of about 2<sup>16</sup>, so to isolate the correct key with good confidence one would need at least 96/16 = 6 (E,D) pairs.<br /><br />The big problem is finding those pairs. Remember that they must be at compatible addresses, that is addresses whose bottom 17 bits are the same. This is a serious limitation, because the code of several games only covers a range of 0x80000 bytes, which would give a maximum of 4 pairs at any address. For the Super Puzzle Fighter 2 games, the range is just 0x40000 bytes, giving just 2 pairs per address.<br />One can find hundreds, even thousands of of (E,D) pairs, but if they are not at compatible addresses they are of no use to find the key using this attack.<br /><br />However, now we know that the key actually has only 64 significant bits, some of which are repeated. I therefore rewrote the program to take that into account. This means that only 4 (E,D) pairs are needed to isolate the key.<br /><br />Also, I made several important optimisations that I missed the first time around, like caching intermediate results and speeding up the s-boxes calculations by using precalculated tables (this last optimisation also made into MAME so the decryption when loading a game is now faster).<br /><br />The end result is a program that is orders of magnitude faster than the previous one.<br />Now it takes just 15 seconds to find the key given 8 (E,D) pairs. With 5 pairs, which was just plain impossible before, it takes 5 minutes. With 4 pairs, 35 minutes.<br /><br />These improvement made it simple to find most of the remaining keys, even for games that didn't have a matching revision already decrypted (most notably some of the Steeet Fighter Zero versions).<br /><br />But there's more: the program is now fast enough to go one step further, and look for the key with just 3 pairs. Of course 3 pairs are not enough to isolate the right key: they only reduce the key space by about 2<sup>48</sup>, therefore leaving about 2<sup>16</sup>keys which are compatible with the data. Once a 64-bit key for the second Feistel network is selected, the compatible 64-bit master keys can then be easily generated, and used to verify other (E,D) pairs at different addresses. This allows to find the correct key in less than one day, and I had to use this extended attack for a couple of the most problematic games.<br /><br />In the meantime, Andreas Naive has been busy implementing the attack he had<a href="http://andreasnaive.blogspot.com/2007/02/cps-2-11.html">described on his blog</a>, and was able to find the keys for two of the Super Puzzle Fighter 2 games. Unfortunately, the attack failed on the third. Work is still in progress on that one, and there is some hope that the key will eventually be found.<br /><br />The only other games that are missing a key are the two CPS2 versions of Mega Man. There is no decrypted CPS2 version of that game to compare with, and the CPS1 version seems to be too different to be able to find good pairs.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-117171582069777064?l=mamelife.blogspot.com' alt='' /></div>
As<a href="http://mamelife.blogspot.com/2007/01/cps2-getting-closer.html">previously mentioned</a>, the 64-bit keys I'm currently using should be the same as the hardware ones, except for a fixed permutation of the bits.<br /><br />The permutation is actually irrelevant as far as the algorithm is concerned, since it is already taken into account when generating subkeys. The difference that it does make, however, is that there are strong suspicions that some of the keys are not random numbers, so what looks like random gibberish currently would show some order if we had the correct permutation.<br /><br />Take the ssf2 versions for example. There are currently 6 different versions supported: World, USA, Asia, Japan, Tournament World, Tournament Japan. Here are the keys (in a different order):<br /><br />3D9E1E15A58C32CE<br />3599DF35AD98284C<br />B74433502F4653D7<br />8758E3923FFA1A50<br />F0AE3D08420DD6BF<br />6260014FD857F7A7<br /><br />there is something immediately obvious about those keys: they all contain exactly 32 0s and 32 1s.<br />When picking one random 64-bit numbers, the likelihood of this happening is about 1 in 10, so it's ok. But the likelihood of it happening for SIX numbers is about 1 in 1<em>million</em>! So we can be pretty sure that those keys are<strong>not</strong>random numbers.<br /><br />What is one particularly simple sequence that has exactly 32 1s? Well, of course 0123456789ABCDEF. And sure enough, after looking at the bits for a while and applying an appropriate permutation, here is what the above keys become:<br /><br />0123456789ABCDEF<br />1032547698BADCFE<br />45673210CDEFAB89<br />67451032FEDC98BA<br />89ABDCEF45672301<br />CDEFBA9823016754<br /><br />looks much better doesn't it?<br />Though there's no way to tell how close it is to the real thing.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116937754701213882?l=mamelife.blogspot.com' alt='' /></div>
The<a href="http://mamelife.blogspot.com/2007/01/cps2-fight-continues.html">improved attack</a>works, and I've been able to recover a few more keys, but it takes a lot of computation time--several hours per game.<br /><br />I've also experienced some failures, e.g. I could find the key for dimahoo but not for gmahou. This might have been because of a false positive when looking for pairs with the complementation property, so now I'm trying again with a different pair. Since the searches take so long, experimenting isn't easy.<br /><br />On the plus side, I've applied the improved attack also to some games for which XOR files were not available, and it worked in a number of cases--though it failed in many others.<br /><br />One of the new versions supported is mshb, which I is the first Brazilian version of a CPS2 game to work.<br /><br />Andreas has published details on a theoretical<a href="http://andreasnaive.blogspot.com/2007/01/cps-2-10.html">attack</a>using<a href="http://en.wikipedia.org/wiki/Linear_cryptanalysis">differential cryptanalysis</a>which looks promising. If Andy's calculations are correct, it should allow to retrive the key for the three most problematic games: spf2t, spf2xj, and spf2ta. It does require a lot of (E,D,k) triplets, something in the order of 2<sup>16</sup>-2<sup>17</sup>, which is a bit steep, but we should be able to do that in a few cases.<br /><br />One thing to note about<a href="http://mamelife.blogspot.com/2007/01/how-to-bruteforce-cps2.html">my attack</a>, which I might not have explained clearly, is that it requires a remarkably small amount of data: it has worked for many games with just 7 (E,D) pairs. The problem is that those pairs must all be at the same address (as far as the encryption is concerned; that is, bits 1-16 of the address must be the same). Those 7 pairs allow to retrieve the 96-bit key for the second round at that address, and once that is known, the 64-bit master key can be found in less than 1 second, without having to know ANY other (E,D) pair at any address.<br /><br />Unfortunately for game like spf2t, whose full encryption range covers just 2 repetitions of an address, we are never going to have 7 pairs so the attack will never work.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116924264481953261?l=mamelife.blogspot.com' alt='' /></div>
I've finished going through all the games previously supported by MAME using XOR files, and generating keys using<a href="http://mamelife.blogspot.com/2007/01/how-to-bruteforce-cps2.html">this attack</a>.<br /><br />The attack needs a minimum of 7 (E,D) pairs at some address in order to work, though with just 7 pairs it takes several hours to find the key.<br /><br />Most of the games provided at least 8 pairs, a few 7, so the attack worked.<br /><br />On 11 games the attack didn't work. Three of them only provide 2 pairs, so there's no way for the attack to work--a different approach will be needed.<br /><br />The others provide 4 pairs, and I'm now trying to still perform the attack, using a new trick.<br /><br />Remember the<a href="http://mamelife.blogspot.com/2006/12/cps2-notes-part-2.html">complementation property</a>? For every address A, we know that exists another address A<sub>1</sub>such that D(X, A) = D(X ^ 0xffff, A<sub>1</sub>) ^ 0xffff. The problem is that we don't know A<sub>1</sub>. We can search it, however, using the XOR data. Pick an address, look at the four (E,D) pairs associated to it, and then see if at another address there is a pair (E ^ 0xffff, D ^ 0xffff). That way we can put together the information from the two addresses, raising the number of pairs from 4 to 7, barely enough to run the attack.<br /><br />There's a possibility of false positives when doing this, so avoid all pairs where E or D are 0x0000 or 0xffff, because those values are very common and make the probablity of a false positive much higher.<br /><br />In theory this trick should work, though it will require some luck and a lot of time. The holy grail remains an attack which could use pairs from different addresses; that would be the only way to retrieve the key for the games that lack XORs.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116907500474529968?l=mamelife.blogspot.com' alt='' /></div>
The correlations between the 96-bit keys of the two Feistel networks were crucial in getting the s-boxes with 4 or 5 inputs "in sync"--that is, make them idential to the real ones apart from a fixed XOR or permutation applied to the whole box.<br /><br />Eventually, I ended with a layout which I'm 99.9% sure is equivalent to the real one. We cannot know the exact contents of the real s-boxes without getting them from the actual hardware, but the current ones should be matematically equivalent.<br />The result is here: http://xoomer.alice.it/nicola.salmoria/cps2crptv2.zip.<br /><br />The most notable news is that the key is now reduced to 64 bits, and the one we are currently using should be identical to the one used by the hardware, apart from a fixed permutation of the bits.<br />Finding the real permutation would be nice, but obviously that's not something we can determine from the algorithm, since the order of the bits of the key is completely irrelevant.<br /><br />What is interesting to note is that the keys used by some games don't seem to be random. If they were random one would expect there to be around 32 0s and 32 1s, but sometimes this isn't the case. E.g.<pre>pzloop2: 3332206a0077f829<br />mshj: 01c0c951370f4c80<br />dstlka: 04048b4e2a498879<br />ringdest: 0405541367806575<br />cybotsj: 0404821534388354</pre><br />Of these, the last three literally scream "I'm not a random number!". Guessing the right bit order to make something appear, of course, is another matter.<br />Some of the watchdog values contain birth dates, e.g. cmpi.l #$19660419,D1, so I expect the same thing might be happening here.<br />Also, it makes sense for the pzloop2 one to be more regular than the others because it's third party game.<br /><br />On the key extraction front, things are going reasonably well. The brute force attack described in the<a href="http://mamelife.blogspot.com/2007/01/how-to-bruteforce-cps2.html">previous article</a>is working decently on most games, however for some of them the available data isn't enough. I'll have a more precise list once I've finished going through all the games. After that, we'll need to devise a better attack if we want to get the missing keys.<br /><br />The discovery that the key is only 64 bits might help to construct a better attack, though at the moment I don't have many ideas. The fact that the algorithm is divided in two parts, with the output of the first one affecting the key on the second part, complicates things.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116880139841169559?l=mamelife.blogspot.com' alt='' /></div>
I couldn't devise an attack using differential cryptanalysis and the XOR files. The fact that the second 96-bit key changes with the address makes thing more difficult, and I couldn't think of a way to effectively use data from different addresses.<br /><br />The XOR files give us no more than 8-16 (E,D) pairs at a given address (remember that the encryption only uses the low 16 bits of the address). We have no choice of what data we have, so we have to make the best of it.<br /><br />So the idea I had is to use a meet in the middle brute force attack which exploits a weakness in the s-boxes.<br /><br />Remember that<br /><br />L<sub>1</sub>= R<sub>0</sub><br />R<sub>1</sub>= L<sub>0</sub>XOR f<sub>1</sub>(R<sub>0</sub>)<br /><br />L<sub>2</sub>= R<sub>1</sub><br />R<sub>2</sub>= L<sub>1</sub>XOR f<sub>2</sub>(R<sub>1</sub>)<br /><br />L<sub>3</sub>= R<sub>2</sub><br />R<sub>3</sub>= L<sub>2</sub>XOR f<sub>3</sub>(R<sub>2</sub>)<br /><br />L<sub>4</sub>= R<sub>3</sub><br />R<sub>4</sub>= L<sub>3</sub>XOR f<sub>4</sub>(R<sub>3</sub>)<br /><br />Remember also that the f<sub>n</sub>round functions are made of 4 s-boxes each.<br />These are the 16 s-boxes, with their inputs and outputs:<br /><pre>f1b1 03457- 67<br />f1b2 12346- 35<br />f1b3 124567 14<br />f1b4 023567 02<br /><br />f2b1 0246-- 46<br />f2b2 134567 03<br />f2b3 013457 17<br />f2b4 123567 25<br /><br />f3b1 2346-- 35<br />f3b2 01357- 02<br />f3b3 012357 16<br />f3b4 024567 47<br /><br />f4b1 01367- 03<br />f4b2 012456 47<br />f4b3 023457 12<br />f4b4 234567 56</pre><br />f2b1 is the weakest link. It has only four inputs, 0246. To get those four inputs, we need just<em>three</em>boxes in round 1: f1b1, which outputs 67, f1b3, which outputs 14, and f1b4, which outputs 02. We don't need f1b2, which outputs 35.<br /><br />So if we start from the ciphertext and run it through the first two rounds of the Feistel network, scanning all 2<sup>24</sup>possible keys for f1b1, f1b3, f1b4, and f2b1, we'll get all possible values for bits 46 of R2.<br /><br />Now let's start from the plaintext instead, and go up. If we scan all 2<sup>6</sup>keys for f4b2, we'll get all possible values for bits 47 of R2 again.<br /><br />Now we impose that bit 4 calculated in these two ways is the same, and given enough (E,D) pairs we have a huge pruning of the valid keys. From experiments, at least 8 pairs are needed for the attack to work effectively, but with 12 it's faster.<br /><br />When we have a match on bit 4, we start adding more key bits, 6 or 12 at a time. First f4b4, to match bit 6 of R2. Then f1b2 and f2b3, to match bit 7 of R2. At this point, we are most likely already left with a single key, so adding more key bits doesn't increase the computation time. The important thing is to do it 6 bits at a time, in order to avoid unnecessary calculations. Soon enough, we have reconstructed the whole 96-bit key.<br /><br />This will be the key at a specific address--of course, before running the search we'd have scanned the whole data and selected the address with most different pairs, in order to make the attack more effective.<br /><br />After the 96-bit key at one address is found, the rest is easy. Since the 96-bit key is modified by the 16-bit result of the first FN in a fixed way, we just use brute force to find the correct 16-bit value at every address, and then we have a full subkey table as when we had the full 8GB tables at the beginning.<br /><br />The process is working reasonably well, it's taking me 20-40 minutes to find the 192-bit key for a game. It could be made faster, probably. I've done some games for which I had more data, and Razoola was kind enough to provide additional data that will help with many other games. I'm not yet sure that the attack will work on all games, but it surely will on a good percentage.<br /><br />Some very good news after obtaining more keys is that I found strong correlations between the first and second 96-bit keys, so they are effectively the same key, just permuted. This will also allow to fix the order of the subtables in the s-boxes of the first FN, in the same way I did for the second.<br /><br />Should we consider ourselves finished after that?<br /><br />Not yet: whether it will be possible to generate keys for games for which we lack XOR data is an open problem. In that case, the best we can expect to do is to match the startup code from a different version of the game, so we'll have several (E,D) pairs at consecutive addresses, and no more than one pair at a given address. A new attack will have to be devised in order to use that kind of information. Hopefully the discovery that the first and second 96-bit keys are correlated will help.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116862699228972073?l=mamelife.blogspot.com' alt='' /></div>
I've submitted to MAMEDEV the code to replace the 4GB CHDs with 192-bit keys.<br />The code is here: http://xoomer.alice.it/nicola.salmoria/cps2crpt.zip<br />It contains all the information needed to understand the algorithm, including the s-boxes.<br /><br />There is still a lot of uncertainty about the contents of the s-boxes. They do their job, but since they are different from the originals they also affect the key. Using the real s-boxes might make correlations between the key bits more apparent, if they exist (anyway, having only 7 keys to look at, there's not enough data to speculate on any kind of correlation).<br /><br />I'm hoping that it will be possible to extract the s-boxes contents from photos of the decapped CPS2 chip. That would be an important step forward in the accuracy of the emulation.<br /><br />Now the next challenge is finding the keys for the other CPS2 games that have XOR files but not full tables. I have some ideas, but it doesn't look simple.<br />We have a lot of (E,D,k) triplets for those games, but unfortunately not many once you fix k (the 96-bit key used in the second FN), and that would be the most important part.<br /><br />Note that we don't have to find the whole 192-bit key all at once. Once the second 96-bit was found, then we could easily use brute force to get the 16-bit key seed at every address, and therefore easily find the first 96-bit key.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116838266619495855?l=mamelife.blogspot.com' alt='' /></div>
Today I realised why I was having problems with the correlations between subkey bits, where some bits had to be derived from the others not only using XOR, but also AND and OR.<br /><br />The reason was again in the s-boxes that only have 4 or 5 data inputs instead of the full 6. Those boxes contain 2 or 4 subtables, and the order of the subtables inside the box or the order of the bits inside each subtable isn't particularly important when decrypting a single address, because they can always be compensated by appropriate bits in the subkey.<br /><br />However, when putting all subkeys together, those things became important. E.g. I could be finding that when using subtable #3 in a box, then two of the inputs had to be inverted. To fix this, I had to rearrange the subtables inside the s-boxes to make everything in sync.<br /><br />The result was excellent. Previously, some of the correlations among the 96 bits were overly complex, taking up to 4 bits at once. Now every bit is directly correlated to another. The only exception is the bits that correspond to the "empty" inputs of s-boxes that take only 4 or 5 data inputs. What this means is that all 6 inputs of all s-boxes always receive the XOR of three sources: either a data bit, a key seed bit, and a global key bit; or two key seed bits, and a global key bit.<br /><br /><br />That's only the beginning of the good news, though. After fixing the s-boxes, I could attack again the first part on the algorithm on the assumption it was a 4-round Feistel network, and indeed it was.<br /><br />So the algorithm turns out to be like this:<ol><br /><li>Take the 16-bit address and a 96-bit key and run them through the first Feistel network, to produce a 16-bit subkey.</li><br /><li>Take the 16-bit ciphertext, 16-bit subkey, and another 96-bit key and run them through the second Feistel network, to produce the 16-bit plaintext</li></ol><br /><br />So now, for the first time, I would be able to produce a program that algorithmically decrypts one of the game for which we have full tables, without using any table.<br /><br />It's not yet time to celebrate, though: the s-boxes for the first Feistel network still have to be properly determined, and this might require having access to some more games.<br /><br />Once that is done, producing keys for games that we have complete tables for will be quite simple.<br /><br />Finding keys for games for which we don't have full tables, however, is an entirely different matter. As said above, we are potentially dealing with a 192-bit key here; it's possible that the key is smaller and the bits are reused, however since we don't know how they would be, we have to treat it like a 192-bit one. For a key of that size, obviously brute force is out of the question; and while the XOR tables do provide some information, it's probably not the kind of information that would allow to use the<a href="http://en.wikipedia.org/wiki/Differential_cryptanalysis">differential cryptanalysis</a>techniques we'd need.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116822211657288301?l=mamelife.blogspot.com' alt='' /></div>
Some people thought we were almost finished with the CPS2 algorithm, but this doesn't seem to be the case.<br />True, at least the 4GB tables could now be replaced with a single 128kB table, but that's still not how the hardware works, and it wouldn't be possible to generate proper keys for the games that are missing the full 8GB tables, which is the main concern.<br /><br />From the full tables, we can extract a 96-bit subkey for every address.<br /><em>Edit: I had a link to a file here. I've removed it since I've found an error which I'll correct soon.</em><br />These wouldn't be the actual keys used by the hardware, however I think me and Andy have agreed that they are, apart from a fixed XOR and bit permutation that wouldn't change from game to game. So we can forget about this step of the decryption for the time being, and move on.<br /><br />The problem now is to understand how the hardware generates the 96-bit subkey starting from the address and from the global key.<br /><br />I have determined that only 16 bits are needed to generate the 96-bit subkey; this was sort of expected, but it isn't without problems.<br />We can generate only<em>94</em>bits of the subkey starting from those 16 bits and using only XOR operations. The remaining 2 bits need AND/OR operations, something which I have no explaination for at this point.<br /><br />That was the least of the problems anyway. The major hurdle at this point is that the mapping from address to 16-bit key seed is very far from trivial.<br /><br />The scheme should be as follows:<br /><ol><li>take 16-bit address, N-bit global key, and generate a 16-bit key seed using an unknown algorithm.</li><br /><li>take 16-bit key seed, M-bit global key, and generate 96-bit subkey using an unknown algorithm.</li><br /><li>take 16-bit ciphertext, 96-bit subkey, and generate 16-bit plaintext using the algorithm we have discovered.</li></ol><br />I think it would make sense for the algorithm in step 1. to be another 4-round Feistel network.<br />If this is the case, things are quite harder than before. To break the other Feistel network, we could rely on complete knowledge of ciphertext-plaintext relationship. Now we can't: we only have a vague idea of what the 16-bit key seed could be.<br /><br />If we could rely on a 16-bit value except for a constant XOR and permutation, it wouldn't be a problem, since that wouldn't change the nature of the Feistel network. Unfortunately, we don't have that luxury.<br /><br />Let's see that with an example. Let's say that the first algorithm generates a 4-bit key seed,<em>abcd</em>, which is expanded into the 6-bit subkey<em>ABCDEF</em>this way:<br /><br />A = a<br />B = a XOR b<br />C = a XOR c<br />D = b XOR c<br />E = b XOR d<br />F = b XOR c XOR d<br /><br />We don't know anything about<em>abcd</em>, all we see is<em>ABCDEF</em>, but we need to guess what<em>abcd</em>looks like. So we notice that<br /><br />D = B XOR C<br />F = A XOR C XOR E<br /><br />and we decide that<br /><br />a' = A<br />b' = B<br />c' = C<br />d' = E<br /><br />so we would have<br /><br />A = a'<br />B = b'<br />C = c'<br />D = b' XOR c'<br />E = d'<br />F = a' XOR c' XOR d'<br /><br />This all works as far as generating the subkey from the seed goes, the problem is that<em>abcd</em>and<em>a'b'c'd'</em>are two completely different numbers! We have that<br /><br /><em>a'b'c'd'</em>=<em>abcd</em>XOR<em>aab</em><br /><br />so this isn't simply a XOR with a constant value, it's a variable modification of the number. And this is something that the Feistel network cannot handle.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116813734850466536?l=mamelife.blogspot.com' alt='' /></div>
I said earlier that I was going to post the program to extract subkeys from a CHD, and the subkey lists for a few games, however after extracting the subkeys I found important relationships between the subkey bits so I'll have to work on that first.<br /><br />A subkey consists of 24*4 = 96 bits. There are 65536 subkeys, so the total is 786kB of data.<br /><br />What I found that one bit of the subkey is constant, while 59 can be derived from the others with a XOR (which is constant for all 65536 addresses, but changes from game to game).<br /><br />So this hints at a 64-bit global key, while the independent subkey bits drop for now at 96-1-59 = 36 bits.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10457042-116809206164431983?l=mamelife.blogspot.com' alt='' /></div>