Line 25: |
Line 25: |
| | 2 | | | 2 |
| | [[Download Play]] Child container ([[NCCH#CFA|CFA]]) | | | [[Download Play]] Child container ([[NCCH#CFA|CFA]]) |
| + | |- |
| + | | 6 |
| + | | New3DS [[System_Update_CFA|Update Data]] ([[NCCH#CFA|CFA]]) |
| |- | | |- |
| | 7 | | | 7 |
Line 61: |
Line 64: |
| | 0x118 | | | 0x118 |
| | 8 | | | 8 |
− | | Partitions crypt type | + | | Partitions crypt type (each byte corresponds to a partition in the partition table) |
| |- | | |- |
| | 0x120 | | | 0x120 |
| | 0x40=(4+4)*8 | | | 0x40=(4+4)*8 |
| | Offset & Length partition table, in media units | | | Offset & Length partition table, in media units |
| + | |- |
| + | | 0x160 |
| + | | 0xA0 |
| + | | ... |
| + | |} |
| + | |
| + | For carts, |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| |- | | |- |
| | 0x160 | | | 0x160 |
Line 88: |
Line 103: |
| |- | | |- |
| | 0x1D0 | | | 0x1D0 |
− | | 0x30 | + | | 0x20 |
| | Reserved | | | Reserved |
| + | |- |
| + | | 0x1F0 |
| + | | 0xE |
| + | | Reserved? |
| + | |- |
| + | | 0x1FE |
| + | | 0x1 |
| + | | Support for this was implemented with [[9.6.0-24|9.6.0-X]] FIRM. Bit0=1 enables using bits 1-2, it's unknown what these two bits are actually used for(the value of these two bits get compared with some other value during NCSD verification/loading). This appears to enable a new, likely hardware-based, antipiracy check on cartridges. |
| + | |- |
| + | | 0x1FF |
| + | | 0x1 |
| + | | Support for this was implemented with [[9.6.0-24|9.6.0-X]] FIRM, see below regarding save crypto. |
| + | |} |
| + | |
| + | For NAND, |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x160 |
| + | | 0x5E |
| + | | Unknown |
| + | |- |
| + | | 0x1BE |
| + | | 0x42 |
| + | | Encrypted MBR partition-table, for the TWL partitions(key-data used for this keyslot is console-unique). |
| |} | | |} |
| + | |
| + | === NCSD Signature === |
| + | The RSA public key used for gamecard NCSD is stored in [[Memory_layout|ITCM]]. The separate public key used for NAND NCSD is stored in Process9 .(ro)data instead of ITCM, and in [[Bootloader|boot ROM]]. |
| + | |
| + | For the boot ROM check, sighax may be used to fake-sign NAND headers. Process9's check will fail, however, unless patched. |
| | | |
| === Partition Flags === | | === Partition Flags === |
Line 124: |
Line 173: |
| |- | | |- |
| | 1 | | | 1 |
− | | Starting with [[6.0.0-11]] NATIVE_FIRM will use this flag to determine the gamecard [[Savegames|savegame]] keyY method, when flag[3] is set. 0 = [[2.0.0-2]] hashed keyY, 1 = [[Savegames|new]] keyY method implemented with [[6.0.0-11]]. | + | | Starting with [[6.0.0-11]] NATIVE_FIRM will use this flag to determine the gamecard [[Savegames|savegame]] keyY method, when flag[3] is set. 0 = [[2.0.0-2]] hashed keyY, 1 = [[Savegames|new]] keyY method implemented with [[6.0.0-11]]. 0x0A = implemented with [[9.3.0-21|9.3.0-X]]. On Old3DS this is identical to the [[2.2.0-4]] crypto. On New3DS this is identical to the [[2.2.0-4]] crypto, except with New3DS-only gamecard savedata [[AES|keyslots]]. |
| + | Starting with [[9.6.0-24|9.6.0-X]] FIRM, Process9 now sets <savecrypto_stateval> to partitionflag[1] + <the u8 value from NCSD+0x1FF>, instead of just setting it to partitionflag[1]. |
| |- | | |- |
| | 3 | | | 3 |
| | Support for this flag was implemented in NATIVE_FIRM with [[2.0.0-2]]. When this flag is set the hashed gamecard [[Savegames|savegame]] keyY method is used, this likely still uses the repeating-CTR however. With [[6.0.0-11]] the system will determine the gamecard savegame keyY method via flag[1], instead of just using the hashed keyY via this flag. | | | Support for this flag was implemented in NATIVE_FIRM with [[2.0.0-2]]. When this flag is set the hashed gamecard [[Savegames|savegame]] keyY method is used, this likely still uses the repeating-CTR however. With [[6.0.0-11]] the system will determine the gamecard savegame keyY method via flag[1], instead of just using the hashed keyY via this flag. |
− | |- | + | |-th |
| | 7 | | | 7 |
| | This flag enables using the hashed gamecard [[Savegames|savegame]] keyY method, support for this flag was implemented in NATIVE_FIRM with [[2.2.0-4]]. All games with the NCSD image finalized since [[2.2.0-4]](and contains [[2.2.0-4]]+ in the system update partition) have this flag set, this flag also enables using new CTR method as well. | | | This flag enables using the hashed gamecard [[Savegames|savegame]] keyY method, support for this flag was implemented in NATIVE_FIRM with [[2.2.0-4]]. All games with the NCSD image finalized since [[2.2.0-4]](and contains [[2.2.0-4]]+ in the system update partition) have this flag set, this flag also enables using new CTR method as well. |
| |} | | |} |
| + | |
| + | Starting with [[9.6.0-24|9.6.0-X]] FIRM, Process9 will just write val0 to a state field then return 0, instead of returning an error when the save crypto type isn't recognized. This was the *only* actual functionality change in the Old3DS Process9 function for gamecard savedata crypto init. |
| | | |
| == Card Info Header == | | == Card Info Header == |
Line 149: |
Line 201: |
| |- | | |- |
| | 0x208 | | | 0x208 |
− | | 0xDF8 | + | | 0xF8 |
− | | Reserved1 | + | | Reserved |
| + | |- |
| + | | 0x300 |
| + | | 4 |
| + | | Filled size of cartridge |
| + | |- |
| + | | 0x304 |
| + | | 0xC |
| + | | Reserved |
| + | |- |
| + | | 0x310 |
| + | | 2 |
| + | | Title version |
| + | |- |
| + | | 0x312 |
| + | | 2 |
| + | | Card revision |
| + | |- |
| + | | 0x314 |
| + | | 0xC |
| + | | Reserved |
| + | |- |
| + | | 0x320 |
| + | | 8 |
| + | | Title ID of [[CVer]] in included update partition |
| + | |- |
| + | | 0x328 |
| + | | 2 |
| + | | Version number of [[CVer]] in included update partition |
| + | |- |
| + | | 0x32A |
| + | | 0xCD6 |
| + | | Reserved |
| |- | | |- |
| | 0x1000 | | | 0x1000 |
− | | 8 | + | | 0x200 |
− | | Media ID (same as first NCCH partitionId) | + | | InitialData |
| + | |} |
| + | |
| + | === InitialData === |
| + | |
| + | This data is returned by [[Gamecards|16-byte cartridge command]] 0x82. |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET |
| + | ! SIZE |
| + | ! DESCRIPTION |
| + | |- |
| + | | 0x00 |
| + | | 0x10 |
| + | | Seed (keyY used to decrypt the title key - keyX is keyslot 0x3B for production cards, or a key of all zeroes for development cards), consisting of the title ID (little-endian) followed by reserved data (normally all-zero) |
| + | |- |
| + | | 0x10 |
| + | | 0x10 |
| + | | TitleKey (AES-CCM encrypted) |
| |- | | |- |
− | | 0x1008 | + | | 0x20 |
− | | 8 | + | | 0x10 |
− | | Reserved2 | + | | AES-CCM MAC |
| |- | | |- |
− | | 0x1010
| |
| | 0x30 | | | 0x30 |
− | | Initial Data | + | | 0xC |
| + | | AES-CCM nonce |
| |- | | |- |
− | | 0x1040 | + | | 0x3C |
− | | 0xC0 | + | | 0xC4 |
− | | Reserved | + | | Reserved (normally all-zero) |
| |- | | |- |
− | | 0x1100
| |
| | 0x100 | | | 0x100 |
− | | Copy of first NCCH header (excluding RSA signature) | + | | 0x100 |
| + | | NcchHeader (copy of the first NCCH header, excluding the RSA signature) |
| |} | | |} |
| | | |
Line 186: |
Line 289: |
| | 0x1400 | | | 0x1400 |
| | 0x10 | | | 0x10 |
− | | TitleKey | + | | TitleKeyData |
| |- | | |- |
| | 0x1410 | | | 0x1410 |
− | | 0xF0 | + | | 0x1BF0 |
| | CardDeviceReserved2 | | | CardDeviceReserved2 |
| + | |- |
| + | | 0x3000 |
| + | | 0x1000 |
| + | | TestData |
| + | |} |
| + | |
| + | TitleKeyData contains the decrypted version of the title key found in the InitialData. This field appears to be what development--and maybe production?--cards read to know what card encryption seed to use in the CTR protocol. |
| + | |
| + | The CardDeviceReserved areas have random-looking data whose purpose is unknown, other than perhaps to hide the TitleKey. |
| + | |
| + | Note that a particular flashcard vendor, namely Gateway, puts what many refer to as "private headers" at CardDeviceReserved1 in place of actual development card information. This header consists of: |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET |
| + | ! SIZE |
| + | ! DESCRIPTION |
| + | |- |
| + | | 0x0 |
| + | | 0x40 |
| + | | Unique cartridge ID; only the first 0x10 bytes are meaningful, the rest are 0xff; obtainable using encrypted [[Gamecards|16-byte cartridge command]] 0xc6; the first 0x10 bytes can also be obtained in userland via [[Process_Services_PXI|pxi:ps9::GetRomId]] |
| + | |- |
| + | | 0x40 |
| + | | 0x4 |
| + | | Cartridge ID1; obtainable using 8-byte cartridge command 0x90 or 16-byte cartridge command 0xa2 |
| + | |- |
| + | | 0x44 |
| + | | 0x4 |
| + | | Cartridge ID2; obtainable using 8-byte cartridge command 0xa0 or 16-byte cartridge command 0xa4 |
| + | |- |
| + | | 0x48 |
| + | | 0x8 |
| + | | Padding (all-0xff) |
| |} | | |} |
| + | |
| + | The legitimacy of the unique cartridge ID can be validated by online services. |
| + | |
| + | Some dumping tools, notably GodMode9 as of 2024-05-26, erroneously always write 0x00000000 into the position of the Cartridge ID2. This is presumably because the cartridge ID2 is always zero for retail carts. |
| + | |
| + | === TestData === |
| + | The test data is the same one encountered in development DS/DSi cartridges. Its layout is as follows: |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET |
| + | ! SIZE |
| + | ! DESCRIPTION |
| + | |- |
| + | | 0x0 |
| + | | 0x8 |
| + | | The bytes FF 00 FF 00 AA 55 AA 55. |
| + | |- |
| + | | 0x8 |
| + | | 0x1F8 |
| + | | An ascending byte sequence equal to the offset mod 256 (08 09 0A ... FE FF 00 01 ... FF). |
| + | |- |
| + | | 0x200 |
| + | | 0x200 |
| + | | A descending byte sequence equal to 255 minus the offset mod 256 (FF FE FD ... 00 FF DE ... 00). |
| + | |- |
| + | | 0x400 |
| + | | 0x200 |
| + | | Filled with 00 (0b00000000) bytes. |
| + | |- |
| + | | 0x600 |
| + | | 0x200 |
| + | | Filled with FF (0b11111111) bytes. |
| + | |- |
| + | | 0x800 |
| + | | 0x200 |
| + | | Filled with 0F (0b00001111) bytes. |
| + | |- |
| + | | 0xA00 |
| + | | 0x200 |
| + | | Filled with F0 (0b11110000) bytes. |
| + | |- |
| + | | 0xC00 |
| + | | 0x200 |
| + | | Filled with 55 (0b01010101) bytes. |
| + | |- |
| + | | 0xE00 |
| + | | 0x1FF |
| + | | Filled with AA (0b10101010) bytes. |
| + | |- |
| + | | 0xFFF |
| + | | 0x1 |
| + | | The final byte is 00 (0b00000000). |
| + | |} |
| + | |
| + | Production cards always return FF when attempting to read 0x1200-0x3FFF. They probably actually have the same data as development cards, but there's no way to read it. |
| | | |
| == Tools == | | == Tools == |