docs/templates/pages/sega/hardware/~keychip.md
2023-03-27 21:43:22 +01:00

21 KiB

Ring Keychip

The Ring keychip is arguably simultaniously one of the most overkill while least utilised parts of the system. On-board is a PIC microcontroller, a dedicated cryptography chip, a hardware SHA engine for authentication, and flash storage.

Protocol

The PIC communicates with the system using a parallel bus. This bus is exposed physically on the keychip connector, and in software can be accessed using \\.\mxparallel. All bus communication is encrypted using AES 128 ECB, using a different key for each data direction. Send/receive is defined from the perspective of the Ring system. That is, the "Send" key handles data from the Ring to the keychip, and the "Receive" key handles data from the keychip to the Ring. The initial key values are:

Initial receive key:

75 6f 72 61 74 6e 65 6b 61 6d 69 68 73 75 6b 75

Initial send key:

66 6E 65 6B 65 72 61 77 64 72 61 68 61 67 65 73

All packets are first prefixed by a command ordinal (see below), then command-specific information. The base unit of transfer is 16 bytes due to AES 128. Unused bytes can contain anything, however mxkeychip chooses to pad using random bytes derrived from the current system time.

Storage locations

EEPROM

Stores entries detailing the tracedata metadata. There is a copy of the structure at 0x000 and a duplicate at 0x100. Each structure is comprised of 16 entries, where each entry first has a 4 byte CRC, then 12 bytes currently unknown.

NVRAM

Start End Content
1800h 1bffh billing public key
1c00h 1fffh ca certificate

Each block begins with a 4 byte integer indicating the length of the data following it (up to 1020 bytes).

Flash

Start End Content
00000h 0ffffh tracedata sector 1
10000h 1ffffh tracedata sector 2
20000h 2ffffh tracedata sector 3
30000h 3ffffh tracedata sector 4
40000h 4ffffh tracedata sector 5
50000h 5ffffh tracedata sector 6
60000h 6ffffh tracedata sector 7
70000h 70fffh nvram0
71000h 71fffh nvram1
72000h 72fffh nvram2
73000h 73fffh nvram3
74000h 74fffh nvram4
75000h 75fffh nvram5
76000h 76fffh nvram6
77000h 77fffh nvram7
78000h 78fffh nvram8
79000h 79fffh nvram9
7a000h 7a10bh billing info
7b000h 7b10bh billing info dup

Each tracedata sector begins with a 128-byte bitfield (1024 bits) indicating which blocks in the sector have been populated. Following this are 1022 blocks, 64 bytes each. (the last two of the theorhetical 1024 would overlap into the next sector). Each slot is individually encrypted with DES ECB, using key 4D77F1748D6D1094.

This is implemented via the AT25DF041A 4Mbit flash chip on the keychip PCB. The maximum address is therefore 7ffffh.

Command Ordinals

Ordinal Command
0 SetKeyS
1 SetKeyR
2 SetIv
3 Decrypt
4 Encrypt
5 GetAppBootInfo
6 EepromWrite
7 EepromRead
8 NvramWrite
9 NvramRead
10 AddPlayCount
11 FlashRead
12 FlashErase
13 ?
14 FlashWrite
15 ?
16 ?
17 ?
18 ?
19 ?
20 KcGetVersion
21 SetMainId
22 GetMainId
23 SetKeyId
24 GetKeyId
25 GetPlayCounter

SetKeyS

Sets the "send" encryption key. The key is changed before communication of the reply.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 0 * * * * * * * * * * * * * * *
^ key < < < < < < < < < < < < < < <
Receive * * * * * * * * * * * * * * * *
Variable
key The send key

SetKeyR

Sets the "receive" encryption key. The key is changed before communication of the reply.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 1 * * * * * * * * * * * * * * *
^ key < < < < < < < < < < < < < < <
Receive * * * * * * * * * * * * * * * *
Variable
key The receive key

SetIv

Reset the game key IV to its initial value

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 2 * * * * * * * * * * * * * * *
Receive * * * * * * * * * * * * * * * *

Decrypt

Decrypt a block of data using the game key

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 3 * * * * * * * * * * * * * * *
ct < < < < < < < < < < < < < < <
Receive pt < < < < < < < < < < < < < < <
Variable
ct The encrypted ciptertext
pt The decrypted plaintext

Encrypt

Encrypt a block of data using the game key

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 4 * * * * * * * * * * * * * * *
^ pt < < < < < < < < < < < < < < <
Receive ct < < < < < < < < < < < < < < <
Variable
pt The decrypted plaintext
ct The encrypted ciptertext

