summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/naomim4decoder.c
blob: 90a39be3c4f867d37bbe3c4cdd717f531102b67a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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;
}