TSEC: Difference between revisions

New findings
No edit summary
Line 571: Line 571:


== Device key generation ==
== Device key generation ==
The Falcon device key is generated by reading SOR registers modified by Falcon.
The TSEC device key is generated by reading SOR1 registers modified by the Falcon CPU.
  // Clear something in unknown host1x channel 0 sync register (HOST1X_SYNC_UNK_300)
  // Clear something in unknown host1x channel 0 sync register (HOST1X_SYNC_UNK_300)
  // This appears to revoke TSEC's exclusive access to host1x
  // This appears to revoke TSEC's exclusive access to host1x
  *(u32 *)0x50003300 = 0;
  *(u32 *)0x50003300 = 0;
   
   
  // Generate Falcon device key
  // Read TSEC device key
  u32 falcon_device_key[4];  
  u32 tsec_device_key[4];  
  falcon_device_key[0] = *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB;
  tsec_device_key[0] = *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB;
  falcon_device_key[1] = *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB;
  tsec_device_key[1] = *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB;
  falcon_device_key[2] = *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB;
  tsec_device_key[2] = *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB;
  falcon_device_key[3] = *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB;
  tsec_device_key[3] = *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB;
   
   
  // Clear SOR registers
  // Clear SOR1 registers
  *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB = 0;
  *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB = 0;
  *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB = 0;
  *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB = 0;
Line 592: Line 592:
     out_size = 0x10;
     out_size = 0x10;
   
   
  // Copy back the Falcon key
  // Copy back the TSEC device key
  memcpy(out_buf, falcon_device_key, out_size);
  memcpy(out_buf, tsec_device_key, out_size);


== Cleanup ==
== Cleanup ==
Line 744: Line 744:
  }
  }
   
   
  // Write Falcon device key to registers
  // Write TSEC device key to registers
  set_device_key(key_data_buf);
  set_device_key(key_data_buf);
   
   
  return boot_res;
  return boot_res;
==== set_device_key ====
This method takes '''key_data_buf''' as argument and writes the TSEC key to SOR1 registers.
// This is TSEC_MMIO + 0x1000 + (0x1C300 / 0x40)
*(u32 *)TSEC_DMA_UNK = 0xFFF;
// Read the key's words
u32 key0 = *(u32 *)(key_data_buf + 0x00);
u32 key1 = *(u32 *)(key_data_buf + 0x04);
u32 key2 = *(u32 *)(key_data_buf + 0x08);
u32 key3 = *(u32 *)(key_data_buf + 0x0C);
u32 result = 0;
// Write to SOR1 register
result = tsec_dma_write(NV_SOR_DP_HDCP_BKSV_LSB, key0);
// Failed to write
if (result)
    return result;
// Write to SOR1 register
result = tsec_dma_write(NV_SOR_TMDS_HDCP_BKSV_LSB, key1);
// Failed to write
if (result)
    return result;
// Write to SOR1 register
result = tsec_dma_write(NV_SOR_TMDS_HDCP_CN_MSB, key2);
// Failed to write
if (result)
    return result;
// Write to SOR1 register
result = tsec_dma_write(NV_SOR_TMDS_HDCP_CN_LSB, key3);
// Failed to write
if (result)
    return result;
return result;
===== tsec_dma_write =====
This method takes '''addr''' and '''value''' as arguments and performs a DMA write using TSEC MMIO.
u32 result = 0;
// Wait for TSEC DMA engine
// This waits for bit 0x0C in TSEC_DMA_CMD to be 0
result = wait_tsec_dma();
// Wait failed
if (result)
    return 1;
// Set the destination address
// This is TSEC_MMIO + 0x1000 + (0x1C100 / 0x40)
*(u32 *)TSEC_DMA_ADDR = addr;
// Set the value
// This is TSEC_MMIO + 0x1000 + (0x1C200 / 0x40)
*(u32 *)TSEC_DMA_VAL = value;
// Start transfer?
// This is TSEC_MMIO + 0x1000 + (0x1C000 / 0x40)
*(u32 *)TSEC_DMA_CMD = 0x800000F2;
// Wait for TSEC DMA engine
// This waits for bit 0x0C in TSEC_DMA_CMD to be 0
result = wait_tsec_dma();
// Wait failed
if (result)
    return 1;
