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 signature, presumably. | + | | 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 | + | | RomAreaStartPageAddress (in Gamecard page units, which are 0x200 bytes) |
| |- | | |- |
| | 0x108 | | | 0x108 |
| | 0x4 | | | 0x4 |
− | | 0xFFFFFFFF | + | | BackupAreaStartPageAddress (always 0xFFFFFFFF) |
| |- | | |- |
| | 0x10C | | | 0x10C |
− | | 0x4 | + | | 0x1 |
− | | ? | + | | TitleKeyDecIndex (high nibble) and KekIndex (low nibble) |
| + | |- |
| + | | 0x10D |
| + | | 0x1 |
| + | | [[#RomSize]] |
| + | |- |
| + | | 0x10E |
| + | | 0x1 |
| + | | CardHeaderVersion |
| + | |- |
| + | | 0x10F |
| + | | 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 ? | + | | 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]]. |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Value |
| + | ! Description |
| + | |- |
| + | | 0xFA |
| + | | 1GB |
| + | |- |
| + | | 0xF8 |
| + | | 2GB |
| + | |- |
| + | | 0xF0 |
| + | | 4GB |
| + | |- |
| + | | 0xE0 |
| + | | 8GB |
| + | |- |
| + | | 0xE1 |
| + | | 16GB |
| + | |- |
| + | | 0xE2 |
| + | | 32GB |
| + | |} |
| + | |
| + | === 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]]. |
| | | |
− | = Cert = | + | === ApplicationIdListEntryCount === |
| + | This is the number of entries in the ApplicationIdList located right before ValidDataEndAddress. |
| | | |
− | This is for the CERT, located at Gamecard + 0x7000 (always?). This matches exactly the output from fsp-srv IDeviceOperator cmd 206 "GetGameCardDeviceCertificate". | + | === 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" |
| + | |- |
| + | ! 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). |
| + | |
| + | {| 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" | | {| class="wikitable" border="1" |
| |- | | |- |
Line 90: |
Line 462: |
| | 0x0 | | | 0x0 |
| | 0x100 | | | 0x100 |
− | | RSA-2048 signature, presumably. | + | | 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. |
| + | |
| + | [[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 | | | 0x100 |
| | 0x4 | | | 0x4 |
− | | Magicnum "CERT" | + | | Magic ("CERT") |
| + | |- |
| + | | 0x104 |
| + | | 0x4 |
| + | | Version |
| + | |- |
| + | | 0x108 |
| + | | 0x1 |
| + | | KekIndex |
| + | |- |
| + | | 0x109 |
| + | | 0x7 |
| + | | Reserved |
| |- | | |- |
| | 0x110 | | | 0x110 |
| | 0x10 | | | 0x10 |
− | | ? | + | | T1CardDeviceId |
| |- | | |- |
− | | 0x12A | + | | 0x120 |
− | | 0xD6 | + | | 0x10 |
− | | Encrypted data. Some kind of key? | + | | Iv |
| + | |- |
| + | | 0x130 |
| + | | 0x10 |
| + | | HwKey (encrypted) |
| + | |- |
| + | | 0x140 |
| + | | 0xC0 |
| + | | Reserved (encrypted) |
| + | |- |
| + | | 0x200 |
| + | | 0x7E00 |
| + | | Reserved |
| |} | | |} |
| | | |
− | The data between the CERT and the start of the HFS0 is all 0xFF.
| + | == NormalArea == |
| + | This region contains all non-secure partitions of the Gamecard file system. |
| | | |
− | = HFS0 = | + | {| class="wikitable" border="1" |
− | This is the FS which has magicnum "HFS0" at header+0. | + | |- |
| + | ! 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" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | Variable |
| + | | Variable |
| + | | [[#PartitionFsHeader|SecurePartitionHeader]] |
| + | |- |
| + | | Variable |
| + | | Variable |
| + | | [[#SecurePartition|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]]. |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
Line 118: |
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 167: |
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 175: |
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?). |