Changes

no edit summary
Line 1: Line 1:  +
NCA means «Nintendo Content Archive».
 +
 
The entire raw NCAs are encrypted.
 
The entire raw NCAs are encrypted.
   Line 25: Line 27:  
| 0x200
 
| 0x200
 
| 0x4
 
| 0x4
| Magicnum "NCA3" ("NCA2", "NCA1" or "NCA0" for pre-1.0.0 NCAs)
+
| Magic "NCA3" ("NCA2", "NCA1" or "NCA0" for pre-1.0.0 NCAs)
 
|-
 
|-
 
| 0x204
 
| 0x204
 
| 0x1
 
| 0x1
| DistributionType (0x00 = System NCA, 0x01 = Gamecard NCA)
+
| DistributionType (0x00 = Download, 0x01 = GameCard)
 
|-
 
|-
 
| 0x205
 
| 0x205
Line 61: Line 63:  
| 0x220
 
| 0x220
 
| 0x1
 
| 0x1
| KeyGeneration (0x03 = [[3.0.1]], 0x04 = [[4.0.0]], 0x05 = [[5.0.0]], 0x06 = [[6.0.0]], 0x07 = [[6.2.0]], 0x08 = [[7.0.0]], 0x09 = [[8.1.0]], 0x0A = [[9.0.0]], 0x0B = [[9.1.0]], 0xFF = Invalid)
+
| KeyGeneration (0x03 = [[3.0.1]], 0x04 = [[4.0.0]], 0x05 = [[5.0.0]], 0x06 = [[6.0.0]], 0x07 = [[6.2.0]], 0x08 = [[7.0.0]], 0x09 = [[8.1.0]], 0x0A = [[9.0.0]], 0x0B = [[9.1.0]], 0x0C = [[12.1.0]], 0x0D = [[13.0.0]], 0x0E = [[14.0.0]], 0x0F = [[15.0.0]], 0x10 = [[16.0.0]], 0x11 = [[17.0.0]], 0x12 = [[18.0.0]], 0xFF = Invalid)
 
|-
 
|-
 
| 0x221
 
| 0x221
 
| 0x1
 
| 0x1
| [9.0.0+] Header1SignatureKeyGeneration (0 or 1)
+
| [9.0.0+] SignatureKeyGeneration
 
|-
 
|-
 
| 0x222
 
| 0x222
Line 111: Line 113:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| StartOffset (in Media Units which are 0x200 bytes)  
+
| StartOffset (in blocks which are 0x200 bytes)  
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| EndOffset (in Media Units which are 0x200 bytes)  
+
| EndOffset (in blocks which are 0x200 bytes)  
 
|-
 
|-
 
| 0x8
 
| 0x8
| 0x4
+
| 0x8
| Reserved
  −
|-
  −
| 0xC
  −
| 0x4
   
| Reserved
 
| Reserved
 
|}
 
|}
Line 139: Line 137:  
| 0x2
 
| 0x2
 
| 0x1
 
| 0x1
| FsType (0 = RomFs, 1 = PartitionFs)
+
| FsType (0 = RomFS, 1 = PartitionFS)
 
|-
 
|-
 
| 0x3
 
| 0x3
 
| 0x1
 
| 0x1
| HashType (0 = Auto, 2 = HierarchicalSha256, 3 = HierarchicalIntegrity)
+
| HashType (0 = Auto, 1 = None, 2 = HierarchicalSha256Hash, 3 = HierarchicalIntegrityHash, [14.0.0+] 4 = AutoSha3, [14.0.0+] 5 = HierarchicalSha3256Hash, [14.0.0+] 6 = HierarchicalIntegritySha3Hash)
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x1
 
| 0x1
| EncryptionType (0 = Auto, 1 = None, 2 = AesCtrOld, 3 = AesCtr, 4 = AesCtrEx)
+
| EncryptionType (0 = Auto, 1 = None, 2 = AesXts, 3 = AesCtr, 4 = AesCtrEx, [14.0.0+] 5 = AesCtrSkipLayerHash, [14.0.0+] 6 = AesCtrExSkipLayerHash)
 
|-
 
|-
 
| 0x5
 
| 0x5
 
| 0x1
 
| 0x1
| Padding
+
| [14.0.0+] MetaDataHashType (0 = None, 1 = HierarchicalIntegrity)
 +
|-
 +
| 0x6
 +
| 0x2
 +
| Reserved
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0xF8
 