return 0;


== Stage 1 ==
== Stage 1 ==
Line 763: Line 840:
   
   
  // fuc5 crypt cauth instruction
  // fuc5 crypt cauth instruction
  // Clear auth_addr
  // Clear bit 0x13 in cauth
  cauth(cauth_old & 0x7FFFF);
  cauth(cauth_old & ~(1 << 0x13));
   
   
  // Set the target port for memory transfers
  // Set the target port for memory transfers
// Target will now be 0 (DMA)
  xtargets(0);
  xtargets(0);
   
   
Line 872: Line 948:
   
   
  // Compare the hashes
  // Compare the hashes
  if (memcmp(sig_key, key_buf + 0x10, 0x10))
  if (memcmp(dst_addr, key_buf + 0x10, 0x10))
  {
  {
   res = 0xDEADBEEF;
   res = 0xDEADBEEF;
Line 975: Line 1,051:
  get_seed(seed_buf, type);
  get_seed(seed_buf, type);
   
   
  // This will write the seed into crypt register c0  
  // This will write the seed into crypto register c0  
  crypt_store(0, seed_buf);
  crypt_store(0, seed_buf);
   
   
  // fuc5 csecret instruction
  // fuc5 csecret instruction
  // Load selected secret into crypt register c1
  // Load selected secret into crypto register c1
  csecret(c1, 0x26);
  csecret(c1, 0x26);
   
   
  // fuc5 ckeyreg instruction
  // fuc5 ckeyreg instruction
  // Binds c1 register as the key for enc/dec operations
  // Bind c1 register as the key for enc/dec operations
  ckeyreg(c1);
  ckeyreg(c1);
   
   
  // fuc5 cenc instruction
  // fuc5 cenc instruction
  // Encrypts seed_buf (in c0) using keyreg value as key into c1
  // Encrypt seed_buf (in c0) using keyreg value as key into c1
  cenc(c1, c0);
  cenc(c1, c0);
   
   
  // fuc5 csigenc instruction
  // fuc5 csigenc instruction
  // Encrypt code sig with c1 register as key
  // Encrypt c1 register with the auth signature stored in c6
  csigenc(c1, c1);
  csigenc(c1, c1);
   
   
Line 1,016: Line 1,092:
  *(u32 *)(buf + 0x0C) = size;
  *(u32 *)(buf + 0x0C) = size;
   
   
  // This will write buf into crypt register c3  
  // This will write buf into crypto register c3  
  crypt_store(0x03, buf);
  crypt_store(0x03, buf);
   
   
  // fuc5 ckeyreg instruction
  // fuc5 ckeyreg instruction
  // Binds c4 register (from keygen) as the key for enc/dec operations
  // Bind c4 register (from keygen) as the key for enc/dec operations
  ckeyreg(c4);
  ckeyreg(c4);
   
   
  // fuc5 cenc instruction
  // fuc5 cenc instruction
  // Encrypts buf (in c3) using keyreg value as key into c5
  // Encrypt buf (in c3) using keyreg value as key into c5
  cenc(c5, c3);
  cenc(c5, c3);
   
   
  // This will read into buf from crypt register c5  
  // This will read into buf from crypto register c5  
  crypt_load(0x05, buf);
  crypt_load(0x05, buf);
   
   
Line 1,049: Line 1,125:
  if (iv_addr)
  if (iv_addr)
  {
  {
   // This will write the iv_addr into crypt register c5  
   // This will write the iv_addr into crypto register c5  
   crypt_store(0x05, iv_addr);
   crypt_store(0x05, iv_addr);
  }
  }
Line 1,061: Line 1,137:
  ckeyreg(c4);
  ckeyreg(c4);
   
   
  // AES-128-ECB? decrypt
  // AES-128-ECB decrypt
  if (mode == 0x00)
  if (mode == 0x00)
  {
  {
Line 1,073: Line 1,149:
   cmov(c5, c3);                // Move c3 into c5
   cmov(c5, c3);                // Move c3 into c5
  }
  }
  else if (mode == 0x01) // AES-128-ECB? encrypt
  else if (mode == 0x01) // AES-128-ECB encrypt
  {
  {
   // Create crypto script with 4 instructions
   // Create crypto script with 4 instructions
Line 1,092: Line 1,168:
   cenc(c5, c5);                // Encrypt from c5 into c5
   cenc(c5, c5);                // Encrypt from c5 into c5
  }
  }
  else if (mode == 0x03) // AES-128-ECB? decrypt (no IV)
  else if (mode == 0x03) // AES-128-ECB decrypt (no IV)
  {
  {
   // Create crypto script with 3 instructions
   // Create crypto script with 3 instructions
Line 1,101: Line 1,177:
   cxsout(c5);                  // Write 0x10 bytes into crypto stream from c5
   cxsout(c5);                  // Write 0x10 bytes into crypto stream from c5
  }
  }
  else if (mode == 0x04) // AES-128-ECB? encrypt (no IV)
  else if (mode == 0x04) // AES-128-ECB encrypt (no IV)
  {
  {
   // Create crypto script with 3 instructions
   // Create crypto script with 3 instructions
Line 1,176: Line 1,252:
   // fuc5 crypt cxset instruction
   // fuc5 crypt cxset instruction
   // The next xfer instruction will be overridden
   // The next xfer instruction will be overridden
   // and target changes from DMA to crypto  
   // and target changes from DMA to crypto input/output stream
   if (crypt_ver == 0x01)
   if (crypt_ver == 0x01)
     cxset(0xA1);        // Flag 0xA0 is unknown
     cxset(0xA1);        // Flag 0xA0 is (0x80 | 0x20)
   else
   else
     cxset(0x21);        // Flag 0x20 is unknown
     cxset(0x21);        // Flag 0x20 is external mem <-> crypto input/output stream
   
   
   // Transfer data into the selected crypto register
   // Transfer data into the crypto input/output stream
   xdst(crypt_xfer_src, crypt_xfer_src);
   xdst(crypt_xfer_src, crypt_xfer_src);
    
    
Line 1,190: Line 1,266:
       // fuc5 crypt cxset instruction
       // fuc5 crypt cxset instruction
       // The next xfer instruction will be overridden
       // The next xfer instruction will be overridden
       // and target changes from DMA to crypto  
       // and target changes from DMA to crypto input/output stream
       if (crypt_ver == 0x01)
       if (crypt_ver == 0x01)
         cxset(0xA1);    // Flag 0xA0 is unknown
         cxset(0xA1);    // Flag 0xA0 is (0x80 | 0x20)
       else
       else
         cxset(0x21);    // Flag 0x20 is unknown
         cxset(0x21);    // Flag 0x20 is external mem <-> crypto input/output stream
 
 
       // Wait for all data loads/stores to finish
       // Wait for all data loads/stores to finish
Line 1,203: Line 1,279:
       // fuc5 crypt cxset instruction
       // fuc5 crypt cxset instruction
       // The next 2 xfer instructions will be overridden
       // The next 2 xfer instructions will be overridden
       // and target changes from DMA to crypto  
       // and target changes from DMA to crypto input/output stream
       if (crypt_ver == 0x01)
       if (crypt_ver == 0x01)
         cxset(0xA2);            // Flag 0xA0 is unknown
         cxset(0xA2);            // Flag 0xA0 is (0x80 | 0x20)
       else
       else
         cxset(0x22);            // Flag 0x20 is unknown
         cxset(0x22);            // Flag 0x20 is external mem <-> crypto input/output stream
   
   
       // Transfer data from the selected crypto register
       // Transfer data from the crypto input/output stream
       xdst(crypt_xfer_dst, crypt_xfer_dst);
       xdld(crypt_xfer_dst, crypt_xfer_dst);
 
 
       // Wait for all data loads/stores to finish
       // Wait for all data loads/stores to finish
Line 1,229: Line 1,305:
  if (mode == 0x02)
  if (mode == 0x02)
  {
  {
     // This will read into dst_addr from crypt register c5  
     // This will read into dst_addr from crypto register c5  
     crypt_load(0x05, dst_addr);
     crypt_load(0x05, dst_addr);
  }
  }