Difference between revisions of "XCI"

From Nintendo Switch Brew
Jump to navigation Jump to search
(PKCS1 signatures)
 
(35 intermediate revisions by 7 users not shown)
Line 1: Line 1:
=Header=
+
This is the format used for storing the contents of a Nintendo Switch Gamecard.
The header is 0x200-bytes, at Gamecard+0.
 
  
 +
= Structure =
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1000
 +
| [[#CardKeyArea]]
 +
|-
 +
| 0x1000
 +
| 0x200
 +
| [[#CardHeader]]
 +
|-
 +
| 0x1200
 +
| 0x200
 +
| [11.0.0+] [[#NewCardHeader]]
 +
|-
 +
| 0x1400
 +
| 0x400
 +
| [11.0.0+] [[#NewCardHeaderCertArea]]
 +
|-
 +
| 0x1800
 +
| 0x6800
 +
| ReservedArea
 +
|-
 +
| 0x8000
 +
| 0x8000
 +
| [[#CertArea]]
 +
|-
 +
| 0x10000
 +
| Variable
 +
| [[#NormalArea]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#RomArea]]
 +
|-
 +
| Invalid
 +
| Invalid
 +
| BackupArea
 +
|}
 +
 +
== CardKeyArea ==
 +
This region cannot be read directly once written to the Gamecard. Therefore, it is hidden away during read/write operations on the raw Gamecard data.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x200
 +
| [[#InitialData]]
 +
|-
 +
| 0x200
 +
| 0xD00
 +
| [[#TitleKeyArea]]
 +
|-
 +
| 0xF00
 +
| 0x100
 +
| Reserved
 +
|}
 +
 +
=== InitialData ===
 +
This region is used for challenge–response authentication when changing to the Gamecard's secure mode.
 +
 +
[[Filesystem_services|FS]] calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the [[#CardHeader]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| Package ID from [[#CardHeader]] at offset 0x110
 +
|-
 +
| 0x8
 +
| 0x8
 +
| Reserved
 +
|-
 +
| 0x10
 +
| 0x10
 +
| Challenge–response authentication data
 +
|-
 +
| 0x20
 +
| 0x10
 +
| Challenge–response authentication MAC
 +
|-
 +
| 0x30
 +
| 0xC
 +
| Challenge–response authentication Nonce
 +
|-
 +
| 0x3C
 +
| 0x1C4
 +
| Reserved (must be empty)
 +
|}
 +
 +
=== TitleKeyArea ===
 +
This region is stored encrypted and contains the title keys used by the [[#InitialData]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TitleKey1
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TitleKey2
 +
|-
 +
| 0x10
 +
| 0xCF0
 +
| Reserved
 +
|}
 +
 +
== CardHeader ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 10: Line 134:
 
| 0x0
 
| 0x0
 
| 0x100
 
| 0x100
| RSA-2048 PKCS #1 signature over the data from 0x100 - 0x200.
+
| RSA-2048 PKCS #1 signature over the header (data from 0x100 to 0x200)
 
|-
 
|-
 
| 0x100
 
| 0x100
 
| 0x4
 
| 0x4
| Magicnum "HEAD"
+
| Magic ("HEAD")
 
|-
 
|-
 
| 0x104
 
| 0x104
 
| 0x4
 
| 0x4
| Offset of Secure partition (Size of non-secure data?), in Media Units (0x200 bytes for switch gamecarts)
+
| RomAreaStartPageAddress (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x108
 
| 0x108
 
| 0x4
 
| 0x4
| 0xFFFFFFFF
+
| BackupAreaStartPageAddress (always 0xFFFFFFFF)
 
|-
 
|-
 
| 0x10C
 
| 0x10C
 
| 0x1
 
| 0x1
| ?
+
| TitleKeyDecIndex (high nibble) and KekIndex (low nibble)
 
|-
 
|-
 
| 0x10D
 
| 0x10D
 
| 0x1
 
| 0x1
| Cartridge Size. 0xF8 = 2 GB, 0xF0 = 4 GB, 0xE0 = 8 GB, 0xE1 = 16 GB
+
| [[#RomSize]]
 
|-
 
|-
 
| 0x10E
 
| 0x10E
 
| 0x1
 
| 0x1
| ?
+
| CardHeaderVersion
 
|-
 
|-
 
| 0x10F
 
| 0x10F
 
| 0x1
 
| 0x1
| ?
+
| [[#Flags]]
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x8
 
| 0x8
| ?
+
| PackageId (used for challenge–response authentication)
 
|-
 
|-
 
| 0x118
 
| 0x118
| 0x8
+
| 0x4
| Size of the Gamecart, in Media Units
+
| ValidDataEndAddress (in Gamecard page units, which are 0x200 bytes)
 +
|-
 +
| 0x11C
 +
| 0x1
 +
| Reserved
 +
|-
 +
| 0x11D
 +
| 0x1
 +
| [18.0.0+] [[#Flags2]] ([1.0.0-17.0.1] Reserved)
 +
|-
 +
| 0x11E
 +
| 0x2
 +
| [19.0.0+] [[#ApplicationIdListEntryCount]] ([1.0.0-18.1.0] Reserved)
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| ?
+
| Iv (reversed)
 
|-
 
|-
 
| 0x130
 
| 0x130
 
| 0x8
 
| 0x8
| Offset of HFS0 FS partition
+
| PartitionFsHeaderAddress
 
|-
 
|-
 
| 0x138
 
| 0x138
| 8
+
| 0x8
| HFS0 Header size
+
| PartitionFsHeaderSize
 
|-
 
|-
 
| 0x140
 
| 0x140
 
| 0x20
 
| 0x20
| SHA256 hash of the HFS0 Header
+
| PartitionFsHeaderHash (SHA-256 hash of the [[#PartitionFsHeader]])
 
|-
 
|-
 
| 0x160
 
| 0x160
 
| 0x20
 
| 0x20
| SHA256 hash of the crypto header
+
| InitialDataHash (SHA-256 hash of the [[#InitialData]])
 
|-
 
|-
 
| 0x180
 
| 0x180
 
| 0x4
 
| 0x4
| 1?
+
| [[#SelSec]]
 
|-
 
|-
 
| 0x184
 
| 0x184
 
| 0x4
 
| 0x4
| 2?
+
| SelT1Key (always 2)
 
|-
 
|-
 
| 0x188
 
| 0x188
 
| 0x4
 
| 0x4
| 0?
+
| SelKey (always 0)
 
|-
 
|-
 
| 0x18C
 
| 0x18C
 
| 0x4
 
| 0x4
| Offset of Secure partition (Size of non-secure data?), in Media Units, again.
+
| LimArea (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x190
 
| 0x190
 
| 0x70
 
| 0x70
| Encrypted data/hashes of some kind
+
| [[#CardHeaderEncryptedData]]
 
|}
 
|}
  
 +
=== RomSize ===
 +
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardSize|GameCardSize]].
  
= Cert =
+
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0xFA
 +
| 1GB
 +
|-
 +
| 0xF8
 +
| 2GB
 +
|-
 +
| 0xF0
 +
| 4GB
 +
|-
 +
| 0xE0
 +
| 8GB
 +
|-
 +
| 0xE1
 +
| 16GB
 +
|-
 +
| 0xE2
 +
| 32GB
 +
|}
  
This is for the CERT, located at Gamecard + 0x7000 (always?). This matches exactly the output from fsp-srv IDeviceOperator cmd 206 "GetGameCardDeviceCertificate".
+
=== Flags ===
 +
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute|GameCardAttribute]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Bits
 +
! Description
 +
|-
 +
| 0
 +
| AutoBoot
 +
|-
 +
| 1
 +
| HistoryErase
 +
|-
 +
| 2
 +
| [4.0.0+] RepairTool
 +
|-
 +
| 3
 +
| [9.0.0+] DifferentRegionCupToTerraDevice
 +
|-
 +
| 4
 +
| [9.0.0+] DifferentRegionCupToGlobalDevice
 +
|-
 +
| 7
 +
| [11.0.0+] HasNewCardHeader
 +
|}
 +
 
 +
=== Flags2 ===
 +
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute2|GameCardAttribute2]].
 +
 
 +
=== ApplicationIdListEntryCount ===
 +
This is the number of entries in the ApplicationIdList located right before ValidDataEndAddress.
 +
 
 +
=== SelSec ===
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 1
 +
| T1
 +
|-
 +
| 2
 +
| T2
 +
|}
 +
 
 +
=== CardHeaderEncryptedData ===
 +
This region is stored encrypted (AES-128-CBC).
  
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| [[#FwVersion]]
 +
|-
 +
| 0x8
 +
| 0x4
 +
| [[#AccCtrl1]]
 +
|-
 +
| 0xC
 +
| 0x4
 +
| Wait1TimeRead (always 0x1388)
 +
|-
 +
| 0x10
 +
| 0x4
 +
| Wait2TimeRead (always 0)
 +
|-
 +
| 0x14
 +
| 0x4
 +
| Wait1TimeWrite (always 0)
 +
|-
 +
| 0x18
 +
| 0x4
 +
| Wait2TimeWrite (always 0)
 +
|-
 +
| 0x1C
 +
| 0x4
 +
| FwMode (the current SdkAddonVersion)
 +
|-
 +
| 0x20
 +
| 0x4
 +
| UppVersion
 +
|-
 +
| 0x24
 +
| 0x1
 +
| [9.0.0+] [[#CompatibilityType]]
 +
|-
 +
| 0x25
 +
| 0x3
 +
| Reserved
 +
|-
 +
| 0x28
 +
| 0x8
 +
| UppHash (SHA-256 hash of the [[#UpdatePartition]])
 +
|-
 +
| 0x30
 +
| 0x8
 +
| UppId (always 0x0100000000000816)
 +
|-
 +
| 0x38
 +
| 0x38
 +
| Reserved
 +
|}
 +
 +
==== FwVersion ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| Development
 +
|-
 +
| 1
 +
| Retail
 +
|-
 +
| 2
 +
| [4.0.0+] Retail
 +
|-
 +
| 3
 +
| [11.0.0+] Development
 +
|-
 +
| 4
 +
| [11.0.0+] Retail
 +
|-
 +
| 5
 +
| [12.0.0+] Retail
 +
|}
 +
 +
==== AccCtrl1 ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0x00A10011
 +
| 25MHz
 +
|-
 +
| 0x00A10010
 +
| 50MHz
 +
|}
 +
 +
==== CompatibilityType ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| Normal
 +
|-
 +
| 1
 +
| Terra
 +
|}
 +
 +
== NewCardHeader ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 102: Line 420:
 
| 0x0
 
| 0x0
 
| 0x100
 
| 0x100
| RSA-2048 PKCS #1 signature over the data from 0x100 - 0x200.
+
| RSA-2048 PKCS #1 signature over the data from 0x100 to 0x200
 
|-
 
|-
 
| 0x100
 
| 0x100
 +
| 0x90
 +
|
 +
|-
 +
| 0x190
 +
| 0x70
 +
| [[#NewCardHeaderEncryptedData]]
 +
|}
 +
 +
=== NewCardHeaderEncryptedData ===
 +
This region is stored encrypted (AES-128-CBC).
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x40
 +
|
 +
|-
 +
| 0x40
 +
| 0x20
 +
| SHA-256 hash of the [[#CardHeader]]
 +
|-
 +
| 0x60
 +
| 0x10
 +
| Reserved
 +
|}
 +
 +
== NewCardHeaderCertArea ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x100
 +
| RSA-2048 PKCS #1 signature over the data from 0x100 to 0x300
 +
|-
 +
| 0x100
 +
| 0x30
 +
|
 +
|-
 +
| 0x130
 +
| 0x100
 +
| [[#NewCardHeader]] modulus
 +
|-
 +
| 0x230
 
| 0x4
 
| 0x4
| Magicnum "CERT"
+
| [[#NewCardHeader]] exponent
 +
|-
 +
| 0x234
 +
| 0x1CC
 +
|
 +
|}
 +
 
 +
== CertArea ==
 +
This is the Gamecard's unique certificate.
 +
 
 +
[[Filesystem_services|FS]] retrieves this data with [[Filesystem_services#GetGameCardDeviceCertificate|GetGameCardDeviceCertificate]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x100
 +
| RSA-2048 PKCS #1 signature over the data from 0x100 to 0x200
 +
|-
 +
| 0x100
 +
| 0x4
 +
| Magic ("CERT")
 +
|-
 +
| 0x104
 +
| 0x4
 +
| Version
 +
|-
 +
| 0x108
 +
| 0x1
 +
| KekIndex
 +
|-
 +
| 0x109
 +
| 0x7
 +
| Reserved
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x10
 
| 0x10
| ?
+
| T1CardDeviceId
 +
|-
 +
| 0x120
 +
| 0x10
 +
| Iv
 +
|-
 +
| 0x130
 +
| 0x10
 +
| HwKey (encrypted)
 +
|-
 +
| 0x140
 +
| 0xC0
 +
| Reserved (encrypted)
 +
|-
 +
| 0x200
 +
| 0x7E00
 +
| Reserved
 +
|}
 +
 
 +
== NormalArea ==
 +
This region contains all non-secure partitions of the Gamecard file system.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|RootPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|UpdatePartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#UpdatePartition|UpdatePartition]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#PartitionFsHeader|LogoPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#LogoPartition|LogoPartition]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|NormalPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#NormalPartition|NormalPartition]]
 +
|}
 +
 
 +
=== UpdatePartition ===
 +
This partition contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
 +
 
 +
=== NormalPartition ===
 +
This partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition. Game icon data can still be shown in the home menu on old firmwares.
 +
 
 +
[4.0.0+] This partition is now empty.
 +
 
 +
=== LogoPartition ===
 +
[4.0.0+] This partition now contains the contents of the [[#NormalPartition]].
 +
 
 +
== RomArea ==
 +
This region contains all secure partitions of the Gamecard file system.
 +
 
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x12A
+
! Offset
| 0xD6
+
! Size
| Encrypted data. Some kind of key?
+
! Description
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|SecurePartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#SecurePartition|SecurePartition]]
 
|}
 
|}
  
The data between the CERT and the start of the HFS0 is all 0xFF.
+
=== SecurePartition ===
 +
This partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
  
= HFS0 =
+
== PartitionFs ==
This is the FS which has magicnum "HFS0" at header+0.
+
This is the Gamecard file system which starts with magicnum "HFS0".
 +
 
 +
=== PartitionFsHeader ===
 +
The "SHA-256 File System" or "HFS0" starts at offset 0x10000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure").
 +
 
 +
A hash for this header is stored at offset 0x140 in the [[#CardHeader]].
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 130: Line 619:
 
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| HFS0 Magic
+
| Magic ("HFS0")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Number of files
+
| FileCount
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Size of the string table
+
| StringTableSize
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Zero/Reserved
+
| Reserved
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| X
 
| X
| File Entry Table
+
| [[#FileEntryTable]]
 
|-
 
|-
 
| 0x10 + X
 
| 0x10 + X
 
| Y
 
| Y
| String Table
+
| StringTable
 
|-
 
|-
 
| 0x10 + X + Y
 
| 0x10 + X + Y
 
| Z
 
| Z
| Raw File Data
+
| RawFileData
 
|}
 
|}
  
Where File Entry Table consists of Number of Files FileEntries:
+
==== FileEntryTable ====
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 179: Line 667:
 
| 0x14
 
| 0x14
 
| 0x4
 
| 0x4
| Size of Hashed region of file (for HFS0s, this is the size of the pre-filedata portion, for NCAs this is usually 0x200).
+
| Size of Hashed region of file (for HFS0s, this is the size of the pre-filedata portion, for NCAs this is usually 0x200)
 
|-
 
|-
 
| 0x18
 
| 0x18
Line 187: Line 675:
 
| 0x20
 
| 0x20
 
| 0x20
 
| 0x20
| SHA256 hash of the first (size of hashed region) bytes of filedata.
+
| SHA-256 hash of the first (size of hashed region) bytes of filedata
 
|}
 
|}
  
 
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
 
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
 
=Typical Cartridge Layout=
 
Observed gamecarts contain three partitions: "update", "normal", and "secure".
 
 
The update partition (Gamecard partition 0 for fsp-srv cmd 31) contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
 
 
The normal partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition, Game icon data can still be shown in the home menu on old firmwares.
 
 
The secure partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
 
 
The entire rest of the gamecard after the secure partition ends is all FF padding.
 

Latest revision as of 22:03, 9 October 2024

This is the format used for storing the contents of a Nintendo Switch Gamecard.

Structure

Offset Size Description
0x0 0x1000 #CardKeyArea
0x1000 0x200 #CardHeader
0x1200 0x200 [11.0.0+] #NewCardHeader
0x1400 0x400 [11.0.0+] #NewCardHeaderCertArea
0x1800 0x6800 ReservedArea
0x8000 0x8000 #CertArea
0x10000 Variable #NormalArea
Variable Variable #RomArea
Invalid Invalid BackupArea

CardKeyArea

This region cannot be read directly once written to the Gamecard. Therefore, it is hidden away during read/write operations on the raw Gamecard data.

Offset Size Description
0x0 0x200 #InitialData
0x200 0xD00 #TitleKeyArea
0xF00 0x100 Reserved

InitialData

This region is used for challenge–response authentication when changing to the Gamecard's secure mode.

FS calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the #CardHeader.

Offset Size Description
0x0 0x8 Package ID from #CardHeader at offset 0x110
0x8 0x8 Reserved
0x10 0x10 Challenge–response authentication data
0x20 0x10 Challenge–response authentication MAC
0x30 0xC Challenge–response authentication Nonce
0x3C 0x1C4 Reserved (must be empty)

TitleKeyArea

This region is stored encrypted and contains the title keys used by the #InitialData.

Offset Size Description
0x0 0x8 TitleKey1
0x8 0x8 TitleKey2
0x10 0xCF0 Reserved

CardHeader

Offset Size Description
0x0 0x100 RSA-2048 PKCS #1 signature over the header (data from 0x100 to 0x200)
0x100 0x4 Magic ("HEAD")
0x104 0x4 RomAreaStartPageAddress (in Gamecard page units, which are 0x200 bytes)
0x108 0x4 BackupAreaStartPageAddress (always 0xFFFFFFFF)
0x10C 0x1 TitleKeyDecIndex (high nibble) and KekIndex (low nibble)
0x10D 0x1 #RomSize
0x10E 0x1 CardHeaderVersion
0x10F 0x1 #Flags
0x110 0x8 PackageId (used for challenge–response authentication)
0x118 0x4 ValidDataEndAddress (in Gamecard page units, which are 0x200 bytes)
0x11C 0x1 Reserved
0x11D 0x1 [18.0.0+] #Flags2 ([1.0.0-17.0.1] Reserved)
0x11E 0x2 [19.0.0+] #ApplicationIdListEntryCount ([1.0.0-18.1.0] Reserved)
0x120 0x10 Iv (reversed)
0x130 0x8 PartitionFsHeaderAddress
0x138 0x8 PartitionFsHeaderSize
0x140 0x20 PartitionFsHeaderHash (SHA-256 hash of the #PartitionFsHeader)
0x160 0x20 InitialDataHash (SHA-256 hash of the #InitialData)
0x180 0x4 #SelSec
0x184 0x4 SelT1Key (always 2)
0x188 0x4 SelKey (always 0)
0x18C 0x4 LimArea (in Gamecard page units, which are 0x200 bytes)
0x190 0x70 #CardHeaderEncryptedData

RomSize

FS retrieves this data as GameCardSize.

Value Description
0xFA 1GB
0xF8 2GB
0xF0 4GB
0xE0 8GB
0xE1 16GB
0xE2 32GB

Flags

FS retrieves this data as GameCardAttribute.

Bits Description
0 AutoBoot
1 HistoryErase
2 [4.0.0+] RepairTool
3 [9.0.0+] DifferentRegionCupToTerraDevice
4 [9.0.0+] DifferentRegionCupToGlobalDevice
7 [11.0.0+] HasNewCardHeader

Flags2

FS retrieves this data as GameCardAttribute2.

ApplicationIdListEntryCount

This is the number of entries in the ApplicationIdList located right before ValidDataEndAddress.

SelSec

Value Description
1 T1
2 T2

CardHeaderEncryptedData

This region is stored encrypted (AES-128-CBC).

Offset Size Description
0x0 0x8 #FwVersion
0x8 0x4 #AccCtrl1
0xC 0x4 Wait1TimeRead (always 0x1388)
0x10 0x4 Wait2TimeRead (always 0)
0x14 0x4 Wait1TimeWrite (always 0)
0x18 0x4 Wait2TimeWrite (always 0)
0x1C 0x4 FwMode (the current SdkAddonVersion)
0x20 0x4 UppVersion
0x24 0x1 [9.0.0+] #CompatibilityType
0x25 0x3 Reserved
0x28 0x8 UppHash (SHA-256 hash of the #UpdatePartition)
0x30 0x8 UppId (always 0x0100000000000816)
0x38 0x38 Reserved

FwVersion

Value Description
0 Development
1 Retail
2 [4.0.0+] Retail
3 [11.0.0+] Development
4 [11.0.0+] Retail
5 [12.0.0+] Retail

AccCtrl1

Value Description
0x00A10011 25MHz
0x00A10010 50MHz

CompatibilityType

Value Description
0 Normal
1 Terra

NewCardHeader

Offset Size Description
0x0 0x100 RSA-2048 PKCS #1 signature over the data from 0x100 to 0x200
0x100 0x90
0x190 0x70 #NewCardHeaderEncryptedData

NewCardHeaderEncryptedData

This region is stored encrypted (AES-128-CBC).

Offset Size Description
0x0 0x40
0x40 0x20 SHA-256 hash of the #CardHeader
0x60 0x10 Reserved

NewCardHeaderCertArea

Offset Size Description
0x0 0x100 RSA-2048 PKCS #1 signature over the data from 0x100 to 0x300
0x100 0x30
0x130 0x100 #NewCardHeader modulus
0x230 0x4 #NewCardHeader exponent
0x234 0x1CC

CertArea

This is the Gamecard's unique certificate.

FS retrieves this data with GetGameCardDeviceCertificate.

Offset Size Description
0x0 0x100 RSA-2048 PKCS #1 signature over the data from 0x100 to 0x200
0x100 0x4 Magic ("CERT")
0x104 0x4 Version
0x108 0x1 KekIndex
0x109 0x7 Reserved
0x110 0x10 T1CardDeviceId
0x120 0x10 Iv
0x130 0x10 HwKey (encrypted)
0x140 0xC0 Reserved (encrypted)
0x200 0x7E00 Reserved

NormalArea

This region contains all non-secure partitions of the Gamecard file system.

Offset Size Description
Variable Variable RootPartitionHeader
Variable Variable UpdatePartitionHeader
Variable Variable UpdatePartition
Variable Variable [4.0.0+] LogoPartitionHeader
Variable Variable [4.0.0+] LogoPartition
Variable Variable NormalPartitionHeader
Variable Variable NormalPartition

UpdatePartition

This partition contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.

NormalPartition

This partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition. Game icon data can still be shown in the home menu on old firmwares.

[4.0.0+] This partition is now empty.

LogoPartition

[4.0.0+] This partition now contains the contents of the #NormalPartition.

RomArea

This region contains all secure partitions of the Gamecard file system.

Offset Size Description
Variable Variable SecurePartitionHeader
Variable Variable SecurePartition

SecurePartition

This partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.

PartitionFs

This is the Gamecard file system which starts with magicnum "HFS0".

PartitionFsHeader

The "SHA-256 File System" or "HFS0" starts at offset 0x10000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure").

A hash for this header is stored at offset 0x140 in the #CardHeader.

Offset Size Description
0x0 0x4 Magic ("HFS0")
0x4 0x4 FileCount
0x8 0x4 StringTableSize
0xC 0x4 Reserved
0x10 X #FileEntryTable
0x10 + X Y StringTable
0x10 + X + Y Z RawFileData

FileEntryTable

Offset Size Description
0x0 0x8 Offset of file in Data
0x8 0x8 Size of file in Data
0x10 0x4 Offset of filename in String Table
0x14 0x4 Size of Hashed region of file (for HFS0s, this is the size of the pre-filedata portion, for NCAs this is usually 0x200)
0x18 8 Zero/Reserved
0x20 0x20 SHA-256 hash of the first (size of hashed region) bytes of filedata

The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).