From 697eff192eca8996ecf707847b55c86729b0e4cc Mon Sep 17 00:00:00 2001 From: Andreas Naive Date: Fri, 17 Jun 2011 23:05:26 +0000 Subject: [PATCH] Added code to manage NAOMI's M4 decryption. [Andreas Naive] --- .gitattributes | 2 + src/mame/machine/naomim4decoder.c | 73 +++++++++++++++++++++++++++++++ src/mame/machine/naomim4decoder.h | 46 +++++++++++++++++++ src/mame/mame.mak | 2 +- 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100755 src/mame/machine/naomim4decoder.c create mode 100755 src/mame/machine/naomim4decoder.h diff --git a/.gitattributes b/.gitattributes index a360ead6ad1..0d0b3a64f31 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3859,6 +3859,8 @@ src/mame/machine/namcos1.c svneol=native#text/plain src/mame/machine/namcos2.c svneol=native#text/plain src/mame/machine/naomi.c svneol=native#text/plain src/mame/machine/naomibd.c svneol=native#text/plain +src/mame/machine/naomim4decoder.c svneol=native#text/plain +src/mame/machine/naomim4decoder.h svneol=native#text/plain src/mame/machine/nb1413m3.c svneol=native#text/plain src/mame/machine/nb1414m4.c svneol=native#text/plain src/mame/machine/neoboot.c svneol=native#text/plain diff --git a/src/mame/machine/naomim4decoder.c b/src/mame/machine/naomim4decoder.c new file mode 100755 index 00000000000..90a39be3c4f --- /dev/null +++ b/src/mame/machine/naomim4decoder.c @@ -0,0 +1,73 @@ +#include "naomim4decoder.h" + +const UINT8 NaomiM4Decoder::k_sboxes[4][16] = { + {13,14,1,11,7,9,10,0,15,6,4,5,8,2,12,3}, + {12,3,14,6,7,15,2,13,1,4,11,0,9,10,8,5}, + {6,12,0,10,1,5,14,9,7,2,15,13,4,11,3,8}, + {9,12,8,7,10,4,0,15,1,11,14,2,13,5,6,3} +}; + +NaomiM4Decoder::NaomiM4Decoder(UINT32 cart_key) +: m_key(cart_key & 0xffff) +, m_iv(cart_key >> 16) // initialization vector +{ + m_one_round = global_alloc_array(UINT16,0x10000); + + // populate the lookup table for one of the internal rounds of the cipher + for (UINT32 i=0; i<0x10000; ++i) + { + m_one_round[i] = one_round_core(i); + } +} + +NaomiM4Decoder::~NaomiM4Decoder() +{ + global_free(m_one_round); +} + +void NaomiM4Decoder::init() +{ + m_counter = 0; +} + +UINT16 NaomiM4Decoder::decrypt(UINT16 ciphertext) // decrypt the next 16-bits value in the stream +{ + if (0 == (m_counter++ & 0xf)) // the iv is recovered every 16 values (32 bytes) + m_middle_value = m_iv; + + UINT16 output_whitening = m_key ^ m_middle_value; + + m_middle_value = m_one_round[ciphertext ^ m_middle_value]; + + return m_one_round[m_middle_value ^ m_key] ^ output_whitening; +} + +UINT16 NaomiM4Decoder::one_round_core(UINT16 round_input) +{ + UINT8 input_nibble[4]; + UINT8 output_nibble[4]; + UINT8 aux_nibble; + UINT8 nibble_idx; + UINT8 i; + UINT16 result; + + for (nibble_idx = 0; nibble_idx < 4; ++nibble_idx, round_input >>= 4) + { + input_nibble[nibble_idx] = round_input & 0xf; + output_nibble[nibble_idx] = 0; + } + + aux_nibble = input_nibble[3]; + for (nibble_idx = 0; nibble_idx < 4; ++nibble_idx) // 4 s-boxes per round + { + aux_nibble ^= k_sboxes[nibble_idx][input_nibble[nibble_idx]]; + for (i = 0; i < 4; ++i) // diffusion of the bits + output_nibble[(nibble_idx - i) & 3] |= aux_nibble & (1 << i); + } + + for (nibble_idx = 0, result = 0; nibble_idx < 4; ++nibble_idx) + result |= (output_nibble[nibble_idx] << (4 * nibble_idx)); + + return result; +} + diff --git a/src/mame/machine/naomim4decoder.h b/src/mame/machine/naomim4decoder.h new file mode 100755 index 00000000000..873f5004e78 --- /dev/null +++ b/src/mame/machine/naomim4decoder.h @@ -0,0 +1,46 @@ +#pragma once + +#ifndef __NAOMIM4DECODER_H__ +#define __NAOMIM4DECODER_H__ + +#include "emu.h" + +// Decoder for M4-type NAOMI cart encryption + +// In hardware, the decryption is managed by the XC3S50 Xilinx Spartan FPGA (IC2) +// and the annexed PIC16C621A PIC MCU (IC3). +// - The FPGA control the clock line of the security PIC. +// - The protocol between the FPGA and the MCU is nibble-based, though it hasn't been RE for now. +// - The decryption algorithm is clearly nibble-based too. + +// The decryption algorithm itself implements a stream cipher built on top of a 16-bits block cipher. +// The underlying block-cipher is a SP-network of 2 rounds (both identical in structure). In every +// round, the substitution phase is done using 4 fixed 4-to-4 sboxes acting on every nibble. The permutation +// phase is indeed a nibble-based linear combination. +// With that block cipher, a stream cipher is constructed by feeding the output result of the 1st round +// of a certain 16-bits block as a whitening value for the next block. The cart dependent data used by +// the algorithm is comprised by a 16-bits "key" and a 16-bits IV (initialization vector) --though they +// will be merged in a only 32-bits number in the code--. The hardware auto-reset the feed value +// to the cart-based IV every 16 blocks (32 bytes); that reset is not address-based, but index-based. + +class NaomiM4Decoder +{ +public: + NaomiM4Decoder(UINT32 cart_key); + ~NaomiM4Decoder(); + + void init(); // initialize the decryption of a new stream (set the IV) + UINT16 decrypt(UINT16 ciphertext); // decrypt the next 16-bits value in the stream + +private: + UINT16 one_round_core(UINT16 round_input); + + static const UINT8 k_sboxes[4][16]; + UINT16 *m_one_round; + const UINT16 m_key; + const UINT16 m_iv; + UINT16 m_middle_value; // used by the stream cipher as feeding to the next block + UINT8 m_counter; +}; + +#endif // __NAOMIM4DECODER_H__ diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 69172afb0eb..5bfcabecf0a 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -1176,7 +1176,7 @@ $(MAMEOBJ)/sega.a: \ $(DRIVERS)/model1.o $(MACHINE)/model1.o $(VIDEO)/model1.o \ $(DRIVERS)/model2.o $(VIDEO)/model2.o \ $(DRIVERS)/model3.o $(VIDEO)/model3.o $(MACHINE)/model3.o \ - $(DRIVERS)/naomi.o $(MACHINE)/dc.o $(VIDEO)/dc.o $(MACHINE)/gdcrypt.o $(MACHINE)/naomibd.o $(MACHINE)/naomi.o \ + $(DRIVERS)/naomi.o $(MACHINE)/dc.o $(VIDEO)/dc.o $(MACHINE)/gdcrypt.o $(MACHINE)/naomibd.o $(MACHINE)/naomi.o $(MACHINE)/naomim4decoder.o\ $(MACHINE)/mie.o $(MACHINE)/maple-dc.o $(MACHINE)/mapledev.o $(MACHINE)/dc-ctrl.o \ $(MACHINE)/jvs13551.o \ $(DRIVERS)/triforce.o \