Changes

Jump to navigation Jump to search
35 bytes added ,  17:30, 19 May 2019
no edit summary
Line 3: Line 3:  
The only known area which is not encrypted in the raw NCA is the logo section, when the NCA includes that section. Everything else documented on this page is for the plaintext version of that data.
 
The only known area which is not encrypted in the raw NCA is the logo section, when the NCA includes that section. Everything else documented on this page is for the plaintext version of that data.
   −
=Encryption=
+
= Encryption =
 
The first 0xC00 bytes are encrypted with AES-XTS with sector size 0x200 with a non-standard "tweak" (endianness is reversed, see [https://gist.github.com/SciresM/fe8a631d13c069bd66e9c656ab5b3f7f here]), this encrypted data is an 0x400 NCA header + an 0x200 header for each section in the section table.
 
The first 0xC00 bytes are encrypted with AES-XTS with sector size 0x200 with a non-standard "tweak" (endianness is reversed, see [https://gist.github.com/SciresM/fe8a631d13c069bd66e9c656ab5b3f7f here]), this encrypted data is an 0x400 NCA header + an 0x200 header for each section in the section table.
    
For pre-1.0.0 "NCA2" NCAs, the first 0x400 byte are encrypted the same way as in NCA3. However, each section header is individually encrypted as though it were sector 0, instead of the appropriate sector as in NCA3.
 
For pre-1.0.0 "NCA2" NCAs, the first 0x400 byte are encrypted the same way as in NCA3. However, each section header is individually encrypted as though it were sector 0, instead of the appropriate sector as in NCA3.
   −
=Header=
+
= Header =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 17: Line 17:  
| 0x0
 
| 0x0
 
| 0x100
 
| 0x100
| RSA-2048 signature over the 0x200-bytes starting at offset 0x200 using fixed key.
+
| RSA-2048 signature over the header (data from 0x200 to 0x400) using a fixed key
 
|-
 
|-
 
| 0x100
 
| 0x100
 
| 0x100
 
| 0x100
| RSA-2048 signature over the 0x200-bytes starting at offset 0x200 using key from [[NPDM]], or zeroes if not a program.
+
| RSA-2048 signature over the header (data from 0x200 to 0x400) using a key from [[NPDM]] (or zeroes if not a program)
 
|-
 
|-
 
| 0x200
 
| 0x200
 
| 0x4
 
| 0x4
| Magicnum (Normally "NCA3", "NCA2" for some pre-1.0.0 NCAs)
+
| Magicnum "NCA3" ("NCA2", "NCA1" or "NCA0" for pre-1.0.0 NCAs)
 
|-
 
|-
 
| 0x204
 
| 0x204
 
| 0x1
 
| 0x1
| 0 for system NCAs. 1 for a NCA from gamecard.
+
| Distribution Type (0 = System NCA, 1 = Gamecard NCA)
 
|-
 
|-
 
| 0x205
 
| 0x205
 
| 0x1
 
| 0x1
| Content Type (0=Program, 1=Meta, 2=Control, 3=Manual, 4=Data, 5=PublicData)
+
| Content Type (0 = Program, 1 = Meta, 2 = Control, 3 = Manual, 4 = Data, 5 = PublicData)
 
|-
 
|-
 
| 0x206
 
| 0x206
 
| 0x1
 
| 0x1
| Crypto Type. Only used stating with [[3.0.0]]. Normally 0. 2 = Crypto supported starting with [[3.0.0]].
+
| Old Key Generation (0 = [[1.0.0]], 2 = [[3.0.0]])
 
|-
 
|-
 
| 0x207
 
| 0x207
 
| 0x1
 
| 0x1
| Key index, must be 0-2.
+
| Key Area Encryption Key Index (0 = Application, 1 = Ocean, 2 = System)
 
|-
 
|-
 
| 0x208
 
| 0x208
 
| 0x8
 
| 0x8
| Size of the entire NCA.
+
| Size of the entire NCA
 
|-
 
|-
 
| 0x210
 
| 0x210
 
| 0x8
 
| 0x8
| titleID
+
| Title ID
 
|-
 
|-
 
| 0x218
 
| 0x218
 
| 0x4
 
| 0x4
| contentIndex
+
| Content Index
 
|-
 
|-
 
| 0x21C
 
| 0x21C
 
| 0x4
 
| 0x4
| sdk_version. byte0 is normally 0? Compared with a required minimum-value(0x000B0000). Matches this string from codebin: "FS_ACCESS: { sdk_version: {byte3}.{byte2}.{byte1}, ...".
+
| SDK AddOn Version (used in "FS_ACCESS: { sdk_version: {byte3}.{byte2}.{byte1}, ..." with byte0 set to 0 and compared with a required minimum value: 0x000B0000)
 
|-
 
|-
 
| 0x220
 
| 0x220
 
| 0x1
 
| 0x1
| Crypto-Type2. Selects which crypto-sysver to use. 0x3 = [[3.0.1]], 0x4 = [[4.0.0]], 0x5 = [[5.0.0]].
+
| Key Generation (3 = [[3.0.1]], 4 = [[4.0.0]], 5 = [[5.0.0]])
 
|-
 
|-
 
| 0x230
 
| 0x230
Line 69: Line 69:  
| 0x240
 
| 0x240
 
| 0x10*0x4(0x40)
 
| 0x10*0x4(0x40)
| Table for each section, see below.
+
| Table for each section (see below)
 
|-
 
|-
 
| 0x280
 
| 0x280
 
| 0x20*0x4(0x80)
 
| 0x20*0x4(0x80)
| Table of SHA256 hashes, over each 0x200-byte Section Header Block.
+
| Table of SHA256 hashes (over each 0x200-byte [[#Section Header Block|Section Header Block]])
 
|-
 
|-
 
| 0x300
 
| 0x300
Line 79: Line 79:  
| Key area
 
| Key area
 
|}
 
|}
      
The header is 0x400-bytes, at NCA+0.
 
The header is 0x400-bytes, at NCA+0.
   −
When the above "Crypto Type" field is 0x2 on >=v3.0, different {crypto/keydata} is used for the sections' data. With system content, this is used with every ncatype except ncatype0. The only other exception is {data-content} for the firm titles: this is required in order for older-system-versions to install it.
+
When the above '''Old Key Generation''' field is 0x2 on >= v3.0, different {crypto/keydata} is used for the sections' data. With system content, this is used with every ncatype except ncatype0. The only other exception is {data-content} for the firm titles: this is required in order for older-system-versions to install it.
   −
Crypto-Type2 0x3(with the above crypto-type value) is used for all [[3.0.1]] sysmodules and the [[System_Version_Title]].
+
'''Key Generation''' 0x3 (with '''Old Key Generation''' set to 0x2) is used for all [[3.0.1]] sysmodules and the [[System_Version_Title]].
    
With [[3.0.2]], all updated titles use the crypto from [[3.0.1]] for non-ncatype0, except for firm {data-content}.
 
With [[3.0.2]], all updated titles use the crypto from [[3.0.1]] for non-ncatype0, except for firm {data-content}.
Line 92: Line 91:     
The keyindex passed to <key-generation-related code> is determined as follows:
 
The keyindex passed to <key-generation-related code> is determined as follows:
* Pre-[[3.0.0]]: The ncahdr keyindex field(0x207) is passed directly.
+
* Pre-[[3.0.0]]: The '''Key Area Encryption Key Index''' field (0x207) is passed directly.
* [[3.0.0]]+: It's determined using ncahdr keyindex(0x207) and "Crypto Type"(0x206). The latter field must be 0-2. In each ncahdr_keyindex block, it executes "if(ncahdr_x206>=3)<panic>", but that won't trigger due to the earlier check. The end result is basically the same as pre-[[3.0.0]], except when ncahdr_x206 == 0x2, final_index is new_base_index+ncahdr_keyindex. Actual implementation loads index from u32_array[ncahdr_crypto_type], where the address of u32_array is different for each ncahdr_keyindex.
+
* [[3.0.0]]+: It's determined using the '''Key Area Encryption Key Index''' field (0x207) and the '''Old Key Generation''' field (0x206). The latter field must be 0, 1 or 2. In each ncahdr_keyindex block, it executes "if(ncahdr_x206>=3)<panic>", but that won't trigger due to the earlier check. The end result is basically the same as pre-[[3.0.0]], except when ncahdr_x206 == 0x2, final_index is new_base_index+ncahdr_keyindex. Actual implementation loads index from u32_array[ncahdr_crypto_type], where the address of u32_array is different for each ncahdr_keyindex.
* [[3.0.1]]+: The dedicated range check for ncahdr_x206("Crypto Type") was removed, since the updated code no longer needs it. The output from a function masked with 0xFF is now used instead of ncahdr_x206(ncahdr_crypto_type). The range check for that field was changed from {ncahdr_x206 check with panic described above}, to "if(index>=4)final_index=10;"(skips accessing the array and uses 10 directly). The arrays were updated with an additional entry: final_index=v301_base_index+ncahdr_keyindex.
+
* [[3.0.1]]+: The dedicated range check for the '''Old Key Generation''' field (0x206) was removed, since the updated code no longer needs it. The output from a function masked with 0xFF is now used instead of ncahdr_x206. The range check for that field was changed from {ncahdr_x206 check with panic described above}, to "if(index>=4)final_index=10;"(skips accessing the array and uses 10 directly). The arrays were updated with an additional entry: final_index=v301_base_index+ncahdr_keyindex.
 
** The keydata for the above index10 is not(?) known to be initialized.
 
** The keydata for the above index10 is not(?) known to be initialized.
 
** The new function called by the code described above does:
 
** The new function called by the code described above does:
 
** <code>if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret;</code>
 
** <code>if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret;</code>
   −
==Section Table Entry==
+
== Section Table Entry ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 108: Line 107:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Media offset
+
| Media Start Offset
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Media end-offset
+
| Media End Offset
 
|-
 
|-
 
| 0x8
 
| 0x8
Line 125: Line 124:  
Entry size is 0x10-bytes.
 
Entry size is 0x10-bytes.
   −
Media offset is absoluteoffset/{mediasize}, where mediasize is hard-coded to 0x200.
+
Media offset is absoluteoffset/{mediasize}, where mediasize is 0x200 bytes.
   −
=Section Header Block=
+
= Section Header Block =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 136: Line 135:  
| 0x0
 
| 0x0
 
| 0x2
 
| 0x2
| Version. Always 0x2
+
| Version (always 2)
 
|-
 
|-
 
| 0x2
 
| 0x2
 
| 0x1
 
| 0x1
| Filesystem Type. 0x0 = RomFS. 0x1 = PFS0
+
| Filesystem Type (0 = RomFS, 1 = PFS0)
 
|-
 
|-
 
| 0x3
 
| 0x3
 
| 0x1
 
| 0x1
| Hash Type. 0x2 = PFS0. 0x3 = RomFS
+
| Hash Type (2 = PFS0, 3 = RomFS)
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x1
 
| 0x1
| Crypto type. 0 and >4 are invalid. 1 = none(plaintext from raw NCA). 2 = other crypto. 3 = regular crypto. 4 = unknown.
+
| Encryption Type (1 = None, 2 = AesCtrOld, 3 = AesCtr, 4 = AesCtrEx)
 
|-
 
|-
 
| 0x5
 
| 0x5
 
| 0x1
 
| 0x1
| Padding?
+
| Padding
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0xF8
 
| 0xF8
| FS-specific superblock.
+
| FS-specific superblock
 
|-
 
|-
 
| 0x100
 
| 0x100
 
| ?
 
| ?
| Optional BKTR header. Can be used with any section, but only known to be used with game-updates RomFS.
+
| Optional BKTR header (can be used with any section, but only known to be used with game-updates RomFS)
 
|}
 
|}
   Line 167: Line 166:  
The total size is 0x200-bytes.
 
The total size is 0x200-bytes.
   −
==PFS0 superblock==
+
== PFS0 superblock ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 176: Line 175:  
| 0x0
 
| 0x0
 
| 0x20
 
| 0x20
| SHA256 hash over the hash-table at section-start+0 with the below hash-table size.
+
| SHA256 hash over the hash-table at section-start+0 with the below hash-table size
 
|-
 
|-
 
| 0x20
 
| 0x20
 
| 0x4
 
| 0x4
| Block size in bytes.
+
| Block size in bytes
 
|-
 
|-
 
| 0x24
 
| 0x24
 
| 0x4
 
| 0x4
| Must be 0x2.
+
| Must be 0x2
 
|-
 
|-
 
| 0x28
 
| 0x28
 
| 0x8
 
| 0x8
| Offset of hash-table. Normally zero?
+
| Offset of hash-table (normally zero)
 
|-
 
|-
 
| 0x30
 
| 0x30
 
| 0x8
 
| 0x8
| Size of hash-table.
+
| Size of hash-table
 
|-
 
|-
 
| 0x38
 
| 0x38
 
| 0x8
 
| 0x8
| Offset relative to section-start where the PFS0 header is located.
+
| Offset relative to section-start where the PFS0 header is located
 
|-
 
|-
 
| 0x40
 
| 0x40
 
| 0x8
 
| 0x8
| Actual byte-size of the PFS0 filesystem relative to the PFS0 header.
+
| Actual byte-size of the PFS0 filesystem relative to the PFS0 header
 
|-
 
|-
 
| 0x48
 
| 0x48
 
| 0xB0
 
| 0xB0
| Normally zeros.
+
| Empty
 
|}
 
|}
   −
==RomFS superblock==
+
== RomFS superblock ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 216: Line 215:  
| 0x8
 
| 0x8
 
| 0xE0
 
| 0xE0
| IVFC header. Basically the same as [[Savegames]] IVFC except with 2 more levels and +0x0C is non-zero, see below.
+
| IVFC header (basically the same as [[Savegames]] IVFC except with 2 more levels and +0x0C is non-zero, see below)
 
|}
 
|}
   Line 230: Line 229:  
| 0x00
 
| 0x00
 
| 4
 
| 4
| Magic ("IVFC")
+
| Magicnum "IVFC"
 
|-
 
|-
 
| 0x04
 
| 0x04
Line 254: Line 253:  
| 0x20
 
| 0x20
 
| 4
 
| 4
| Level 1 block size, in log2
+
| Level 1 block size (in log2)
 
|-
 
|-
 
| 0x24
 
| 0x24
Line 270: Line 269:  
| 0x38
 
| 0x38
 
| 4
 
| 4
| Level 2 block size, in log2.
+
| Level 2 block size (in log2)
 
|-
 
|-
 
| 0x3C
 
| 0x3C
Line 286: Line 285:  
| 0x50
 
| 0x50
 
| 4
 
| 4
| Level 3 block size, in log2.
+
| Level 3 block size (in log2)
 
|-
 
|-
 
| 0x54
 
| 0x54
Line 302: Line 301:  
| 0x68
 
| 0x68
 
| 4
 
| 4
| Level 4 block size, in log2.
+
| Level 4 block size (in log2)
 
|-
 
|-
 
| 0x6C
 
| 0x6C
Line 318: Line 317:  
| 0x80
 
| 0x80
 
| 4
 
| 4
| Level 5 block size, in log2.
+
| Level 5 block size (in log2)
 
|-
 
|-
 
| 0x84
 
| 0x84
Line 334: Line 333:  
| 0x98
 
| 0x98
 
| 4
 
| 4
| Level 6 block size, in log2.
+
| Level 6 block size (in log2)
 
|-
 
|-
 
| 0x9C
 
| 0x9C
Line 350: Line 349:     
== BKTR ==
 
== BKTR ==
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 360: Line 358:  
| 0x8
 
| 0x8
 
| Offset
 
| Offset
|-
   
|-
 
|-
 
| 0x8
 
| 0x8
Line 368: Line 365:  
| 0x10
 
| 0x10
 
| 0x4
 
| 0x4
| "BKTR"
+
| Magicnum "BKTR"
 
|-
 
|-
 
| 0x14
 
| 0x14
Line 401: Line 398:  
The two sections specified by the two BKTR entries are usually(?) at the very end of the section data(section_endoffset-{size of BKTR sections}).
 
The two sections specified by the two BKTR entries are usually(?) at the very end of the section data(section_endoffset-{size of BKTR sections}).
   −
===RomFS Patching===
+
=== RomFS Patching ===
 
   
The BKTR section enables combining data from an update NCA with the RomFS from a base NCA to create a single patched RomFS image.  
 
The BKTR section enables combining data from an update NCA with the RomFS from a base NCA to create a single patched RomFS image.  
   Line 474: Line 470:  
| 0x4000 || 0x4000*X || Subsection Buckets
 
| 0x4000 || 0x4000*X || Subsection Buckets
 
|}
 
|}
      
Where subsection buckets are as follows:
 
Where subsection buckets are as follows:
Line 510: Line 505:  
Official code assumes the relocation entries are sorted, and performs a binary search when determining where to read from. Each subsection in the Patch RomFS has its CTR calculated separately from the others based on the value in its entry (the BKTR entries use normal crypto). Thus decrypting a Patch RomFS requires decrypting and parsing the BKTR entries before anything else.
 
Official code assumes the relocation entries are sorted, and performs a binary search when determining where to read from. Each subsection in the Patch RomFS has its CTR calculated separately from the others based on the value in its entry (the BKTR entries use normal crypto). Thus decrypting a Patch RomFS requires decrypting and parsing the BKTR entries before anything else.
   −
=Logo section=
+
= Logo section =
This is a PFS0. See [[NCA_Content_FS|here]] for the mounted-FS logo contents.
+
This is a PFS0.
 +
 
 +
See [[NCA_Content_FS|here]] for the mounted-FS logo contents.
   −
=ExeFS section =
+
= ExeFS section =
 
This is a PFS0.
 
This is a PFS0.
    
See [[ExeFS|here]] for mounted-FS ExeFS contents.
 
See [[ExeFS|here]] for mounted-FS ExeFS contents.
   −
=Game-updates=
+
= Game-updates =
 
The section-data for ncatype1 RomFS section(section1) uses section-crypto-type 0x4.
 
The section-data for ncatype1 RomFS section(section1) uses section-crypto-type 0x4.
    
Game-updates also contain multiple ncatype6 content, which contain "section0_pfs0/fragment". Some of these are just NCAs, unknown for the rest(presumably NCAs with additional crypto?). The first ncatype6 content fragment file has a NDV0 header, with the NCA starting at offset 0x44.
 
Game-updates also contain multiple ncatype6 content, which contain "section0_pfs0/fragment". Some of these are just NCAs, unknown for the rest(presumably NCAs with additional crypto?). The first ncatype6 content fragment file has a NDV0 header, with the NCA starting at offset 0x44.
   −
=PFS0=
+
= PFS0 =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 557: Line 554:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| "PFS0" Magic
+
| Magicnum "PFS0"
 
|-
 
|-
 
| 0x4
 
| 0x4

Navigation menu