docs/templates/pages/sega/hardware/~keychip.md

368 lines
21 KiB
Markdown
Raw Normal View History

2023-03-27 19:47:33 +00:00
# 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 |
| ---------------- | ---------------- | ------------------ |
| 1800<sub>h</sub> | 1bff<sub>h</sub> | billing public key |
| 1c00<sub>h</sub> | 1fff<sub>h</sub> | 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 |
| ----------------- | ----------------- | ------------------ |
| 00000<sub>h</sub> | 0ffff<sub>h</sub> | tracedata sector 1 |
| 10000<sub>h</sub> | 1ffff<sub>h</sub> | tracedata sector 2 |
| 20000<sub>h</sub> | 2ffff<sub>h</sub> | tracedata sector 3 |
| 30000<sub>h</sub> | 3ffff<sub>h</sub> | tracedata sector 4 |
| 40000<sub>h</sub> | 4ffff<sub>h</sub> | tracedata sector 5 |
| 50000<sub>h</sub> | 5ffff<sub>h</sub> | tracedata sector 6 |
| 60000<sub>h</sub> | 6ffff<sub>h</sub> | tracedata sector 7 |
| 70000<sub>h</sub> | 70fff<sub>h</sub> | nvram0 |
| 71000<sub>h</sub> | 71fff<sub>h</sub> | nvram1 |
| 72000<sub>h</sub> | 72fff<sub>h</sub> | nvram2 |
| 73000<sub>h</sub> | 73fff<sub>h</sub> | nvram3 |
| 74000<sub>h</sub> | 74fff<sub>h</sub> | nvram4 |
| 75000<sub>h</sub> | 75fff<sub>h</sub> | nvram5 |
| 76000<sub>h</sub> | 76fff<sub>h</sub> | nvram6 |
| 77000<sub>h</sub> | 77fff<sub>h</sub> | nvram7 |
| 78000<sub>h</sub> | 78fff<sub>h</sub> | nvram8 |
| 79000<sub>h</sub> | 79fff<sub>h</sub> | nvram9 |
| 7a000<sub>h</sub> | 7a10b<sub>h</sub> | billing info |
| 7b000<sub>h</sub> | 7b10b<sub>h</sub> | 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 7ffff<sub>h</sub>.
## Command Ordinals
| Ordinal | Command |
| ------- | --------------------------------- |
| `0` | [SetKeyS](#setkeys) |
| `1` | [SetKeyR](#setkeyr) |
| `2` | [SetIv](#setiv) |
| `3` | [Decrypt](#decrypt) |
| `4` | [Encrypt](#encrypt) |
| `5` | [GetAppBootInfo](#getappbootinfo) |
| `6` | [EepromWrite](#eepromwrite) |
| `7` | [EepromRead](#eepromread) |
| `8` | [NvramWrite](#nvramwrite) |
| `9` | [NvramRead](#nvramread) |
| `10` | [AddPlayCount](#addplaycount) |
| `11` | [FlashRead](#flashread) |
| `12` | [FlashErase](#flasherase) |
| `13` | ? |
| `14` | [FlashWrite](#flashwrite) |
| `15` | ? |
| `16` | ? |
| `17` | ? |
| `18` | ? |
| `19` | ? |
| `20` | [KcGetVersion](#kcgetversion) |
| `21` | [SetMainId](#setmainid) |
| `22` | [GetMainId](#getmainid) |
| `23` | [SetKeyId](#setkeyid) |
| `24` | [GetKeyId](#getkeyid) |
| `25` | [GetPlayCounter](#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, FF<sub>h</sub> 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, FF<sub>h</sub> 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 |