SC Communication: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
Line 185: Line 185:
=== Step 3e - Validate AUTH2 ===
=== Step 3e - Validate AUTH2 ===
Again, check the header/footer.
Again, check the header/footer.
* Calulcate aesOmac over the packet length and compare to omac from syscon. Use sc2be key.
* Calculate AES [http://en.wikipedia.org/wiki/One-key_MAC OMAC] over the packet length and compare to [http://en.wikipedia.org/wiki/One-key_MAC OMAC] from syscon. Use sc2be key.
* Decrypt internal packet with sc2be key. Use AES128-CBC
* Decrypt internal packet with sc2be key. Use AES128-CBC
* Compare returned session_id and seq_service_id.
* Compare returned session_id and seq_service_id.

Revision as of 14:13, 29 January 2013

Introduction

  • The following information was reverse engineered from lv0ldr, lv0, lv1, and sc_iso.self.
  • Big thanks to graf_chokolo for a large part of the basis of this page, and to Jestero for Syscon Authentication info!

Overview of Syscon Communication

  • Syscon lives at the mmio space of 0x24000080000.
  • Communication occurs through mmio read/writes.

List of known offsets in Syscon:

Offset (from start of address space) Size Description
0xC000 0xFF0 Syscon packet send area
0xCFF0 0x4 Syscon sent packet counter
0xCFF4 0x4 Syscon sent packet acknowledge counter
0xD000 0xFF0 Syscon packet receive area
0xDFF0 0x4 Syscon received packet counter
0xDFF4 0x4 Syscon received packet acknowledge counter
0xE100 0x4 Tells syscon there is a packet to be received

Quick explanation of the packet counters:

  • There are two counters that are incremented by each side (Cell / Syscon).
  • 0xCFF0 and 0xDFF0 are incremented by the sending side (Syscon for 0xCFF0, Cell for 0xDFF0)
  • 0xCFF4 and 0xDFF4 are incremented by the receiving side (Cell for 0xCFF4, Syscon for 0xDFF4)

Syscon Services

  • To be completed...
Service ID Description
0x14 NVS Service - Used for eeprom read/write (Non-Volatile Storage?)
0x18 Livelock(?) Service - Checks for permission to use other services
0x20 Syscon Debug Output(?) - Used to send a string to syscon.
0x1F Authenticated Services
0xFF Syscon Init (Seen in lv0ldr init sequence to syscon: http://www.ps3devwiki.com/wiki/User_talk:JuanNadie)

Syscon Packet Headers

  • Some useful packet headers...
  • If the header is shorter than 0x10, you must add your own size.
What? Description Data Notes
AUTH1 AUTH1 Header 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x30
AUTH2 AUTH2 Header 0x1F, 0x01, 0x00, 0x01, 0x00, 0x00, 0x80, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x30
Debug Output Sends string to Syscon TTY 0x20, 0x01, 0x00, 0x07, 0x00, 0x00, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00
Start message with 0x00. Will print as much as packet length.

Syscon Authentication

- An IV of 0x00 is used for most AES steps.

Step 1 - Generate Individual Seeds

Encrypt sc_iso metadata seeds w/ eid root key / iv.

aes256cbc_enc(eid_root_erk, eid_root_riv, sc_module_seeds, 0x40, sc_module_seeds);

Step 2 - Generate SC_ISO encrypted keys

Encrypt the sc_key_seeds.

indiv_key = sc_module_seeds + 0x20;
for (int i = 0; i < 0x100; i += 0x10)
    aes256cbc_enc(indiv_key, zero_iv, key_seeds + i, 0x10, enc_key_seeds + i);

Step 3 - Authenticate with Syscon

Pick a session_id. Must be <= 7.

Step 3a - Secure Packet Header

struct secure_payload_header {
    u8 session_id;
    u8 seq_service_id;  //service_ID (Unsecure uses 0xFF, AUTH1 = 0x02, AUTH2 = 0x03, READ/WRITE = 0x04)
    u8 packet_type;     //0xFF for BE->SC, 0x00 for SC->BE (if success)
    u8 magic[0x2];      //0xAD1A
    u8 prng_random[0xB] //Random shit for padding
};

Step 3b - AUTH 1 to SC

uint8_t random_shit[0x10];
auth_key_1_0x01 = enc_key_seeds + (session_id * (0x10*2));
auth_key_2_0x01 = enc_key_seeds + (session_id * (0x10*2) + 0x10);

//generating random payload for auth1
rnd_gen(random_shit, 0x10);

//create auth1 random data
aes128cbc_enc(auth_key_1_0x01, zero_iv, random_shit, 0x10, secure_payload_buf + 0x10);

//length = 0x20
//Create secure header/footer
// create header: 5 bytes + random stuff (0xb)
payload_header->session_id = session_id;
payload_header->seq_service_id = seq_service_id++; // starts at 0
payload_header->packet_type = 0xFF;
payload_header->magic[0] = 0xAD;
payload_header->magic[1] = 0x1A;
rnd_gen((u8*) &payload_header->prng_random, 0x0B);
    
//encrypt payload
aes128cbc_enc(be2sc_key, zero_iv, secure_payload_buf, length, secure_payload_buf);

// create footer: omac1 of the whole packet
aesOmac1Mode(secure_payload_buf + length, secure_payload_buf, length, be2sc_key, sizeof(be2sc_key)*8);

//Set regular header
memcpy(sc_packet, auth1_pkt_header, 0x10);

//Send packet. 0x40 Bytes

Step 3c - Validate AUTH1

First, check the header/footer.

  • Calculate AES OMAC over the packet length and compare to OMAC from syscon. Use sc2be key.
  • Decrypt internal packet with sc2be key. Use AES128CBC
  • Compare returned session_id and seq_service_id.
  • Check secure_payload_buf[0x2] == 0.

Then check the AUTH1 response

// decrypt secure_payload
for (i = 0x0; i < 0x20; i += 0x10)
    aes128cbc(auth_key_2_0x01, zero_iv, secure_payload_buf + 0x10 + i, 0x10, secure_payload_buf + 0x10 + i);
    
// check if challange returned from syscon is correct
res = memcmp(secure_payload_buf + 0x10, random_shit, 0x10);
if (res != 0)
    return -1;
    
// save the new challange needed for AUTH2
memcpy(auth_challenge, secure_payload_buf + 0x20, 0x10);

Step 3d - AUTH2 to SC

//AUTH2 Challenge Payload
aes128cbc_enc(auth_key_1_0x01, zero_iv, auth_challenge, 0x10, secure_payload_buf + 0x10);

//length = 0x20
//Create secure header/footer
// create header: 5 bytes + random stuff (0xb)
payload_header->session_id = session_id;
payload_header->seq_service_id = seq_service_id++; // starts at 0
payload_header->packet_type = 0xFF;
payload_header->magic[0] = 0xAD;
payload_header->magic[1] = 0x1A;
rnd_gen((u8*) &payload_header->prng_random, 0x0B);
    
//encrypt payload
aes128cbc_enc(be2sc_key, zero_iv, secure_payload_buf, length, secure_payload_buf);

// create footer: omac1 of the whole packet
aesOmac1Mode(secure_payload_buf + length, secure_payload_buf, length, be2sc_key, sizeof(be2sc_key)*8);

//Set regular header
memcpy(sc_packet, auth2_pkt_header, 0x10);

//Put packet - 0x40 packet length

Step 3e - Validate AUTH2

Again, check the header/footer.

  • Calculate AES OMAC over the packet length and compare to OMAC from syscon. Use sc2be key.
  • Decrypt internal packet with sc2be key. Use AES128-CBC
  • Compare returned session_id and seq_service_id.
  • Check secure_payload_buf[0x2] == 0.
// encrypt random_shit using auth_challenge (returned from AUTH1 reply) as key and 0 IV
aes128cbc_enc(auth_challenge, zero_iv, random_shit, 0x10, session_key);

// encrypt result in place with session_key_create[0x10 * sess_id] and IV 0 (result will be the session_key)
aes128cbc_enc(session_key_create + (session_id * 0x10), zero_iv, session_key, 0x10, session_key);

// use the session_key to decrypt auth2_payload in place (0x10)
aes128cbc(session_key, zero_iv, secure_payload_buf + 0x10, 0x10, secure_payload_buf + 0x10);
    
// compare the result with a 0x10 zero string
res = memcmp(secure_payload_buf + 0x10, zero_iv, 0x10);

//res == 0x0 is good.

Step 4 - Profit?

You are now authenticated with syscon, and can use privileged commands. Just use the session_key calculated from the AUTH2 reply to encrypt/decrypt responses.