| 0xF8
| [[#HashInfo|HashInfo]]
+
| [[#HashData|HashData]]
 
|-
 
|-
 
| 0x100
 
| 0x100
Line 171: Line 173:  
| 0x148
 
| 0x148
 
| 0x30
 
| 0x30
| SparseInfo (only used in sections with sparse storage)
+
| [[#SparseInfo|SparseInfo]] (only used in sections with sparse storage)
 
|-
 
|-
 
| 0x178
 
| 0x178
| 0x88
+
| 0x28
 +
| [12.0.0+] [[#CompressionInfo|CompressionInfo]]
 +
|-
 +
| 0x1A0
 +
| 0x30
 +
| [14.0.0+] [[#MetaDataHashDataInfo|MetaDataHashDataInfo]]
 +
|-
 +
| 0x1D0
 +
| 0x30
 
| Reserved
 
| Reserved
 
|}
 
|}
Line 180: Line 190:  
The FsHeader for each section is at absoluteoffset+0x400+(sectionid*0x200), where sectionid corresponds to the index used with the entry/hash tables.
 
The FsHeader for each section is at absoluteoffset+0x400+(sectionid*0x200), where sectionid corresponds to the index used with the entry/hash tables.
   −
== HashInfo ==
+
== HashData ==
 
This contains information specific to the hash type in use.
 
This contains information specific to the hash type in use.
   −
=== HierarchicalSha256 ===
+
=== HierarchicalSha256Data ===
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 192: Line 202:  
| 0x0
 
| 0x0
 
| 0x20
 
| 0x20
| SHA256 hash over the hash-table at section-start+0 with the below hash-table size
+
| MasterHash (SHA256 hash over the hash-table at section-start+0 with the below hash-table size)
 
|-
 
|-
 
| 0x20
 
| 0x20
 
| 0x4
 
| 0x4
| Block size in bytes
+
| BlockSize
 
|-
 
|-
 
| 0x24
 
| 0x24
 
| 0x4
 
| 0x4
| Must be 0x2
+
| LayerCount (always 2)
 
|-
 
|-
 
| 0x28
 
| 0x28
| 0x8
+
| 0x50
| Offset of hash-table (normally zero)
+
| [[#Region|LayerRegions]] (one region for the hash-table and another for PFS0 filesystem)
 +
|-
 +
| 0x78
 +
| 0x80
 +
| Reserved
 +
|}
 +
 
 +
==== Region ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
| 0x30
+
| 0x0
 
| 0x8
 
| 0x8
| Size of hash-table
+
| Offset
 
|-
 
|-
| 0x38
   
| 0x8
 
| 0x8
| Offset relative to section-start where the PFS0 header is located
  −
|-
  −
| 0x40
   
| 0x8
 
| 0x8
| Actual byte-size of the PFS0 filesystem relative to the PFS0 header
+
| Size
|-
  −
| 0x48
  −
| 0xB0
  −
| Reserved
   
|}
 
|}
   −
=== HierarchicalIntegrity ===
+
=== IntegrityMetaInfo ===
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 232: Line 246:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Magicnum "IVFC"
+
| Magic ("IVFC")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Magic Number (0x20000)
+
| Version
 
|-
 
|-
| 0xC
+
| 0x8
 
| 0x4
 
| 0x4
| Master hash size?
+
| MasterHashSize
 
|-
 
|-
| 0x10
+
| 0xC
| 0x4
+
| 0xB4
| Usually 7? Unknown, could be related to total number of levels maybe?
+
| [[#InfoLevelHash|InfoLevelHash]]
|-
  −
| 0x14
  −
| 0x8
  −
| Level 1 offset
  −
|-
  −
| 0x1C
  −
| 0x8
  −
| Level 1 size
   
|-
 
|-
 +
| 0xC0
 
| 0x20
 
| 0x20
| 0x4
+
| MasterHash
| Level 1 block size (in log2)
   
|-
 
|-
| 0x24
+
| 0xE0
| 0x4
+
| 0x18
 
| Reserved
 
| Reserved
 +
|}
 +
 +
==== InfoLevelHash ====
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x28
+
! Offset
| 0x8
+
! Size
| Level 2 offset
+
! Description
 
|-
 
|-
| 0x30
+
| 0x0
| 0x8
  −
| Level 2 size
  −
|-
  −
| 0x38
   
| 0x4
 
| 0x4
| Level 2 block size (in log2)
+
| MaxLayers
 
|-
 
|-
| 0x3C
   
| 0x4
 
| 0x4
| Reserved
+
| 0x90
 +
| [[#HierarchicalIntegrityVerificationLevelInformation|Levels]]
 
|-
 
|-
| 0x40
+
| 0x94
| 0x8
+
| 0x20
| Level 3 offset
+
| SignatureSalt
 +
|}
 +
 
 +
===== HierarchicalIntegrityVerificationLevelInformation =====
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x48
+
! Offset
| 0x8
+
! Size
| Level 3 size
+
! Description
 
|-
 
|-
| 0x50
+
| 0x0
| 0x4
  −
| Level 3 block size (in log2)
  −
|-
  −
| 0x54
  −
| 0x4
  −
| Reserved
  −
|-
  −
| 0x58
   
| 0x8
 
| 0x8
| Level 4 offset
+
| LogicalOffset
 
|-
 
|-
| 0x60
   
| 0x8
 
| 0x8
| Level 4 size
  −
|-
  −
| 0x68
  −
| 0x4
  −
| Level 4 block size (in log2)
  −
|-
  −
| 0x6C
  −
| 0x4
  −
| Reserved
  −
|-
  −
| 0x70
   
| 0x8
 
| 0x8
| Level 5 offset
+
| HashDataSize
 
|-
 
|-
| 0x78
+
| 0x10
| 0x8
  −
| Level 5 size
  −
|-
  −
| 0x80
   
| 0x4
 
| 0x4
| Level 5 block size (in log2)
+
| BlockSize (in log2)
 
|-
 
|-
| 0x84
+
| 0x14
 
| 0x4
 
| 0x4
 
| Reserved
 
| Reserved
|-
  −
| 0x88
  −
| 0x8
  −
| Level 6 offset
  −
|-
  −
| 0x90
  −
| 0x8
  −
| Level 6 size
  −
|-
  −
| 0x98
  −
| 0x4
  −
| Level 6 block size (in log2)
  −
|-
  −
| 0x9C
  −
| 0x4
  −
| Reserved
  −
|-
  −
| 0xA0
  −
| 0x20
  −
| Reserved
  −
|-
  −
| 0xC0
  −
| 0x20
  −
| Hash
   
|}
 
|}
   Line 360: Line 322:  
| 0x0
 
| 0x0
 
| 0x8
 
| 0x8
| Offset
+
| IndirectOffset
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x8
 
| 0x8
| Size
+
| IndirectSize
 
|-
 
|-
 
| 0x10
 
| 0x10
| 0x4
+
| 0x10
| Magicnum "BKTR"
+
| [[#BucketTreeHeader|IndirectHeader]]
 
|-
 
|-
| 0x14
+
| 0x20
| 0x4
+
| 0x8
| u32, must be <=1.
+
| AesCtrExOffset
 
|-
 
|-
| 0x18
+
| 0x28
| 0x4
+
| 0x8
| s32, must be >=1.
+
| AesCtrExSize
 
|-
 
|-
| 0x1C
+
| 0x30
| 0x4
+
| 0x10
|  
+
| [[#BucketTreeHeader|AesCtrExHeader]]
|-
  −
| 0x20
  −
| 0x20
  −
| Same as the above 0x20-bytes except with different data.
   
|}
 
|}
   Line 539: Line 497:     
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.
 +
 +
== SparseInfo ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TableOffset
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TableSize
 +
|-
 +
| 0x10
 +
| 0x10
 +
| [[#BucketTreeHeader|TableHeader]]
 +
|-
 +
| 0x20
 +
| 0x8
 +
| PhysicalOffset
 +
|-
 +
| 0x28
 +
| 0x2
 +
| Generation
 +
|-
 +
| 0x2A
 +
| 0x6
 +
| Reserved
 +
|}
 +
 +
== CompressionInfo ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TableOffset
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TableSize
 +
|-
 +
| 0x10
 +
| 0x10
 +
| [[#BucketTreeHeader|TableHeader]]
 +
|-
 +
| 0x20
 +
| 0x8
 +
| Reserved
 +
|}
 +
 +
== BucketTreeHeader ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x4
 +
| Magic ("BKTR")
 +
|-
 +
| 0x4
 +
| 0x4
 +
| Version
 +
|-
 +
| 0x8
 +
| 0x4
 +
| EntryCount
 +
|-
 +
| 0xC
 +
| 0x4
 +
| Reserved
 +
|}
 +
 +
== MetaDataHashDataInfo ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TableOffset
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TableSize
 +
|-
 +
| 0x10
 +
| 0x20
 +
| TableHash
 +
|}
    
= Logo Section =
 
= Logo Section =
Line 589: Line 647:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Magicnum "PFS0"
+
| Magic ("PFS0")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Number of files
+
| EntryCount
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Size of the string table
+
| StringTableSize
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Zero/Reserved
+
| Reserved
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| X
 
| X
| File Entry Table
+
| [[#PartitionEntry|PartitionEntryTable]]
 
|-
 
|-
 
| 0x10 + X
 
| 0x10 + X
 
| Y
 
| Y
| String Table
+
| StringTable
 
|-
 
|-
 
| 0x10 + X + Y
 
| 0x10 + X + Y
 
| Z
 
| Z
| Raw File Data
+
| FileData
 
|}
 
|}
   −
Where File Entry Table consists of Number of Files FileEntries:
+
== PartitionEntry ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 625: Line 683:  
| 0x0
 
| 0x0
 
| 0x8
 
| 0x8
| Offset of file in Data
+
| Offset
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x8
 
| 0x8
| Size of file in Data
+
| Size
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| 0x4
 
| 0x4
| Offset of filename in String Table
+
| StringOffset
 
|-
 
|-
 
| 0x14
 
| 0x14
 
| 0x4
 
| 0x4
| Normally zero?
+
| Reserved
 
|}
 
|}