Previous 199869 Revisions Next

r33132 Sunday 2nd November, 2014 at 09:29:08 UTC by David Haywood
move 315-5881 based encryption to it's own file, allowing me to experiment with the device for the encrypted ST-V games.
[src/mame]mame.mak
[src/mame/drivers]stv.c
[src/mame/includes]stv.h
[src/mame/machine]315-5881_crypt.c* 315-5881_crypt.h* naomim2.c naomim2.h stvprot.c

trunk/src/mame/drivers/stv.c
r241643r241644
10211021   MCFG_SOUND_ADD("cdda", CDDA, 0)
10221022   MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
10231023   MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
1024
1025   MCFG_DEVICE_ADD("315_5881", SEGA315_5881_CRYPT, 0)
1026   //MCFG_SET_READ_CALLBACK(stv_state, read_callback)
10241027MACHINE_CONFIG_END
10251028
10261029/*
trunk/src/mame/includes/stv.h
r241643r241644
99#include "bus/generic/slot.h"
1010#include "bus/generic/carts.h"
1111
12#include "machine/315-5881_crypt.h"
13
1214#define MAX_FILTERS (24)
1315#define MAX_BLOCKS  (200)
1416#define MAX_DIR_SIZE    (256*1024)
r241643r241644
3335         m_cart3(*this, "stv_slot3"),
3436         m_cart4(*this, "stv_slot4"),
3537         m_gfxdecode(*this, "gfxdecode"),
36         m_palette(*this, "palette")
38         m_palette(*this, "palette"),
39         m_cryptdevice(*this, "315_5881")
3740   {
3841   }
3942
r241643r241644
167170   required_device<gfxdecode_device> m_gfxdecode;
168171   required_device<palette_device> m_palette;
169172
173   optional_device<sega_315_5881_crypt_device> m_cryptdevice;
174
175
170176   bitmap_rgb32 m_tmpbitmap;
171177   DECLARE_VIDEO_START(stv_vdp2);
172178   UINT32 screen_update_saturn(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
trunk/src/mame/machine/315-5881_crypt.c
r0r241644
1/*
2  re: Tecmo World Cup '98 (ST-V) (from ANY)
3
4  I got one of the card in subject open it up to check the rom version
5  and made a discovery...
6  The protection chip has the part number on it "315-5881", it's the same
7  used on naomi M2 carts as you can see here
8  http://imagizer.imageshack.us/a/img540/7634/BsqvD8.jpg
9
10  The same chip 315-5881 but with a Lattice IspLSI2032 (Sega part
11  315-6050) was used on some Model3 games...
12
13*/
14
15#include "emu.h"
16#include "machine/315-5881_crypt.h"
17
18extern const device_type SEGA315_5881_CRYPT = &device_creator<sega_315_5881_crypt_device>;
19
20
21sega_315_5881_crypt_device::sega_315_5881_crypt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
22   : device_t(mconfig, SEGA315_5881_CRYPT, "Sega 'SEGA315_5881' Encryption device", tag, owner, clock, "SEGA315_5881", __FILE__)
23{
24}
25
26
27
28void sega_315_5881_crypt_device::device_start()
29{
30   buffer = auto_alloc_array(machine(), UINT8, BUFFER_SIZE);
31   line_buffer = auto_alloc_array(machine(), UINT8, LINE_SIZE);
32   line_buffer_prev = auto_alloc_array(machine(), UINT8, LINE_SIZE);
33
34   m_read.bind_relative_to(*owner());
35
36   save_pointer(NAME(buffer), BUFFER_SIZE);
37   save_pointer(NAME(line_buffer), LINE_SIZE);
38   save_pointer(NAME(line_buffer_prev), LINE_SIZE);
39   save_item(NAME(prot_cur_address));
40   save_item(NAME(subkey));
41   save_item(NAME(enc_ready));
42   save_item(NAME(dec_hist));
43   save_item(NAME(dec_header));
44   save_item(NAME(buffer_pos));
45   save_item(NAME(line_buffer_pos));
46   save_item(NAME(line_buffer_size));
47
48}
49
50void sega_315_5881_crypt_device::device_reset()
51{
52   memset(buffer, 0, BUFFER_SIZE);
53   memset(line_buffer, 0, LINE_SIZE);
54   memset(line_buffer_prev, 0, LINE_SIZE);
55
56   prot_cur_address = 0;
57   subkey = 0;
58   dec_hist = 0;
59   dec_header = 0;
60   enc_ready = false;
61
62   buffer_pos = 0;
63   line_buffer_pos = 0;
64   line_buffer_size = 0;
65   buffer_bit = 0;
66}
67
68void sega_315_5881_crypt_device::do_decrypt(UINT8 *&base)
69{
70   if(!enc_ready)
71      enc_start();
72   if(dec_header & FLAG_COMPRESSED) {
73      if(line_buffer_pos == line_buffer_size)
74         line_fill();
75      base = line_buffer + line_buffer_pos;
76      line_buffer_pos += 2;
77   } else {
78      if(buffer_pos == BUFFER_SIZE)
79         enc_fill();
80      base = buffer + buffer_pos;
81      buffer_pos += 2;
82   }
83}
84
85void sega_315_5881_crypt_device::set_addr_low(UINT16 data)
86{
87   prot_cur_address = (prot_cur_address & 0xffff0000) | data;
88   enc_ready = false;
89}
90
91void sega_315_5881_crypt_device::set_addr_high(UINT16 data)
92{
93   prot_cur_address = (prot_cur_address & 0x0000ffff) | (data << 16);
94   enc_ready = false;
95}
96
97void sega_315_5881_crypt_device::set_subkey(UINT16 data)
98{
99   subkey = data;
100   enc_ready = false;
101}
102
103void sega_315_5881_crypt_device::set_key(UINT32 data)
104{
105   key = data;
106   enc_ready = false;
107}
108
109/***************************************************************************
110    DECRYPTION EMULATION
111
112By convention, we label the three known cart protection methods this way (using Deunan Knute's wording):
113M1: DMA read of protected ROM area
114M2: special read of ROM area which supplies decryption key first
115M3: normal read followed by write to cart's decryption buffer (up to 64kB), followed by M2 but from buffer area
116
117Notes below refer to M2 & M3.
118
119The encryption is done by a stream cipher operating in counter mode, which use a 16-bits internal block cipher.
120
121There are 2 "control bits" at the start of the decrypted stream which control the mode of operation: bit #1 set to 1 means
122that the decrypted stream needs to be decompressed after being decrypted. More on this later.
123
124The next 16-bits are part of the header (they don't belong to the plaintext), but his meaning is unclear. It has been
125conjectured that it could stablish when to "reset" the process and start processing a new stream (based on some tests
126on WWFROYAL, in which the decryption's output doesn't seem to be valid for more than some dozens of words), but some
127more testing would be needed for clarifying that.
128
129After those 18 heading bits, we find the proper plaintext. It must be noted that, due to the initial 2 special bits,
130the 16-bits words of the plaintext are shifted 2 bits respect to the word-boundaries of the output stream of the
131internal block-cipher. So, at a given step, the internal block cipher will output 16-bits, 14 of which will go to a
132given plaintext word, and the remaining 2 to the next plaintext word.
133
134The underlying block cipher consists of two 4-round Feistel Networks (FN): the first one takes the counter (16 bits),
135the game-key (>=26 bits) and the sequence-key (16 bits) and output a middle result (16 bits) which will act as another key
136for the second one. The second FN will take the encrypted word (16 bits), the game-key, the sequence-key and the result
137from the first FN and will output the decrypted word (16 bits).
138
139Each round of the Feistel Networks use four substitution sboxes, each having 6 inputs and 2 outputs. The input can be the
140XOR of at most two "sources bits", being source bits the bits from the previous round and the bits from the different keys.
141
142The underlying block cipher has the same structure than the one used by the CPS-2 (Capcom Play System 2) and,
143indeed, some of the used sboxes are exactly the same and appear in the same FN/round in both systems (this is not evident,
144as you need to apply a bitswapping and some XORs to the input & output of the sboxes to get the same values due). However,
145the key scheduling used by this implementation is much weaker than the CPS-2's one. Many s-boxes inputs aren't XORed with any
146key bit.
147
148Due to the small key-length, no sophisticated attacks are needed to recover the keys; a brute-force attack knowing just
149some (encrypted word-decrypted word) pairs suffice. However, due to the weak key scheduling, it should be noted that some
150related keys can produce the same output bytes for some (short) input sequences.
151
152The only difference in the decryption process between M2 and M3 is the initialization of the counter. In M3, the counter is
153always set to 0 at the beginning of the decryption while, in M2, the bits #1-#16 of the ciphertext's address are used
154to initialize the counter.
155
156Note that this implementation considers that the counter initialization for ram decryption is 0 simply because the ram is
157mapped to multiples of 128K.
158
159Due to the nature of the cipher, there are some degrees of freedom when choosing the s-boxes and keys values; by example,
160you could apply a fixed bitswapping and XOR to the keys and the decryption would remain the same as long as you change
161accordingly the s-boxes' definitions. So the order of the bits in the keys is arbitrary, and the s-boxes values have been
162chosen so as to make the key for CAPSNK equal to 0.
163
164It can be observed that a couple of sboxes have incomplete tables (a 255 value indicate an unknown value). The recovered keys
165as of december/2010 show small randomness and big correlations, making possible that some unseen bits could make the
166decryption need those incomplete parts.
167
168****************************************************************************************/
169
170const sega_315_5881_crypt_device::sbox sega_315_5881_crypt_device::fn1_sboxes[4][4] = {
171   {   // 1st round
172      {
173         {
174            0,3,2,2,1,3,1,2,3,2,1,2,1,2,3,1,3,2,2,0,2,1,3,0,0,3,2,3,2,1,2,0,
175            2,3,1,1,2,2,1,1,1,0,2,3,3,0,2,1,1,1,1,1,3,0,3,2,1,0,1,2,0,3,1,3,
176         },
177         {3,4,5,7,-1,-1},
178         {0,4}
179      },
180
181      {
182         {
183            2,2,2,0,3,3,0,1,2,2,3,2,3,0,2,2,1,1,0,3,3,2,0,2,0,1,0,1,2,3,1,1,
184            0,1,3,3,1,3,3,1,2,3,2,0,0,0,2,2,0,3,1,3,0,3,2,2,0,3,0,3,1,1,0,2,
185         },
186         {0,1,2,5,6,7},
187         {1,6}
188      },
189
190      {
191         {
192            0,1,3,0,3,1,1,1,1,2,3,1,3,0,2,3,3,2,0,2,1,1,2,1,1,3,1,0,0,2,0,1,
193            1,3,1,0,0,3,2,3,2,0,3,3,0,0,0,0,1,2,3,3,2,0,3,2,1,0,0,0,2,2,3,3,
194         },
195         {0,2,5,6,7,-1},
196         {2,3}
197      },
198
199      {
200         {
201            3,2,1,2,1,2,3,2,0,3,2,2,3,1,3,3,0,2,3,0,3,3,2,1,1,1,2,0,2,2,0,1,
202            1,3,3,0,0,3,0,3,0,2,1,3,2,1,0,0,0,1,1,2,0,1,0,0,0,1,3,3,2,0,3,3,
203         },
204         {1,2,3,4,6,7},
205         {5,7}
206      },
207   },
208   {   // 2nd round
209      {
210         {
211            3,3,1,2,0,0,2,2,2,1,2,1,3,1,1,3,3,0,0,3,0,3,3,2,1,1,3,2,3,2,1,3,
212            2,3,0,1,3,2,0,1,2,1,3,1,2,2,3,3,3,1,2,2,0,3,1,2,2,1,3,0,3,0,1,3,
213         },
214         {0,1,3,4,5,7},
215         {0,4}
216      },
217
218      {
219         {
220            2,0,1,0,0,3,2,0,3,3,1,2,1,3,0,2,0,2,0,0,0,2,3,1,3,1,1,2,3,0,3,0,
221            3,0,2,0,0,2,2,1,0,2,3,3,1,3,1,0,1,3,3,0,0,1,3,1,0,2,0,3,2,1,0,1,
222         },
223         {0,1,3,4,6,-1},
224         {1,5}
225      },
226
227      {
228         {
229            2,2,2,3,1,1,0,1,0,1,2,2,3,3,0,2,0,3,2,3,3,0,2,1,0,3,1,0,0,2,3,2,
230            3,2,0,3,2,0,1,0,3,3,1,1,2,2,2,0,2,1,3,1,1,1,1,2,2,2,3,0,1,3,0,0,
231         },
232         {1,2,5,6,7,-1},
233         {2,7}
234      },
235
236      {
237         {
238            0,1,3,3,3,1,3,3,1,0,2,0,2,0,0,3,1,2,1,3,1,2,3,2,2,0,1,3,0,3,3,3,
239            0,0,0,2,1,1,2,3,2,2,3,1,1,2,0,2,0,2,1,3,1,1,3,3,1,1,3,0,2,3,0,0,
240         },
241         {2,3,4,5,6,7},
242         {3,6}
243      },
244   },
245   {   // 3rd round
246      {
247         {
248            0,0,1,0,1,0,0,3,2,0,0,3,0,1,0,2,0,3,0,0,2,0,3,2,2,1,3,2,2,1,1,2,
249            0,0,0,3,0,1,1,0,0,2,1,0,3,1,2,2,2,0,3,1,3,0,1,2,2,1,1,1,0,2,3,1,
250         },
251         {1,2,3,4,5,7},
252         {0,5}
253      },
254
255      {
256         {
257            1,2,1,0,3,1,1,2,0,0,2,3,2,3,1,3,2,0,3,2,2,3,1,1,1,1,0,3,2,0,0,1,
258            1,0,0,1,3,1,2,3,0,0,2,3,3,0,1,0,0,2,3,0,1,2,0,1,3,3,3,1,2,0,2,1,
259         },
260         {0,2,4,5,6,7},
261         {1,6}
262      },
263
264      {
265         {
266            0,3,0,2,1,2,0,0,1,1,0,0,3,1,1,0,0,3,0,0,2,3,3,2,3,1,2,0,0,2,3,0,
267            // unused?
268            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
269         },
270         {0,2,4,6,7,-1},
271         {2,3}
272      },
273
274      {
275         {
276            0,0,1,0,0,1,0,2,3,3,0,3,3,2,3,0,2,2,2,0,3,2,0,3,1,0,0,3,3,0,0,0,
277            2,2,1,0,2,0,3,2,0,0,3,1,3,3,0,0,2,1,1,2,1,0,1,1,0,3,1,2,0,2,0,3,
278         },
279         {0,1,2,3,6,-1},
280         {4,7}
281      },
282   },
283   {   // 4th round
284      {
285         {
286            0,3,3,3,3,3,2,0,0,1,2,0,2,2,2,2,1,1,0,2,2,1,3,2,3,2,0,1,2,3,2,1,
287            3,2,2,3,1,0,1,0,0,2,0,1,2,1,2,3,1,2,1,1,2,2,1,0,1,3,2,3,2,0,3,1,
288         },
289         {0,1,3,4,5,6},
290         {0,5}
291      },
292
293      {
294         {
295            0,3,0,0,2,0,3,1,1,1,2,2,2,1,3,1,2,2,1,3,2,2,3,3,0,3,1,0,3,2,0,1,
296            3,0,2,0,1,0,2,1,3,3,1,2,2,0,2,3,3,2,3,0,1,1,3,3,0,2,1,3,0,2,2,3,
297         },
298         {0,1,2,3,5,7},
299         {1,7}
300      },
301
302      {
303         {
304            0,1,2,3,3,3,3,1,2,0,2,3,2,1,0,1,2,2,1,2,0,3,2,0,1,1,0,1,3,1,3,1,
305            3,1,0,0,1,0,0,0,0,1,2,2,1,1,3,3,1,2,3,3,3,2,3,0,2,2,1,3,3,0,2,0,
306         },
307         {2,3,4,5,6,7},
308         {2,3}
309      },
310
311      {
312         {
313            0,2,1,1,3,2,0,3,1,0,1,0,3,2,1,1,2,2,0,3,1,0,1,2,2,2,3,3,0,0,0,0,
314            1,2,1,0,2,1,2,2,2,3,2,3,0,1,3,0,0,1,3,0,0,1,1,0,1,0,0,0,0,2,0,1,
315         },
316         {0,1,2,4,6,7},
317         {4,6}
318      },
319   },
320};
321
322
323const sega_315_5881_crypt_device::sbox sega_315_5881_crypt_device::fn2_sboxes[4][4] = {
324   {   // 1st round
325      {
326         {
327            3,3,0,1,0,1,0,0,0,3,0,0,1,3,1,2,0,3,3,3,2,1,0,1,1,1,2,2,2,3,2,2,
328            2,1,3,3,1,3,1,1,0,0,1,2,0,2,2,1,1,2,3,1,2,1,3,1,2,2,0,1,3,0,2,2,
329         },
330         {1,3,4,5,6,7},
331         {0,7}
332      },
333
334      {
335         {
336            0,2,3,2,1,1,0,0,2,1,0,3,3,0,0,0,3,2,0,2,1,1,2,1,0,0,3,1,2,2,3,1,
337            3,1,3,0,0,0,1,3,1,0,0,3,2,2,3,1,1,3,0,0,2,1,3,3,1,3,1,2,3,1,2,1,
338         },
339         {0,3,5,6,-1,-1},
340         {1,2}
341      },
342
343      {
344         {
345            0,2,2,1,0,1,2,1,2,0,1,2,3,3,0,1,3,1,1,2,1,2,1,3,3,2,3,3,2,1,0,1,
346            0,1,0,2,0,1,1,3,2,0,3,2,1,1,1,3,2,3,0,2,3,0,2,2,1,3,0,1,1,2,2,2,
347         },
348         {0,2,3,4,7,-1},
349         {3,4}
350      },
351
352      {
353         {
354            2,3,1,3,2,0,1,2,0,0,3,3,3,3,3,1,2,0,2,1,2,3,0,2,0,1,0,3,0,2,1,0,
355            2,3,0,1,3,0,3,2,3,1,2,0,3,1,1,2,0,3,0,0,2,0,2,1,2,2,3,2,1,2,3,1,
356         },
357         {1,2,5,6,-1,-1},
358         {5,6}
359      },
360   },
361   {   // 2nd round
362      {
363         {
364            2,3,1,3,1,0,3,3,3,2,3,3,2,0,0,3,2,3,0,3,1,1,2,3,1,1,2,2,0,1,0,0,
365            2,1,0,1,2,0,1,2,0,3,1,1,2,3,1,2,0,2,0,1,3,0,1,0,2,2,3,0,3,2,3,0,
366         },
367         {0,1,4,5,6,7},
368         {0,7}
369      },
370
371      {
372         {
373            0,2,2,0,2,2,0,3,2,3,2,1,3,2,3,3,1,1,0,0,3,0,2,1,1,3,3,2,3,2,0,1,
374            1,2,3,0,1,0,3,0,3,1,0,2,1,2,0,3,2,3,1,2,2,0,3,2,3,0,0,1,2,3,3,3,
375         },
376         {0,2,3,6,7,-1},
377         {1,5}
378      },
379
380      {
381         {
382            1,2,3,2,0,3,2,3,0,1,1,0,0,2,2,3,2,0,0,3,0,2,3,3,2,2,1,0,2,1,0,3,
383            1,0,2,0,1,1,0,1,0,0,1,0,3,0,3,3,2,2,0,2,1,1,1,0,3,0,1,3,2,3,2,1,
384         },
385         {2,3,4,6,7,-1},
386         {2,3}
387      },
388
389      {
390         {
391            2,3,1,3,1,1,2,3,3,1,1,0,1,0,2,3,2,1,0,0,2,2,0,1,0,2,2,2,0,2,1,0,
392            3,1,2,3,1,3,0,2,1,0,1,0,0,1,2,2,3,2,3,1,3,2,1,1,2,0,2,1,3,3,1,0,
393         },
394         {1,2,3,4,5,6},
395         {4,6}
396      },
397   },
398   {   // 3rd round
399      {
400         {
401            0,3,0,1,0,2,3,3,1,0,1,3,2,2,1,1,3,3,3,0,2,0,2,0,0,0,2,3,1,1,0,0,
402            3,3,0,3,3,0,0,2,1,1,1,0,2,2,2,0,3,0,3,1,2,2,0,3,0,0,3,2,0,3,2,1,
403         },
404         {1,4,5,6,7,-1},
405         {0,5}
406      },
407
408      {
409         {
410            0,3,0,1,3,0,3,1,3,2,2,2,3,0,3,2,2,1,2,2,0,3,2,2,0,0,2,1,1,3,2,3,
411            2,3,3,1,2,0,1,2,2,1,0,0,0,0,2,3,1,2,0,3,1,3,1,2,3,2,1,0,3,0,0,2,
412         },
413         {0,2,3,4,6,7},
414         {1,7}
415      },
416
417      {
418         {
419            2,2,3,2,0,3,2,3,1,1,2,0,2,3,1,3,0,0,0,3,2,0,1,0,1,3,2,3,3,3,1,0,
420            // unused?
421            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
422         },
423         {1,2,4,7,-1,-1},
424         {2,4}
425      },
426
427      {
428         {
429            0,2,3,1,3,1,1,0,0,1,3,0,2,1,3,3,2,0,2,1,1,2,3,3,0,0,0,2,0,2,3,0,
430            3,3,3,3,2,3,3,2,3,0,1,0,2,3,3,2,0,1,3,1,0,1,2,3,3,0,2,0,3,0,3,3,
431         },
432         {0,1,2,3,5,7},
433         {3,6}
434      },
435   },
436   {   // 4th round
437      {
438         {
439            0,1,1,0,0,1,0,2,3,3,0,1,2,3,0,2,1,0,3,3,2,0,3,0,0,2,1,0,1,0,1,3,
440            0,3,3,1,2,0,3,0,1,3,2,0,3,3,1,3,0,2,3,3,2,1,1,2,2,1,2,1,2,0,1,1,
441         },
442         {0,1,2,4,7,-1},
443         {0,5}
444      },
445
446      {
447         {
448            2,0,0,2,3,0,2,3,3,1,1,1,2,1,1,0,0,2,1,0,0,3,1,0,0,3,3,0,1,0,1,2,
449            0,2,0,2,0,1,2,3,2,1,1,0,3,3,3,3,3,3,1,0,3,0,0,2,0,3,2,0,2,2,0,1,
450         },
451         {0,1,3,5,6,-1},
452         {1,3}
453      },
454
455      {
456         {
457            0,1,1,2,1,3,1,1,0,0,3,1,1,1,2,0,3,2,0,1,1,2,3,3,3,0,3,0,0,2,0,3,
458            3,2,0,0,3,2,3,1,2,3,0,3,2,0,1,2,2,2,0,2,0,1,2,2,3,1,2,2,1,1,1,1,
459         },
460         {0,2,3,4,5,7},
461         {2,7}
462      },
463
464      {
465         {
466            0,1,2,0,3,3,0,3,2,1,3,3,0,3,1,1,3,2,3,2,3,0,0,0,3,0,2,2,3,2,2,3,
467            2,2,3,1,2,3,1,2,0,3,0,2,3,1,0,0,3,2,1,2,1,2,1,3,1,0,2,3,3,1,3,2,
468         },
469         {2,3,4,5,6,7},
470         {4,6}
471      },
472   },
473};
474
475const int sega_315_5881_crypt_device::fn1_game_key_scheduling[38][2] = {
476   {1,29},  {1,71},  {2,4},   {2,54},  {3,8},   {4,56},  {4,73},  {5,11},
477   {6,51},  {7,92},  {8,89},  {9,9},   {9,10},  {9,39},  {9,41},  {9,58},
478   {9,59},  {9,86},  {10,90}, {11,6},  {12,64}, {13,49}, {14,44}, {15,40},
479   {16,69}, {17,15}, {18,23}, {18,43}, {19,82}, {20,81}, {21,32}, {21,61},
480   {22,5},  {23,66}, {24,13}, {24,45}, {25,12}, {25,35}
481};
482
483const int sega_315_5881_crypt_device::fn2_game_key_scheduling[34][2] = {
484   {0,0},   {1,3},   {2,11},  {3,20},  {4,22},  {5,23},  {6,29},  {7,38},
485   {8,39},  {9,47},  {9,55},  {9,86},  {9,87},  {9,90},  {10,50}, {10,53},
486   {11,57}, {12,59}, {13,61}, {13,64}, {14,63}, {15,67}, {16,72}, {17,83},
487   {18,88}, {19,94}, {20,35}, {21,17}, {21,92}, {22,6},  {22,11}, {23,85},
488   {24,16}, {25,25}
489};
490
491const int sega_315_5881_crypt_device::fn1_sequence_key_scheduling[20][2] = {
492   {0,52},  {1,34},  {2,17},  {3,36}, {4,84},  {4,88},  {5,57},  {6,48},
493   {6,68},  {7,76},  {8,83},  {9,30}, {10,22}, {10,41}, {11,38}, {12,55},
494   {13,74}, {14,19}, {14,80}, {15,26}
495};
496
497const int sega_315_5881_crypt_device::fn2_sequence_key_scheduling[16] = {77,34,8,42,36,27,69,66,13,9,79,31,49,7,24,64};
498
499const int sega_315_5881_crypt_device::fn2_middle_result_scheduling[16] = {1,10,44,68,74,78,81,95,2,4,30,40,41,51,53,58};
500
501int sega_315_5881_crypt_device::feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys)
502{
503   int k,m;
504   int aux;
505   int result=0;
506
507   for (m=0; m<4; ++m) { // 4 sboxes
508      for (k=0, aux=0; k<6; ++k)
509         if (sboxes[m].inputs[k]!=-1)
510            aux |= BIT(input, sboxes[m].inputs[k]) << k;
511
512      aux = sboxes[m].table[(aux^subkeys)&0x3f];
513
514      for (k=0; k<2; ++k)
515         result |= BIT(aux,k) << sboxes[m].outputs[k];
516
517      subkeys >>=6;
518   }
519
520   return result;
521}
522
523/**************************
524This implementation is an "educational" version. It must be noted that it can be speed-optimized in a number of ways.
525The most evident one is to factor out the parts of the key-scheduling that must only be done once (like the game-key &
526sequence-key parts) as noted in the comments inlined in the function. More sophisticated speed-ups can be gained by
527noticing that the weak key-scheduling would allow to create some pregenerated look-up tables for doing most of the work
528of the function. Even so, it would still be pretty slow, so caching techniques could be a wiser option here.
529**************************/
530
531UINT16 sega_315_5881_crypt_device::block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data)
532{
533   int j;
534   int aux,aux2;
535   int A,B;
536   int middle_result;
537   UINT32 fn1_subkeys[4];
538   UINT32 fn2_subkeys[4];
539
540   /* Game-key scheduling; this could be done just once per game at initialization time */
541   memset(fn1_subkeys,0,sizeof(UINT32)*4);
542   memset(fn2_subkeys,0,sizeof(UINT32)*4);
543
544   for (j=0; j<38; ++j) {
545      if (BIT(game_key, fn1_game_key_scheduling[j][0])!=0) {
546         aux = fn1_game_key_scheduling[j][1]%24;
547         aux2 = fn1_game_key_scheduling[j][1]/24;
548         fn1_subkeys[aux2] ^= (1<<aux);
549      }
550   }
551
552   for (j=0; j<34; ++j) {
553      if (BIT(game_key, fn2_game_key_scheduling[j][0])!=0) {
554         aux = fn2_game_key_scheduling[j][1]%24;
555         aux2 = fn2_game_key_scheduling[j][1]/24;
556         fn2_subkeys[aux2] ^= (1<<aux);
557      }
558   }
559   /********************************************************/
560
561   /* Sequence-key scheduling; this could be done just once per decryption run */
562   for (j=0; j<20; ++j) {
563      if (BIT(sequence_key,fn1_sequence_key_scheduling[j][0])!=0) {
564         aux = fn1_sequence_key_scheduling[j][1]%24;
565         aux2 = fn1_sequence_key_scheduling[j][1]/24;
566         fn1_subkeys[aux2] ^= (1<<aux);
567      }
568   }
569
570   for (j=0; j<16; ++j) {
571      if (BIT(sequence_key,j)!=0) {
572         aux = fn2_sequence_key_scheduling[j]%24;
573         aux2 = fn2_sequence_key_scheduling[j]/24;
574         fn2_subkeys[aux2] ^= (1<<aux);
575      }
576   }
577
578   // subkeys bits 10 & 41
579   fn2_subkeys[0] ^= (BIT(sequence_key,2)<<10);
580   fn2_subkeys[1] ^= (BIT(sequence_key,4)<<17);
581   /**************************************************************/
582
583   // First Feistel Network
584
585   aux = BITSWAP16(counter,5,12,14,13,9,3,6,4,    8,1,15,11,0,7,10,2);
586
587   // 1st round
588   B = aux >> 8;
589   A = (aux & 0xff) ^ feistel_function(B,fn1_sboxes[0],fn1_subkeys[0]);
590
591   // 2nd round
592   B = B ^ feistel_function(A,fn1_sboxes[1],fn1_subkeys[1]);
593
594   // 3rd round
595   A = A ^ feistel_function(B,fn1_sboxes[2],fn1_subkeys[2]);
596
597   // 4th round
598   B = B ^ feistel_function(A,fn1_sboxes[3],fn1_subkeys[3]);
599
600   middle_result = (B<<8)|A;
601
602
603   /* Middle-result-key sheduling */
604   for (j=0; j<16; ++j) {
605      if (BIT(middle_result,j)!=0) {
606         aux = fn2_middle_result_scheduling[j]%24;
607         aux2 = fn2_middle_result_scheduling[j]/24;
608         fn2_subkeys[aux2] ^= (1<<aux);
609      }
610   }
611   /*********************/
612
613   // Second Feistel Network
614
615   aux = BITSWAP16(data,14,3,8,12,13,7,15,4,    6,2,9,5,11,0,1,10);
616
617   // 1st round
618   B = aux >> 8;
619   A = (aux & 0xff) ^ feistel_function(B,fn2_sboxes[0],fn2_subkeys[0]);
620
621   // 2nd round
622   B = B ^ feistel_function(A,fn2_sboxes[1],fn2_subkeys[1]);
623
624   // 3rd round
625   A = A ^ feistel_function(B,fn2_sboxes[2],fn2_subkeys[2]);
626
627   // 4th round
628   B = B ^ feistel_function(A,fn2_sboxes[3],fn2_subkeys[3]);
629
630   aux = (B<<8)|A;
631
632   aux = BITSWAP16(aux,15,7,6,14,13,12,5,4,    3,2,11,10,9,1,0,8);
633
634   return aux;
635}
636
637UINT16 sega_315_5881_crypt_device::get_decrypted_16()
638{
639   UINT16 enc;
640
641   enc = m_read(prot_cur_address);
642
643   UINT16 dec = block_decrypt(key, subkey, prot_cur_address, enc);
644   UINT16 res = (dec & 3) | (dec_hist & 0xfffc);
645   dec_hist = dec;
646
647   prot_cur_address ++;
648   return res;
649}
650
651void sega_315_5881_crypt_device::enc_start()
652{
653   buffer_pos = BUFFER_SIZE;
654   dec_header = get_decrypted_16() << 16;
655   dec_header |= get_decrypted_16();
656
657   if(dec_header & FLAG_COMPRESSED) {
658      line_buffer_size = dec_header & FLAG_LINE_SIZE_512 ? 512 : 256;
659      line_buffer_pos = line_buffer_size;
660      buffer_bit = 7;
661   }
662   enc_ready = true;
663}
664
665void sega_315_5881_crypt_device::enc_fill()
666{
667   assert(buffer_pos == BUFFER_SIZE);
668   for(int i = 0; i != BUFFER_SIZE; i+=2) {
669      UINT16 val = get_decrypted_16();
670      buffer[i] = val;
671      buffer[i+1] = val >> 8;
672   }
673   buffer_pos = 0;
674}
675
676/* node format
6770xxxxxxx - next node index
6781a0bbccc - end node
679           a - 0 = repeat
680               1 = fetch
681           b - if a = 1
682               00 - fetch  0
683               01 - fetch  1
684               11 - fetch -1
685               if a = 0
686               000
687           c - repeat/fetch counter
688               count = ccc + 1
68911111111 - empty node
690*/
691const UINT8 sega_315_5881_crypt_device::trees[9][2][32] = {
692   {
693      {0x01,0x10,0x0f,0x05,0xc4,0x13,0x87,0x0a,0xcc,0x81,0xce,0x0c,0x86,0x0e,0x84,0xc2,
694         0x11,0xc1,0xc3,0xcf,0x15,0xc8,0xcd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
695      {0xc7,0x02,0x03,0x04,0x80,0x06,0x07,0x08,0x09,0xc9,0x0b,0x0d,0x82,0x83,0x85,0xc0,
696         0x12,0xc6,0xc5,0x14,0x16,0xca,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
697   },
698   {
699      {0x02,0x80,0x05,0x04,0x81,0x10,0x15,0x82,0x09,0x83,0x0b,0x0c,0x0d,0xdc,0x0f,0xde,
700         0x1c,0xcf,0xc5,0xdd,0x86,0x16,0x87,0x18,0x19,0x1a,0xda,0xca,0xc9,0x1e,0xce,0xff,},
701      {0x01,0x17,0x03,0x0a,0x08,0x06,0x07,0xc2,0xd9,0xc4,0xd8,0xc8,0x0e,0x84,0xcb,0x85,
702         0x11,0x12,0x13,0x14,0xcd,0x1b,0xdb,0xc7,0xc0,0xc1,0x1d,0xdf,0xc3,0xc6,0xcc,0xff,},
703   },
704   {
705      {0xc6,0x80,0x03,0x0b,0x05,0x07,0x82,0x08,0x15,0xdc,0xdd,0x0c,0xd9,0xc2,0x14,0x10,
706         0x85,0x86,0x18,0x16,0xc5,0xc4,0xc8,0xc9,0xc0,0xcc,0xff,0xff,0xff,0xff,0xff,0xff,},
707      {0x01,0x02,0x12,0x04,0x81,0x06,0x83,0xc3,0x09,0x0a,0x84,0x11,0x0d,0x0e,0x0f,0x19,
708         0xca,0xc1,0x13,0xd8,0xda,0xdb,0x17,0xde,0xcd,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,},
709   },
710   {
711      {0x01,0x80,0x0d,0x04,0x05,0x15,0x83,0x08,0xd9,0x10,0x0b,0x0c,0x84,0x0e,0xc0,0x14,
712         0x12,0xcb,0x13,0xca,0xc8,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
713      {0xc5,0x02,0x03,0x07,0x81,0x06,0x82,0xcc,0x09,0x0a,0xc9,0x11,0xc4,0x0f,0x85,0xd8,
714         0xda,0xdb,0xc3,0xdc,0xdd,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
715   },
716   {
717      {0x01,0x80,0x06,0x0c,0x05,0x81,0xd8,0x84,0x09,0xdc,0x0b,0x0f,0x0d,0x0e,0x10,0xdb,
718         0x11,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
719      {0xc4,0x02,0x03,0x04,0xcb,0x0a,0x07,0x08,0xd9,0x82,0xc8,0x83,0xc0,0xc1,0xda,0xc2,
720         0xc9,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
721   },
722   {
723      {0x01,0x02,0x06,0x0a,0x83,0x0b,0x07,0x08,0x09,0x82,0xd8,0x0c,0xd9,0xda,0xff,0xff,
724         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
725      {0xc3,0x80,0x03,0x04,0x05,0x81,0xca,0xc8,0xdb,0xc9,0xc0,0xc1,0x0d,0xc2,0xff,0xff,
726         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
727   },
728   {
729      {0x01,0x02,0x03,0x04,0x81,0x07,0x08,0xd8,0xda,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,
730         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
731      {0xc2,0x80,0x05,0xc9,0xc8,0x06,0x82,0xc0,0x09,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,
732         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
733   },
734   {
735      {0x01,0x80,0x04,0xc8,0xc0,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
736         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
737      {0xc1,0x02,0x03,0x81,0x05,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
738         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
739   },
740   {
741      {0x01,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
742         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
743      {0xc0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
744         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
745   },
746};
747
748int sega_315_5881_crypt_device::get_compressed_bit()
749{
750   if(buffer_pos == BUFFER_SIZE)
751      enc_fill();
752   int res = (buffer[buffer_pos^1] >> buffer_bit) & 1;
753   buffer_bit--;
754   if(buffer_bit == -1) {
755      buffer_bit = 7;
756      buffer_pos++;
757   }
758   return res;
759}
760
761void sega_315_5881_crypt_device::line_fill()
762{
763   assert(line_buffer_pos == line_buffer_size);
764   UINT8 *lp = line_buffer;
765   UINT8 *lc = line_buffer_prev;
766   line_buffer = lc;
767   line_buffer_prev = lp;
768   line_buffer_pos = 0;
769
770   UINT32 line_buffer_mask = line_buffer_size-1;
771
772   for(int i=0; i != line_buffer_size;) {
773      // vlc 0: start of line
774      // vlc 1: interior of line
775      // vlc 2-9: 7-1 bytes from end of line
776
777      int slot = i ? i < line_buffer_size - 7 ? 1 : (i & 7) + 1 : 0;
778
779      UINT32 tmp = 0;
780      while (!(tmp&0x80))
781         if(get_compressed_bit())
782            tmp = trees[slot][1][tmp];
783         else
784            tmp = trees[slot][0][tmp];
785      if(tmp != 0xff) {
786         int count = (tmp & 7) + 1;
787
788         if(tmp&0x40) {
789            // Copy from previous line
790
791            static int offsets[4] = {0, 1, 0, -1};
792            int offset = offsets[(tmp & 0x18) >> 3];
793            for(int j=0; j != count; j++) {
794               lc[i^1] = lp[((i+offset) & line_buffer_mask)^1];
795               i++;
796            }
797
798         } else {
799            // Get a byte in the stream and write n times
800            UINT8 byte;
801            byte =         get_compressed_bit()  << 1;
802            byte = (byte | get_compressed_bit()) << 1;
803            byte = (byte | get_compressed_bit()) << 1;
804            byte = (byte | get_compressed_bit()) << 1;
805            byte = (byte | get_compressed_bit()) << 1;
806            byte = (byte | get_compressed_bit()) << 1;
807            byte = (byte | get_compressed_bit()) << 1;
808            byte =  byte | get_compressed_bit();
809            for(int j=0; j != count; j++)
810               lc[(i++)^1] = byte;
811
812         }
813      }
814   }
815}
No newline at end of file
trunk/src/mame/machine/315-5881_crypt.h
r0r241644
1
2#pragma once
3
4#ifndef __SEGA315_5881_CRYPT__
5#define __SEGA315_5881_CRYPT__
6
7typedef device_delegate<UINT16 (UINT32)> sega_m2_read_delegate;
8
9extern const device_type SEGA315_5881_CRYPT;
10
11#define MCFG_SET_READ_CALLBACK( _class, _method) \
12   sega_315_5881_crypt_device::set_read_cb(*device, sega_m2_read_delegate(&_class::_method, #_class "::" #_method, NULL, (_class *)0));
13
14
15class sega_315_5881_crypt_device :  public device_t
16{
17public:
18   // construction/destruction
19   sega_315_5881_crypt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
20   
21
22   void do_decrypt(UINT8 *&base);
23   void set_addr_low(UINT16 data);
24   void set_addr_high(UINT16 data);
25   void set_subkey(UINT16 data);
26   void set_key(UINT32 data);
27
28   sega_m2_read_delegate m_read;
29
30   static void set_read_cb(device_t &device,sega_m2_read_delegate readcb)
31   {
32      sega_315_5881_crypt_device &dev = downcast<sega_315_5881_crypt_device &>(device);
33      dev.m_read = readcb;
34   }
35
36protected:
37   virtual void device_start();
38   virtual void device_reset();
39
40private:
41
42   enum {
43      BUFFER_SIZE = 32768, LINE_SIZE = 512,
44      FLAG_COMPRESSED = 0x10000, FLAG_LINE_SIZE_512 = 0x20000
45   };
46
47   UINT32 key;
48
49   UINT8 *buffer, *line_buffer, *line_buffer_prev;
50   UINT32 prot_cur_address;
51   UINT16 subkey, dec_hist;
52   UINT32 dec_header;
53
54   bool enc_ready;
55
56   int buffer_pos, line_buffer_pos, line_buffer_size, buffer_bit;
57
58   struct sbox {
59      UINT8 table[64];
60      int inputs[6];      // positions of the inputs bits, -1 means no input except from key
61      int outputs[2];     // positions of the output bits
62   };
63
64   static const sbox fn1_sboxes[4][4];
65   static const sbox fn2_sboxes[4][4];
66
67   static const int fn1_game_key_scheduling[38][2];
68   static const int fn2_game_key_scheduling[34][2];
69   static const int fn1_sequence_key_scheduling[20][2];
70   static const int fn2_sequence_key_scheduling[16];
71   static const int fn2_middle_result_scheduling[16];
72
73   static const UINT8 trees[9][2][32];
74
75   int feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys);
76   UINT16 block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data);
77
78   UINT16 get_decrypted_16();
79   int get_compressed_bit();
80
81   void enc_start();
82   void enc_fill();
83   void line_fill();
84
85};
86
87#endif
trunk/src/mame/machine/naomim2.c
r241643r241644
105105const device_type NAOMI_M2_BOARD = &device_creator<naomi_m2_board>;
106106
107107naomi_m2_board::naomi_m2_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
108   : naomi_board(mconfig, NAOMI_M2_BOARD, "Sega NAOMI M2 BOARD", tag, owner, clock, "naomi_m2_board", __FILE__)
108   : naomi_board(mconfig, NAOMI_M2_BOARD, "Sega NAOMI M2 BOARD", tag, owner, clock, "naomi_m2_board", __FILE__),
109   m_cryptdevice(*this, "segam2crypt")
109110{
110111   key_tag = 0;
111112}
r241643r241644
120121{
121122   naomi_board::device_start();
122123
123#if USE_NAOMICRYPT
124   key = get_naomi_key(machine());
125#else
126   const UINT8 *key_data = memregion(key_tag)->base();
127   key = (key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | key_data[3];
128#endif
129124   ram = auto_alloc_array(machine(), UINT8, RAM_SIZE);
130   buffer = auto_alloc_array(machine(), UINT8, BUFFER_SIZE);
131   line_buffer = auto_alloc_array(machine(), UINT8, LINE_SIZE);
132   line_buffer_prev = auto_alloc_array(machine(), UINT8, LINE_SIZE);
133125
134   save_pointer(NAME(ram), RAM_SIZE);
135   save_pointer(NAME(buffer), BUFFER_SIZE);
136   save_pointer(NAME(line_buffer), LINE_SIZE);
137   save_pointer(NAME(line_buffer_prev), LINE_SIZE);
138126   save_item(NAME(rom_cur_address));
139   save_item(NAME(prot_cur_address));
140   save_item(NAME(subkey));
141   save_item(NAME(enc_ready));
142   save_item(NAME(dec_hist));
143   save_item(NAME(dec_header));
144   save_item(NAME(buffer_pos));
145   save_item(NAME(line_buffer_pos));
146   save_item(NAME(line_buffer_size));
127   save_pointer(NAME(ram), RAM_SIZE);
147128}
148129
149130void naomi_m2_board::device_reset()
r241643r241644
151132   naomi_board::device_reset();
152133
153134   memset(ram, 0, RAM_SIZE);
154   memset(buffer, 0, BUFFER_SIZE);
155   memset(line_buffer, 0, LINE_SIZE);
156   memset(line_buffer_prev, 0, LINE_SIZE);
157135
158136   rom_cur_address = 0;
159   prot_cur_address = 0;
160   subkey = 0;
161   dec_hist = 0;
162   dec_header = 0;
163   enc_ready = false;
164137
165   buffer_pos = 0;
166   line_buffer_pos = 0;
167   line_buffer_size = 0;
168   buffer_bit = 0;
138#if USE_NAOMICRYPT
139   m_cryptdevice->set_key(get_naomi_key(machine()));
140#else
141   const UINT8 *key_data = memregion(key_tag)->base();
142   m_cryptdevice->set_key((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | key_data[3]);
143#endif
169144}
170145
171146void naomi_m2_board::board_setup_address(UINT32 address, bool is_dma)
r241643r241644
175150
176151void naomi_m2_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
177152{
153
178154   if(rom_cur_address & 0x40000000) {
179155      if(rom_cur_address == 0x4001fffe) {
180         if(!enc_ready)
181            enc_start();
182         if(dec_header & FLAG_COMPRESSED) {
183            if(line_buffer_pos == line_buffer_size)
184               line_fill();
185            base = line_buffer + line_buffer_pos;
186            line_buffer_pos += 2;
187         } else {
188            if(buffer_pos == BUFFER_SIZE)
189               enc_fill();
190            base = buffer + buffer_pos;
191            buffer_pos += 2;
192         }
156         m_cryptdevice->do_decrypt(base);
193157         limit = 2;
194158
195159      } else
r241643r241644
214178
215179void naomi_m2_board::board_write(offs_t offset, UINT16 data)
216180{
181
182
217183   if(offset & 0x40000000) {
218184      if((offset & 0x0f000000) == 0x02000000) {
219185         offset &= RAM_SIZE-1;
r241643r241644
222188         return;
223189      }
224190      switch(offset & 0x1fffffff) {
225      case 0x1fff8: prot_cur_address = (prot_cur_address & 0xffff0000) | data; enc_ready = false; return;
226      case 0x1fffa: prot_cur_address = (prot_cur_address & 0x0000ffff) | (data << 16); enc_ready = false; return;
227      case 0x1fffc: subkey = data; enc_ready = false; return;
191
192      case 0x1fff8: m_cryptdevice->set_addr_low(data); return;
193      case 0x1fffa: m_cryptdevice->set_addr_high(data);  return;
194      case 0x1fffc: m_cryptdevice->set_subkey(data); return;
228195      }
229196   }
230197   throw emu_fatalerror("NAOMIM2: unhandled board write %08x, %04x\n", offset, data);
231198}
232199
233/***************************************************************************
234    DECRYPTION EMULATION
235
236By convention, we label the three known cart protection methods this way (using Deunan Knute's wording):
237M1: DMA read of protected ROM area
238M2: special read of ROM area which supplies decryption key first
239M3: normal read followed by write to cart's decryption buffer (up to 64kB), followed by M2 but from buffer area
240
241Notes below refer to M2 & M3.
242
243The encryption is done by a stream cipher operating in counter mode, which use a 16-bits internal block cipher.
244
245There are 2 "control bits" at the start of the decrypted stream which control the mode of operation: bit #1 set to 1 means
246that the decrypted stream needs to be decompressed after being decrypted. More on this later.
247
248The next 16-bits are part of the header (they don't belong to the plaintext), but his meaning is unclear. It has been
249conjectured that it could stablish when to "reset" the process and start processing a new stream (based on some tests
250on WWFROYAL, in which the decryption's output doesn't seem to be valid for more than some dozens of words), but some
251more testing would be needed for clarifying that.
252
253After those 18 heading bits, we find the proper plaintext. It must be noted that, due to the initial 2 special bits,
254the 16-bits words of the plaintext are shifted 2 bits respect to the word-boundaries of the output stream of the
255internal block-cipher. So, at a given step, the internal block cipher will output 16-bits, 14 of which will go to a
256given plaintext word, and the remaining 2 to the next plaintext word.
257
258The underlying block cipher consists of two 4-round Feistel Networks (FN): the first one takes the counter (16 bits),
259the game-key (>=26 bits) and the sequence-key (16 bits) and output a middle result (16 bits) which will act as another key
260for the second one. The second FN will take the encrypted word (16 bits), the game-key, the sequence-key and the result
261from the first FN and will output the decrypted word (16 bits).
262
263Each round of the Feistel Networks use four substitution sboxes, each having 6 inputs and 2 outputs. The input can be the
264XOR of at most two "sources bits", being source bits the bits from the previous round and the bits from the different keys.
265
266The underlying block cipher has the same structure than the one used by the CPS-2 (Capcom Play System 2) and,
267indeed, some of the used sboxes are exactly the same and appear in the same FN/round in both systems (this is not evident,
268as you need to apply a bitswapping and some XORs to the input & output of the sboxes to get the same values due). However,
269the key scheduling used by this implementation is much weaker than the CPS-2's one. Many s-boxes inputs aren't XORed with any
270key bit.
271
272Due to the small key-length, no sophisticated attacks are needed to recover the keys; a brute-force attack knowing just
273some (encrypted word-decrypted word) pairs suffice. However, due to the weak key scheduling, it should be noted that some
274related keys can produce the same output bytes for some (short) input sequences.
275
276The only difference in the decryption process between M2 and M3 is the initialization of the counter. In M3, the counter is
277always set to 0 at the beginning of the decryption while, in M2, the bits #1-#16 of the ciphertext's address are used
278to initialize the counter.
279
280Note that this implementation considers that the counter initialization for ram decryption is 0 simply because the ram is
281mapped to multiples of 128K.
282
283Due to the nature of the cipher, there are some degrees of freedom when choosing the s-boxes and keys values; by example,
284you could apply a fixed bitswapping and XOR to the keys and the decryption would remain the same as long as you change
285accordingly the s-boxes' definitions. So the order of the bits in the keys is arbitrary, and the s-boxes values have been
286chosen so as to make the key for CAPSNK equal to 0.
287
288It can be observed that a couple of sboxes have incomplete tables (a 255 value indicate an unknown value). The recovered keys
289as of december/2010 show small randomness and big correlations, making possible that some unseen bits could make the
290decryption need those incomplete parts.
291
292****************************************************************************************/
293
294const naomi_m2_board::sbox naomi_m2_board::fn1_sboxes[4][4] = {
295   {   // 1st round
296      {
297         {
298            0,3,2,2,1,3,1,2,3,2,1,2,1,2,3,1,3,2,2,0,2,1,3,0,0,3,2,3,2,1,2,0,
299            2,3,1,1,2,2,1,1,1,0,2,3,3,0,2,1,1,1,1,1,3,0,3,2,1,0,1,2,0,3,1,3,
300         },
301         {3,4,5,7,-1,-1},
302         {0,4}
303      },
304
305      {
306         {
307            2,2,2,0,3,3,0,1,2,2,3,2,3,0,2,2,1,1,0,3,3,2,0,2,0,1,0,1,2,3,1,1,
308            0,1,3,3,1,3,3,1,2,3,2,0,0,0,2,2,0,3,1,3,0,3,2,2,0,3,0,3,1,1,0,2,
309         },
310         {0,1,2,5,6,7},
311         {1,6}
312      },
313
314      {
315         {
316            0,1,3,0,3,1,1,1,1,2,3,1,3,0,2,3,3,2,0,2,1,1,2,1,1,3,1,0,0,2,0,1,
317            1,3,1,0,0,3,2,3,2,0,3,3,0,0,0,0,1,2,3,3,2,0,3,2,1,0,0,0,2,2,3,3,
318         },
319         {0,2,5,6,7,-1},
320         {2,3}
321      },
322
323      {
324         {
325            3,2,1,2,1,2,3,2,0,3,2,2,3,1,3,3,0,2,3,0,3,3,2,1,1,1,2,0,2,2,0,1,
326            1,3,3,0,0,3,0,3,0,2,1,3,2,1,0,0,0,1,1,2,0,1,0,0,0,1,3,3,2,0,3,3,
327         },
328         {1,2,3,4,6,7},
329         {5,7}
330      },
331   },
332   {   // 2nd round
333      {
334         {
335            3,3,1,2,0,0,2,2,2,1,2,1,3,1,1,3,3,0,0,3,0,3,3,2,1,1,3,2,3,2,1,3,
336            2,3,0,1,3,2,0,1,2,1,3,1,2,2,3,3,3,1,2,2,0,3,1,2,2,1,3,0,3,0,1,3,
337         },
338         {0,1,3,4,5,7},
339         {0,4}
340      },
341
342      {
343         {
344            2,0,1,0,0,3,2,0,3,3,1,2,1,3,0,2,0,2,0,0,0,2,3,1,3,1,1,2,3,0,3,0,
345            3,0,2,0,0,2,2,1,0,2,3,3,1,3,1,0,1,3,3,0,0,1,3,1,0,2,0,3,2,1,0,1,
346         },
347         {0,1,3,4,6,-1},
348         {1,5}
349      },
350
351      {
352         {
353            2,2,2,3,1,1,0,1,0,1,2,2,3,3,0,2,0,3,2,3,3,0,2,1,0,3,1,0,0,2,3,2,
354            3,2,0,3,2,0,1,0,3,3,1,1,2,2,2,0,2,1,3,1,1,1,1,2,2,2,3,0,1,3,0,0,
355         },
356         {1,2,5,6,7,-1},
357         {2,7}
358      },
359
360      {
361         {
362            0,1,3,3,3,1,3,3,1,0,2,0,2,0,0,3,1,2,1,3,1,2,3,2,2,0,1,3,0,3,3,3,
363            0,0,0,2,1,1,2,3,2,2,3,1,1,2,0,2,0,2,1,3,1,1,3,3,1,1,3,0,2,3,0,0,
364         },
365         {2,3,4,5,6,7},
366         {3,6}
367      },
368   },
369   {   // 3rd round
370      {
371         {
372            0,0,1,0,1,0,0,3,2,0,0,3,0,1,0,2,0,3,0,0,2,0,3,2,2,1,3,2,2,1,1,2,
373            0,0,0,3,0,1,1,0,0,2,1,0,3,1,2,2,2,0,3,1,3,0,1,2,2,1,1,1,0,2,3,1,
374         },
375         {1,2,3,4,5,7},
376         {0,5}
377      },
378
379      {
380         {
381            1,2,1,0,3,1,1,2,0,0,2,3,2,3,1,3,2,0,3,2,2,3,1,1,1,1,0,3,2,0,0,1,
382            1,0,0,1,3,1,2,3,0,0,2,3,3,0,1,0,0,2,3,0,1,2,0,1,3,3,3,1,2,0,2,1,
383         },
384         {0,2,4,5,6,7},
385         {1,6}
386      },
387
388      {
389         {
390            0,3,0,2,1,2,0,0,1,1,0,0,3,1,1,0,0,3,0,0,2,3,3,2,3,1,2,0,0,2,3,0,
391            // unused?
392            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
393         },
394         {0,2,4,6,7,-1},
395         {2,3}
396      },
397
398      {
399         {
400            0,0,1,0,0,1,0,2,3,3,0,3,3,2,3,0,2,2,2,0,3,2,0,3,1,0,0,3,3,0,0,0,
401            2,2,1,0,2,0,3,2,0,0,3,1,3,3,0,0,2,1,1,2,1,0,1,1,0,3,1,2,0,2,0,3,
402         },
403         {0,1,2,3,6,-1},
404         {4,7}
405      },
406   },
407   {   // 4th round
408      {
409         {
410            0,3,3,3,3,3,2,0,0,1,2,0,2,2,2,2,1,1,0,2,2,1,3,2,3,2,0,1,2,3,2,1,
411            3,2,2,3,1,0,1,0,0,2,0,1,2,1,2,3,1,2,1,1,2,2,1,0,1,3,2,3,2,0,3,1,
412         },
413         {0,1,3,4,5,6},
414         {0,5}
415      },
416
417      {
418         {
419            0,3,0,0,2,0,3,1,1,1,2,2,2,1,3,1,2,2,1,3,2,2,3,3,0,3,1,0,3,2,0,1,
420            3,0,2,0,1,0,2,1,3,3,1,2,2,0,2,3,3,2,3,0,1,1,3,3,0,2,1,3,0,2,2,3,
421         },
422         {0,1,2,3,5,7},
423         {1,7}
424      },
425
426      {
427         {
428            0,1,2,3,3,3,3,1,2,0,2,3,2,1,0,1,2,2,1,2,0,3,2,0,1,1,0,1,3,1,3,1,
429            3,1,0,0,1,0,0,0,0,1,2,2,1,1,3,3,1,2,3,3,3,2,3,0,2,2,1,3,3,0,2,0,
430         },
431         {2,3,4,5,6,7},
432         {2,3}
433      },
434
435      {
436         {
437            0,2,1,1,3,2,0,3,1,0,1,0,3,2,1,1,2,2,0,3,1,0,1,2,2,2,3,3,0,0,0,0,
438            1,2,1,0,2,1,2,2,2,3,2,3,0,1,3,0,0,1,3,0,0,1,1,0,1,0,0,0,0,2,0,1,
439         },
440         {0,1,2,4,6,7},
441         {4,6}
442      },
443   },
444};
445
446
447const naomi_m2_board::sbox naomi_m2_board::fn2_sboxes[4][4] = {
448   {   // 1st round
449      {
450         {
451            3,3,0,1,0,1,0,0,0,3,0,0,1,3,1,2,0,3,3,3,2,1,0,1,1,1,2,2,2,3,2,2,
452            2,1,3,3,1,3,1,1,0,0,1,2,0,2,2,1,1,2,3,1,2,1,3,1,2,2,0,1,3,0,2,2,
453         },
454         {1,3,4,5,6,7},
455         {0,7}
456      },
457
458      {
459         {
460            0,2,3,2,1,1,0,0,2,1,0,3,3,0,0,0,3,2,0,2,1,1,2,1,0,0,3,1,2,2,3,1,
461            3,1,3,0,0,0,1,3,1,0,0,3,2,2,3,1,1,3,0,0,2,1,3,3,1,3,1,2,3,1,2,1,
462         },
463         {0,3,5,6,-1,-1},
464         {1,2}
465      },
466
467      {
468         {
469            0,2,2,1,0,1,2,1,2,0,1,2,3,3,0,1,3,1,1,2,1,2,1,3,3,2,3,3,2,1,0,1,
470            0,1,0,2,0,1,1,3,2,0,3,2,1,1,1,3,2,3,0,2,3,0,2,2,1,3,0,1,1,2,2,2,
471         },
472         {0,2,3,4,7,-1},
473         {3,4}
474      },
475
476      {
477         {
478            2,3,1,3,2,0,1,2,0,0,3,3,3,3,3,1,2,0,2,1,2,3,0,2,0,1,0,3,0,2,1,0,
479            2,3,0,1,3,0,3,2,3,1,2,0,3,1,1,2,0,3,0,0,2,0,2,1,2,2,3,2,1,2,3,1,
480         },
481         {1,2,5,6,-1,-1},
482         {5,6}
483      },
484   },
485   {   // 2nd round
486      {
487         {
488            2,3,1,3,1,0,3,3,3,2,3,3,2,0,0,3,2,3,0,3,1,1,2,3,1,1,2,2,0,1,0,0,
489            2,1,0,1,2,0,1,2,0,3,1,1,2,3,1,2,0,2,0,1,3,0,1,0,2,2,3,0,3,2,3,0,
490         },
491         {0,1,4,5,6,7},
492         {0,7}
493      },
494
495      {
496         {
497            0,2,2,0,2,2,0,3,2,3,2,1,3,2,3,3,1,1,0,0,3,0,2,1,1,3,3,2,3,2,0,1,
498            1,2,3,0,1,0,3,0,3,1,0,2,1,2,0,3,2,3,1,2,2,0,3,2,3,0,0,1,2,3,3,3,
499         },
500         {0,2,3,6,7,-1},
501         {1,5}
502      },
503
504      {
505         {
506            1,2,3,2,0,3,2,3,0,1,1,0,0,2,2,3,2,0,0,3,0,2,3,3,2,2,1,0,2,1,0,3,
507            1,0,2,0,1,1,0,1,0,0,1,0,3,0,3,3,2,2,0,2,1,1,1,0,3,0,1,3,2,3,2,1,
508         },
509         {2,3,4,6,7,-1},
510         {2,3}
511      },
512
513      {
514         {
515            2,3,1,3,1,1,2,3,3,1,1,0,1,0,2,3,2,1,0,0,2,2,0,1,0,2,2,2,0,2,1,0,
516            3,1,2,3,1,3,0,2,1,0,1,0,0,1,2,2,3,2,3,1,3,2,1,1,2,0,2,1,3,3,1,0,
517         },
518         {1,2,3,4,5,6},
519         {4,6}
520      },
521   },
522   {   // 3rd round
523      {
524         {
525            0,3,0,1,0,2,3,3,1,0,1,3,2,2,1,1,3,3,3,0,2,0,2,0,0,0,2,3,1,1,0,0,
526            3,3,0,3,3,0,0,2,1,1,1,0,2,2,2,0,3,0,3,1,2,2,0,3,0,0,3,2,0,3,2,1,
527         },
528         {1,4,5,6,7,-1},
529         {0,5}
530      },
531
532      {
533         {
534            0,3,0,1,3,0,3,1,3,2,2,2,3,0,3,2,2,1,2,2,0,3,2,2,0,0,2,1,1,3,2,3,
535            2,3,3,1,2,0,1,2,2,1,0,0,0,0,2,3,1,2,0,3,1,3,1,2,3,2,1,0,3,0,0,2,
536         },
537         {0,2,3,4,6,7},
538         {1,7}
539      },
540
541      {
542         {
543            2,2,3,2,0,3,2,3,1,1,2,0,2,3,1,3,0,0,0,3,2,0,1,0,1,3,2,3,3,3,1,0,
544            // unused?
545            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
546         },
547         {1,2,4,7,-1,-1},
548         {2,4}
549      },
550
551      {
552         {
553            0,2,3,1,3,1,1,0,0,1,3,0,2,1,3,3,2,0,2,1,1,2,3,3,0,0,0,2,0,2,3,0,
554            3,3,3,3,2,3,3,2,3,0,1,0,2,3,3,2,0,1,3,1,0,1,2,3,3,0,2,0,3,0,3,3,
555         },
556         {0,1,2,3,5,7},
557         {3,6}
558      },
559   },
560   {   // 4th round
561      {
562         {
563            0,1,1,0,0,1,0,2,3,3,0,1,2,3,0,2,1,0,3,3,2,0,3,0,0,2,1,0,1,0,1,3,
564            0,3,3,1,2,0,3,0,1,3,2,0,3,3,1,3,0,2,3,3,2,1,1,2,2,1,2,1,2,0,1,1,
565         },
566         {0,1,2,4,7,-1},
567         {0,5}
568      },
569
570      {
571         {
572            2,0,0,2,3,0,2,3,3,1,1,1,2,1,1,0,0,2,1,0,0,3,1,0,0,3,3,0,1,0,1,2,
573            0,2,0,2,0,1,2,3,2,1,1,0,3,3,3,3,3,3,1,0,3,0,0,2,0,3,2,0,2,2,0,1,
574         },
575         {0,1,3,5,6,-1},
576         {1,3}
577      },
578
579      {
580         {
581            0,1,1,2,1,3,1,1,0,0,3,1,1,1,2,0,3,2,0,1,1,2,3,3,3,0,3,0,0,2,0,3,
582            3,2,0,0,3,2,3,1,2,3,0,3,2,0,1,2,2,2,0,2,0,1,2,2,3,1,2,2,1,1,1,1,
583         },
584         {0,2,3,4,5,7},
585         {2,7}
586      },
587
588      {
589         {
590            0,1,2,0,3,3,0,3,2,1,3,3,0,3,1,1,3,2,3,2,3,0,0,0,3,0,2,2,3,2,2,3,
591            2,2,3,1,2,3,1,2,0,3,0,2,3,1,0,0,3,2,1,2,1,2,1,3,1,0,2,3,3,1,3,2,
592         },
593         {2,3,4,5,6,7},
594         {4,6}
595      },
596   },
597};
598
599const int naomi_m2_board::fn1_game_key_scheduling[38][2] = {
600   {1,29},  {1,71},  {2,4},   {2,54},  {3,8},   {4,56},  {4,73},  {5,11},
601   {6,51},  {7,92},  {8,89},  {9,9},   {9,10},  {9,39},  {9,41},  {9,58},
602   {9,59},  {9,86},  {10,90}, {11,6},  {12,64}, {13,49}, {14,44}, {15,40},
603   {16,69}, {17,15}, {18,23}, {18,43}, {19,82}, {20,81}, {21,32}, {21,61},
604   {22,5},  {23,66}, {24,13}, {24,45}, {25,12}, {25,35}
605};
606
607const int naomi_m2_board::fn2_game_key_scheduling[34][2] = {
608   {0,0},   {1,3},   {2,11},  {3,20},  {4,22},  {5,23},  {6,29},  {7,38},
609   {8,39},  {9,47},  {9,55},  {9,86},  {9,87},  {9,90},  {10,50}, {10,53},
610   {11,57}, {12,59}, {13,61}, {13,64}, {14,63}, {15,67}, {16,72}, {17,83},
611   {18,88}, {19,94}, {20,35}, {21,17}, {21,92}, {22,6},  {22,11}, {23,85},
612   {24,16}, {25,25}
613};
614
615const int naomi_m2_board::fn1_sequence_key_scheduling[20][2] = {
616   {0,52},  {1,34},  {2,17},  {3,36}, {4,84},  {4,88},  {5,57},  {6,48},
617   {6,68},  {7,76},  {8,83},  {9,30}, {10,22}, {10,41}, {11,38}, {12,55},
618   {13,74}, {14,19}, {14,80}, {15,26}
619};
620
621const int naomi_m2_board::fn2_sequence_key_scheduling[16] = {77,34,8,42,36,27,69,66,13,9,79,31,49,7,24,64};
622
623const int naomi_m2_board::fn2_middle_result_scheduling[16] = {1,10,44,68,74,78,81,95,2,4,30,40,41,51,53,58};
624
625int naomi_m2_board::feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys)
200UINT16 naomi_m2_board::read_callback(UINT32 addr)
626201{
627   int k,m;
628   int aux;
629   int result=0;
202   if ((addr & 0xffff0000) == 0x01000000) {
203      int base = 2*(addr & 0x7fff);
204      return ram[base+1] | (ram[base] << 8);
630205
631   for (m=0; m<4; ++m) { // 4 sboxes
632      for (k=0, aux=0; k<6; ++k)
633         if (sboxes[m].inputs[k]!=-1)
634            aux |= BIT(input, sboxes[m].inputs[k]) << k;
635
636      aux = sboxes[m].table[(aux^subkeys)&0x3f];
637
638      for (k=0; k<2; ++k)
639         result |= BIT(aux,k) << sboxes[m].outputs[k];
640
641      subkeys >>=6;
642206   }
643
644   return result;
645}
646
647/**************************
648This implementation is an "educational" version. It must be noted that it can be speed-optimized in a number of ways.
649The most evident one is to factor out the parts of the key-scheduling that must only be done once (like the game-key &
650sequence-key parts) as noted in the comments inlined in the function. More sophisticated speed-ups can be gained by
651noticing that the weak key-scheduling would allow to create some pregenerated look-up tables for doing most of the work
652of the function. Even so, it would still be pretty slow, so caching techniques could be a wiser option here.
653**************************/
654
655UINT16 naomi_m2_board::block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data)
656{
657   int j;
658   int aux,aux2;
659   int A,B;
660   int middle_result;
661   UINT32 fn1_subkeys[4];
662   UINT32 fn2_subkeys[4];
663
664   /* Game-key scheduling; this could be done just once per game at initialization time */
665   memset(fn1_subkeys,0,sizeof(UINT32)*4);
666   memset(fn2_subkeys,0,sizeof(UINT32)*4);
667
668   for (j=0; j<38; ++j) {
669      if (BIT(game_key, fn1_game_key_scheduling[j][0])!=0) {
670         aux = fn1_game_key_scheduling[j][1]%24;
671         aux2 = fn1_game_key_scheduling[j][1]/24;
672         fn1_subkeys[aux2] ^= (1<<aux);
673      }
207   else {
208      const UINT8 *base = m_region->base() + 2*addr;
209      return base[1] | (base[0] << 8);
674210   }
675
676   for (j=0; j<34; ++j) {
677      if (BIT(game_key, fn2_game_key_scheduling[j][0])!=0) {
678         aux = fn2_game_key_scheduling[j][1]%24;
679         aux2 = fn2_game_key_scheduling[j][1]/24;
680         fn2_subkeys[aux2] ^= (1<<aux);
681      }
682   }
683   /********************************************************/
684
685   /* Sequence-key scheduling; this could be done just once per decryption run */
686   for (j=0; j<20; ++j) {
687      if (BIT(sequence_key,fn1_sequence_key_scheduling[j][0])!=0) {
688         aux = fn1_sequence_key_scheduling[j][1]%24;
689         aux2 = fn1_sequence_key_scheduling[j][1]/24;
690         fn1_subkeys[aux2] ^= (1<<aux);
691      }
692   }
693
694   for (j=0; j<16; ++j) {
695      if (BIT(sequence_key,j)!=0) {
696         aux = fn2_sequence_key_scheduling[j]%24;
697         aux2 = fn2_sequence_key_scheduling[j]/24;
698         fn2_subkeys[aux2] ^= (1<<aux);
699      }
700   }
701
702   // subkeys bits 10 & 41
703   fn2_subkeys[0] ^= (BIT(sequence_key,2)<<10);
704   fn2_subkeys[1] ^= (BIT(sequence_key,4)<<17);
705   /**************************************************************/
706
707   // First Feistel Network
708
709   aux = BITSWAP16(counter,5,12,14,13,9,3,6,4,    8,1,15,11,0,7,10,2);
710
711   // 1st round
712   B = aux >> 8;
713   A = (aux & 0xff) ^ feistel_function(B,fn1_sboxes[0],fn1_subkeys[0]);
714
715   // 2nd round
716   B = B ^ feistel_function(A,fn1_sboxes[1],fn1_subkeys[1]);
717
718   // 3rd round
719   A = A ^ feistel_function(B,fn1_sboxes[2],fn1_subkeys[2]);
720
721   // 4th round
722   B = B ^ feistel_function(A,fn1_sboxes[3],fn1_subkeys[3]);
723
724   middle_result = (B<<8)|A;
725
726
727   /* Middle-result-key sheduling */
728   for (j=0; j<16; ++j) {
729      if (BIT(middle_result,j)!=0) {
730         aux = fn2_middle_result_scheduling[j]%24;
731         aux2 = fn2_middle_result_scheduling[j]/24;
732         fn2_subkeys[aux2] ^= (1<<aux);
733      }
734   }
735   /*********************/
736
737   // Second Feistel Network
738
739   aux = BITSWAP16(data,14,3,8,12,13,7,15,4,    6,2,9,5,11,0,1,10);
740
741   // 1st round
742   B = aux >> 8;
743   A = (aux & 0xff) ^ feistel_function(B,fn2_sboxes[0],fn2_subkeys[0]);
744
745   // 2nd round
746   B = B ^ feistel_function(A,fn2_sboxes[1],fn2_subkeys[1]);
747
748   // 3rd round
749   A = A ^ feistel_function(B,fn2_sboxes[2],fn2_subkeys[2]);
750
751   // 4th round
752   B = B ^ feistel_function(A,fn2_sboxes[3],fn2_subkeys[3]);
753
754   aux = (B<<8)|A;
755
756   aux = BITSWAP16(aux,15,7,6,14,13,12,5,4,    3,2,11,10,9,1,0,8);
757
758   return aux;
759211}
760212
761UINT16 naomi_m2_board::get_decrypted_16()
762{
763   UINT16 enc;
213static MACHINE_CONFIG_FRAGMENT( naomim2 )
214   MCFG_DEVICE_ADD("segam2crypt", SEGA315_5881_CRYPT, 0)
215   MCFG_SET_READ_CALLBACK(naomi_m2_board, read_callback)
216MACHINE_CONFIG_END
764217
765   if((prot_cur_address & 0xffff0000) == 0x01000000) {
766      int base = 2*(prot_cur_address & 0x7fff);
767      enc = ram[base+1] | (ram[base] << 8);
768   } else {
769      const UINT8 *base = m_region->base() + 2*prot_cur_address;
770      enc = base[1] | (base[0] << 8);
771   }
772
773   UINT16 dec = block_decrypt(key, subkey, prot_cur_address, enc);
774   UINT16 res = (dec & 3) | (dec_hist & 0xfffc);
775   dec_hist = dec;
776
777   prot_cur_address ++;
778   return res;
779}
780
781void naomi_m2_board::enc_start()
218machine_config_constructor naomi_m2_board::device_mconfig_additions() const
782219{
783   buffer_pos = BUFFER_SIZE;
784   dec_header = get_decrypted_16() << 16;
785   dec_header |= get_decrypted_16();
786
787   if(dec_header & FLAG_COMPRESSED) {
788      line_buffer_size = dec_header & FLAG_LINE_SIZE_512 ? 512 : 256;
789      line_buffer_pos = line_buffer_size;
790      buffer_bit = 7;
791   }
792   enc_ready = true;
220   return MACHINE_CONFIG_NAME( naomim2 );
793221}
794222
795void naomi_m2_board::enc_fill()
796{
797   assert(buffer_pos == BUFFER_SIZE);
798   for(int i = 0; i != BUFFER_SIZE; i+=2) {
799      UINT16 val = get_decrypted_16();
800      buffer[i] = val;
801      buffer[i+1] = val >> 8;
802   }
803   buffer_pos = 0;
804}
805
806/* node format
8070xxxxxxx - next node index
8081a0bbccc - end node
809           a - 0 = repeat
810               1 = fetch
811           b - if a = 1
812               00 - fetch  0
813               01 - fetch  1
814               11 - fetch -1
815               if a = 0
816               000
817           c - repeat/fetch counter
818               count = ccc + 1
81911111111 - empty node
820*/
821const UINT8 naomi_m2_board::trees[9][2][32] = {
822   {
823      {0x01,0x10,0x0f,0x05,0xc4,0x13,0x87,0x0a,0xcc,0x81,0xce,0x0c,0x86,0x0e,0x84,0xc2,
824         0x11,0xc1,0xc3,0xcf,0x15,0xc8,0xcd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
825      {0xc7,0x02,0x03,0x04,0x80,0x06,0x07,0x08,0x09,0xc9,0x0b,0x0d,0x82,0x83,0x85,0xc0,
826         0x12,0xc6,0xc5,0x14,0x16,0xca,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
827   },
828   {
829      {0x02,0x80,0x05,0x04,0x81,0x10,0x15,0x82,0x09,0x83,0x0b,0x0c,0x0d,0xdc,0x0f,0xde,
830         0x1c,0xcf,0xc5,0xdd,0x86,0x16,0x87,0x18,0x19,0x1a,0xda,0xca,0xc9,0x1e,0xce,0xff,},
831      {0x01,0x17,0x03,0x0a,0x08,0x06,0x07,0xc2,0xd9,0xc4,0xd8,0xc8,0x0e,0x84,0xcb,0x85,
832         0x11,0x12,0x13,0x14,0xcd,0x1b,0xdb,0xc7,0xc0,0xc1,0x1d,0xdf,0xc3,0xc6,0xcc,0xff,},
833   },
834   {
835      {0xc6,0x80,0x03,0x0b,0x05,0x07,0x82,0x08,0x15,0xdc,0xdd,0x0c,0xd9,0xc2,0x14,0x10,
836         0x85,0x86,0x18,0x16,0xc5,0xc4,0xc8,0xc9,0xc0,0xcc,0xff,0xff,0xff,0xff,0xff,0xff,},
837      {0x01,0x02,0x12,0x04,0x81,0x06,0x83,0xc3,0x09,0x0a,0x84,0x11,0x0d,0x0e,0x0f,0x19,
838         0xca,0xc1,0x13,0xd8,0xda,0xdb,0x17,0xde,0xcd,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,},
839   },
840   {
841      {0x01,0x80,0x0d,0x04,0x05,0x15,0x83,0x08,0xd9,0x10,0x0b,0x0c,0x84,0x0e,0xc0,0x14,
842         0x12,0xcb,0x13,0xca,0xc8,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
843      {0xc5,0x02,0x03,0x07,0x81,0x06,0x82,0xcc,0x09,0x0a,0xc9,0x11,0xc4,0x0f,0x85,0xd8,
844         0xda,0xdb,0xc3,0xdc,0xdd,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
845   },
846   {
847      {0x01,0x80,0x06,0x0c,0x05,0x81,0xd8,0x84,0x09,0xdc,0x0b,0x0f,0x0d,0x0e,0x10,0xdb,
848         0x11,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
849      {0xc4,0x02,0x03,0x04,0xcb,0x0a,0x07,0x08,0xd9,0x82,0xc8,0x83,0xc0,0xc1,0xda,0xc2,
850         0xc9,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
851   },
852   {
853      {0x01,0x02,0x06,0x0a,0x83,0x0b,0x07,0x08,0x09,0x82,0xd8,0x0c,0xd9,0xda,0xff,0xff,
854         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
855      {0xc3,0x80,0x03,0x04,0x05,0x81,0xca,0xc8,0xdb,0xc9,0xc0,0xc1,0x0d,0xc2,0xff,0xff,
856         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
857   },
858   {
859      {0x01,0x02,0x03,0x04,0x81,0x07,0x08,0xd8,0xda,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,
860         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
861      {0xc2,0x80,0x05,0xc9,0xc8,0x06,0x82,0xc0,0x09,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,
862         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
863   },
864   {
865      {0x01,0x80,0x04,0xc8,0xc0,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
866         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
867      {0xc1,0x02,0x03,0x81,0x05,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
868         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
869   },
870   {
871      {0x01,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
872         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
873      {0xc0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
874         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
875   },
876};
877
878int naomi_m2_board::get_compressed_bit()
879{
880   if(buffer_pos == BUFFER_SIZE)
881      enc_fill();
882   int res = (buffer[buffer_pos^1] >> buffer_bit) & 1;
883   buffer_bit--;
884   if(buffer_bit == -1) {
885      buffer_bit = 7;
886      buffer_pos++;
887   }
888   return res;
889}
890
891void naomi_m2_board::line_fill()
892{
893   assert(line_buffer_pos == line_buffer_size);
894   UINT8 *lp = line_buffer;
895   UINT8 *lc = line_buffer_prev;
896   line_buffer = lc;
897   line_buffer_prev = lp;
898   line_buffer_pos = 0;
899
900   UINT32 line_buffer_mask = line_buffer_size-1;
901
902   for(int i=0; i != line_buffer_size;) {
903      // vlc 0: start of line
904      // vlc 1: interior of line
905      // vlc 2-9: 7-1 bytes from end of line
906
907      int slot = i ? i < line_buffer_size - 7 ? 1 : (i & 7) + 1 : 0;
908
909      UINT32 tmp = 0;
910      while (!(tmp&0x80))
911         if(get_compressed_bit())
912            tmp = trees[slot][1][tmp];
913         else
914            tmp = trees[slot][0][tmp];
915      if(tmp != 0xff) {
916         int count = (tmp & 7) + 1;
917
918         if(tmp&0x40) {
919            // Copy from previous line
920
921            static int offsets[4] = {0, 1, 0, -1};
922            int offset = offsets[(tmp & 0x18) >> 3];
923            for(int j=0; j != count; j++) {
924               lc[i^1] = lp[((i+offset) & line_buffer_mask)^1];
925               i++;
926            }
927
928         } else {
929            // Get a byte in the stream and write n times
930            UINT8 byte;
931            byte =         get_compressed_bit()  << 1;
932            byte = (byte | get_compressed_bit()) << 1;
933            byte = (byte | get_compressed_bit()) << 1;
934            byte = (byte | get_compressed_bit()) << 1;
935            byte = (byte | get_compressed_bit()) << 1;
936            byte = (byte | get_compressed_bit()) << 1;
937            byte = (byte | get_compressed_bit()) << 1;
938            byte =  byte | get_compressed_bit();
939            for(int j=0; j != count; j++)
940               lc[(i++)^1] = byte;
941
942         }
943      }
944   }
945}
trunk/src/mame/machine/naomim2.h
r241643r241644
22#define _NAOMIM2_H_
33
44#include "naomibd.h"
5#include "315-5881_crypt.h"
56
67#define MCFG_NAOMI_M2_BOARD_ADD(_tag, _key_tag, _eeprom_tag, _actel_tag, _irq_cb) \
78   MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_M2_BOARD, _eeprom_tag, _actel_tag, _irq_cb) \
r241643r241644
1112{
1213public:
1314   naomi_m2_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
15   UINT32 rom_cur_address;
16   static const int RAM_SIZE = 65536;
17   UINT8* ram;
1418
1519   static void static_set_tags(device_t &device, const char *_key_tag);
20   UINT16 read_callback(UINT32 addr);
1621
1722protected:
1823   virtual void device_start();
1924   virtual void device_reset();
25   virtual machine_config_constructor device_mconfig_additions() const;
2026
2127   virtual void board_setup_address(UINT32 address, bool is_dma);
2228   virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
r241643r241644
2430   virtual void board_write(offs_t offset, UINT16 data);
2531
2632private:
27   enum {
28      RAM_SIZE = 65536, BUFFER_SIZE = 32768, LINE_SIZE = 512,
29      FLAG_COMPRESSED = 0x10000, FLAG_LINE_SIZE_512 = 0x20000
30   };
3133
34
3235   const char *key_tag;
33   UINT32 key;
3436
35   UINT8 *ram, *buffer, *line_buffer, *line_buffer_prev;
36   UINT32 rom_cur_address, prot_cur_address;
37   UINT16 subkey, dec_hist;
38   UINT32 dec_header;
39   bool enc_ready;
40
41   int buffer_pos, line_buffer_pos, line_buffer_size, buffer_bit;
42
43   struct sbox {
44      UINT8 table[64];
45      int inputs[6];      // positions of the inputs bits, -1 means no input except from key
46      int outputs[2];     // positions of the output bits
47   };
48
49   static const sbox fn1_sboxes[4][4];
50   static const sbox fn2_sboxes[4][4];
51
52   static const int fn1_game_key_scheduling[38][2];
53   static const int fn2_game_key_scheduling[34][2];
54   static const int fn1_sequence_key_scheduling[20][2];
55   static const int fn2_sequence_key_scheduling[16];
56   static const int fn2_middle_result_scheduling[16];
57
58   static const UINT8 trees[9][2][32];
59
60   int feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys);
61   UINT16 block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data);
62
63   UINT16 get_decrypted_16();
64   int get_compressed_bit();
65
66   void enc_start();
67   void enc_fill();
68   void line_fill();
37   
38   required_device<sega_315_5881_crypt_device> m_cryptdevice;
6939};
7040
7141extern const device_type NAOMI_M2_BOARD;
trunk/src/mame/machine/stvprot.c
r241643r241644
572572*
573573*************************************/
574574
575// the naomi hookup of 315-5881 reads 16-bits at a time, here we seem to read 32?
576
575577READ32_MEMBER( stv_state::common_prot_r )
576578{
577579   UINT32 *ROM = (UINT32 *)space.machine().root_device().memregion("abus")->base();
r241643r241644
616618   else if(offset == 2)
617619   {
618620      COMBINE_DATA(&m_abus_prot_addr);
621
622      m_cryptdevice->set_addr_low(m_abus_prot_addr >> 16);
623      m_cryptdevice->set_addr_high(m_abus_prot_addr&0xffff);
624
619625   }
620626   else if(offset == 3)
621627   {
622628      COMBINE_DATA(&m_abus_protkey);
629
630      m_cryptdevice->set_subkey(m_abus_protkey);
631
632
623633      int a_bus_vector;
624634      a_bus_vector = m_abus_prot_addr >> 16;
625635      a_bus_vector|= (m_abus_prot_addr & 0xffff) << 16;
trunk/src/mame/mame.mak
r241643r241644
17071707   $(DRIVERS)/naomi.o $(MACHINE)/dc.o $(VIDEO)/powervr2.o $(MACHINE)/naomi.o \
17081708   $(MACHINE)/naomig1.o $(MACHINE)/naomibd.o $(MACHINE)/naomirom.o $(MACHINE)/naomigd.o \
17091709   $(MACHINE)/naomicrypt.o $(MACHINE)/naomim1.o $(MACHINE)/naomim2.o $(MACHINE)/naomim4.o \
1710   $(MACHINE)/315-5881_crypt.o \
17101711   $(MACHINE)/awboard.o \
17111712   $(MACHINE)/mie.o $(MACHINE)/maple-dc.o $(MACHINE)/mapledev.o $(MACHINE)/dc-ctrl.o $(MACHINE)/jvs13551.o \
17121713   $(DRIVERS)/triforce.o \


Previous 199869 Revisions Next


© 1997-2024 The MAME Team