GetAppBootInfo

Request the AppBoot structure from the keychip. The AppBoot structure is 256 bytes, thus requires 16 packets.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 5 0 * * * * * * * * * * * * * *
Receive CRC < < < Format < < < Game ID < < < Region Model type System flag ?
Platform ID < < DVD flag Network address < < <
206 bytes padding < < < < < < < < < < < < < < <
^ Seed < < < < < < < < < < < < < < <
Variable
CRC CRC32 checksum of the reamining 252 bytes
Format AppBoot format type. The described type is format 1
Game ID Four character game ID. For example, SBTR
Region Region bitmask
Model type Model type this keychip is for
System flag System flag bitmask
DVD flag Is update from DVD allowed
Network address Permitted subnet. Fourth octet is null

Note: I'm not sure what the 0 is for here. Surprises await for anything other than 0 :D

EepromWrite

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 6 reg * * * * * * * * * * * * * *
^ data < < < < < < < < < < < < < < <
Receive * * * * * * * * * * * * * * * *
Variable
reg EEPROM register to write. EEPROM is divided into 16x16 byte registers
data The data to write

EepromRead

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 7 reg * * * * * * * * * * * * * *
Receive data < < < < < < < < < < < < < < <
Variable
reg EEPROM register to read. EEPROM is divided into 16x16 byte registers
data The data read

NvramWrite

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 8 addr < blocks * * * * * * * * * * * *
^ data < < < < < < < < < < < < < < <
Receive * * * * * * * * * * * * * * * *
Variable
addr Absolute offset in NVRAM to write at
blocks The number of 16 bytes blocks to write
data The data to write. This will require blocks packets

NvramRead

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 8 addr < blocks * * * * * * * * * * * *
Receive data < < < < < < < < < < < < < < <
Variable
addr Absolute offset in NVRAM to read at
blocks The number of 16 bytes blocks to read
data The read data. This will require blocks packets

AddPlayCount

Increment the playcount value

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 10 * * * * * * * * * * * * * * *
Receive * * * * * * * * * * * * * * * *

FlashRead

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 11 addr < < # bytes < < * * * * * * * * *
Variable
addr Absolute offset in flash to read at
# bytes The number of bytes to read

Important: Data is returned as raw bytes transmitted over parallel, without encryption or packet encapsulation.

FlashErase

Honestly not actually sure if this is an erase or what. Still working on it!

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 12 addr < < * * * * * * * * * * * *
Receive * * * * * * * * * * * * * * * *

FlashWrite

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 14 addr < < # bytes < < * * * * * * * * *
Receive * * * * * * * * * * * * * * * *
Variable
addr Absolute offset in flash to write at
# bytes The number of bytes to write

Important: Data is transmitted immediately following transmission of the first packet. Is it transmitted as raw bytes over parallel, without encryption or packet encapsulation. The response packet is transmitted after # bytes have been received in this manner.

KcGetVersion

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 20 * * * * * * * * * * * * * * *
Receive version < * * * * * * * * * * * * * *
Variable
version Two-byte version number. Keychips are observed to return 01,04.

SetMainId

Set the Main ID on the keychip, if not already set.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 21 * * * * * * * * * * * * * * *
^ Main ID < < < < < < < < < < < < < < <
Receive err * * * * * * * * * * * * * * *
Variable
Main ID The new keychip Main ID. No validation is performed of this value.
err ? (0?) when succesful, FFh otherwise

GetMainId

Get the Main ID on the keychip.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 22 * * * * * * * * * * * * * * *
Receive Main ID < < < < < < < < < < < < < < <
Variable
Main ID The keychip Main ID

SetKeyId

Set the Key ID on the keychip, if not already set.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 23 * * * * * * * * * * * * * * *
^ Key ID < < < < < < < < < < < < < < <
Receive err * * * * * * * * * * * * * * *
Variable
Key ID The new keychip ID. No validation is performed of this value.
err ? (0?) when succesful, FFh otherwise

GetKeyId

Get the Key ID on the keychip.

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 24 * * * * * * * * * * * * * * *
Receive Key ID < < < < < < < < < < < < < < <
Variable
Key ID The keychip ID

GetPlayCounter

Get the current playcount value

0 1 2 3 4 5 6 7 8 9 A B C D E F
Send 24 * * * * * * * * * * * * * * *
Receive playcount < < < * * * * * * * * * * * *
Variable
playcount The billing playcount value