NCCH

From 3dbrew
Revision as of 20:01, 1 May 2019 by Wwylele (talk | contribs) (→‎Encryption: Just document the encryption stuff here instead of external link)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

The following text tries to document the structure of the NCCH (Nintendo Content Container Header) container format. This format is used to store the content of any installed title.

Overview[edit]

There are two known NCCH container specializations used on the 3DS, "executable" and "non-executable", officially known as CXI and CFA, respectively.

CXI[edit]

The CXI (CTR Executable Image) specialization of the NCCH container contains executable code, which runs on a single ARM11 core.

The CXI format is structured in the following order:

  • first a NCCH header,
  • followed by an extended header,
  • followed by an access descriptor,
  • followed by an optional plain binary region,
  • followed by an optional executable filesystem (ExeFS) - (contains ARM11 code, Home menu icn/bnr and logo),
  • and finally followed by an optional read-only filesystem (RomFS) - (Used for external file storage).

The extended header contains additional information regarding access control. The plain binary region is an area specifically stored in plaintext, mostly containing SDK library strings for identification.

CFA[edit]

The CFA (CTR File Archive) specialization of the NCCH container is not executable, but is used in conjunction with CXI files, e.g. the DLP Child Container and the Electronic Manual. (There is a system update NCCH which follows this format, but is used by the 3DS rather than the Application NCCH, and only works when embedded in the CCI format because the nVer is kept in the header of retail CCI files instead of the application NCCH). There are CFA files which exist alone in a title, but these are just System Data Archive titles and are found only in the NAND.

CFA files are structured in the following order:

  • first a NCCH header,
  • followed by an optional executable filesystem (ExeFS) (same as in CXI, except no ARM11 code)
  • followed by an optional read-only filesystem (RomFS)

Container File Format[edit]

Encryption[edit]

The extended header, the ExeFS, and the RomFS are encrypted using 128-bit AES CTR unless the NoCrypto flag is set in ncchflag[7]. There are different sets of encryption parameters in use, as over the time new system updates introduced more sophisticated means of encryption.

All encrypted regions are grouped into two categories, each of which uses one kind of encryption scheme:

  • The "menu info" group, including the extended header, the ExeFS header, and the files "icon" and "banner" in ExeFS, which are needed to display the game on the menu regardless whether system version supports the game, or whether the pre-downloaded eshop game is officially released.
  • The "content" group, including the rest files (".code" and ".firm") in ExeFS, and the entire RomFS, which is needed for actually running the game, and which can be only decrypted on the supported system (and when the seed is officially released for eshop games).

The decryption key is generated using the AES Engine. The keyX and keyY for each group are set as follows:

  • The "menu info" group uses the primary key, always generated by keyX in the slot 0x2C (set by bootrom) and keyY from the first 0x10 bytes of the NCCH signature.
  • The "content" group uses the secondary key. The slot selection for keyX depends on ncchflag[3], as listed in the table below.
ncchflag[3] FW Introduced Old3DS AES Keyslots Notes
0x00 The initial version Yes 0x2C This keyslot is initialized by bootrom. This is the same key as the primary key.
0x01 7.0.0-X Yes 0x25 This keyslot is initialized by the 6.0 gamecard savegame keyY init function during boot, using a different portion of the final hash (this keyslot is separate from the one used for the 6.0 save crypto).
0x0A 9.3.0-X No 0x18 This keyslot is initialized by arm9loader on New3DS starting with 8.1.0-0_New3DS, but only 9.3.0-X and later know how to use it with ncchflag[3].
0x0B 9.6.0-X No 0x1B 9.6.0-X's arm9loader changed the contents of keyslots 0x19-0x1F; 9.6.0-X was the first time they were officially used, so this is not a breaking change (there is no content that would use the old versions of those keys).

Besides all rules above, if ncchflag[7] bitmask 0x1 is set, and a fixed AES key instead is used for both groups. There are two fixed keys, one for titles which have the system category bit set (SystemFixedKey), and one for the rest ("zeros" key). These are debug keys, as they aren't nomally supported on retail systems.

The initial CTR for decryption each region is generated from the partition ID, as described below:

  • if the version field (NCCH header + 0x112) is 0 or 2, the 16-byte CTR is [partition_id[7], partition_id[6], ..., partition_id[0], M, 0, ..., 0], where
    • The 8-byte partition ID starts from the beginning in the reverse order. If the partition ID is viewed as a little-endian u64, and the CTR is viewed as big-endian u128, then this is to put the partition ID to the most significant bits of the CTR
    • CTR[8] is set to a magic number M. For extended header, M = 1. For ExeFS, M = 2. For RomFS, M = 3.
    • The rest 7 bytes (the least significant bits of big-endian CTR) are set to zero
  • if the version field is 1, the 16-byte CTR is [partition_id[0], partition_id[1], ...,partition_id[7], 0, 0, 0, 0, T[0], T[1], T[2], T[3]], where
    • The 8-byte partition ID starts from the beginning in the same order.
    • Then four zeros follow.
    • Then a number T in big-endian follows. This number is the offset of each encrypted region to the NCCH beginning. So for extended header, T = 0x200. For ExeFS/RomFS. T = 0x200 * ExeFS/RomFS offset in media units

Note that due to the key generation schemes described above, ExeFS can contain regions using different keys. Regardless of this, both regions shared the same initial CTR at the beginning of ExeFS. If one region doesn't start at the beginning of ExeFS, its actual CTR at its own beginning = ExeFS CTR + (region offset / AESBlockSize=16)

Format[edit]

Currently, only ExeFS:/.code can be compressed (with a LZ77 variant). A flag in the exheader determines if this is the case.

On retail for SD applications, exheader_systeminfoflags.flag bit1 must be set.

Retail CFAs use the default NCCH product code "CTR-P-CTAP", while retail title/gamecard CXIs use NCCH product code "CTR-X-XXXX". This product code is the NCCH serial code. The region-locking info checked by home menu is stored in the icon.

All of the hashes stored in this NCCH header are over the cleartext data. The ExeFS/RomFS superblock starts at offset 0x0 in the ExeFS/RomFS, and the size is specified by the hash region fields. Nintendo's NCCH validation code seems to have the size of this region fixed to 0x200 bytes (for ExeFS at least).

As of 5.0.0-11 the application ExeFS:/logo can be loaded from the plaintext region between the access descriptor and the plain region, all applications built since 5.0.0-11 store the logo here. The size of this logo is always 0x2000-bytes.

The plain region mainly contains tags for each SDK library used when building the CXI. The version used for the "FIRMWARE" tag is the kernel/FIRM version, this version can also be stored in the exheader "kernel release version" ARM11 kernel descriptor field. As of 2.2.0-X the NATIVE_FIRM kernels check the CXI exheader "kernel release version" field, if it is stored in the CXI exheader. If the kernel/FIRM version specified by this field is higher than the version of the running NATIVE_FIRM, the kernel will return error-code 0xD9001413.

NCCH Header[edit]

Offset Size Description
0x000 0x100 RSA-2048 signature of the NCCH header, using SHA-256.
0x100 4 Magic ID, always 'NCCH'
0x104 4 Content size, in media units (1 media unit = 0x200 bytes)
0x108 8 Partition ID
0x110 2 Maker code
0x112 2 Version
0x114 4 When ncchflag[7] = 0x20 starting with FIRM 9.6.0-X, this is compared with the first output u32 from a SHA256 hash. The data used for that hash is 0x18-bytes: <0x10-long title-unique content lock seed> <programID from NCCH+0x118>. This hash is only used for verification of the content lock seed, and is not the actual keyY.
0x118 8 Program ID
0x120 0x10 Reserved
0x130 0x20 Logo Region SHA-256 hash. (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
0x150 0x10 Product code
0x160 0x20 Extended header SHA-256 hash (SHA256 of 2x Alignment Size, beginning at 0x0 of ExHeader)
0x180 4 Extended header size, in bytes
0x184 4 Reserved
0x188 8 Flags (See Below)
0x190 4 Plain region offset, in media units
0x194 4 Plain region size, in media units
0x198 4 Logo Region offset, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
0x19c 4 Logo Region size, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
0x1A0 4 ExeFS offset, in media units
0x1A4 4 ExeFS size, in media units
0x1A8 4 ExeFS hash region size, in media units
0x1AC 4 Reserved
0x1B0 4 RomFS offset, in media units
0x1B4 4 RomFS size, in media units
0x1B8 4 RomFS hash region size, in media units
0x1BC 4 Reserved
0x1C0 0x20 ExeFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the ExeFS over the number of media units specified in the ExeFS hash region size)
0x1E0 0x20 RomFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the RomFS over the number of media units specified in the RomFS hash region size)

Given offsets are based on the start of the file.

NCCH Flags[edit]

INDEX DESCRIPTION
3 Crypto Method: When this is non-zero, a NCCH crypto method using two keyslots is used(see above).
4 Content Platform: 1 = CTR, 2 = snake (New 3DS).
5 Content Type Bit-masks: Data = 0x1, Executable = 0x2, SystemUpdate = 0x4, Manual = 0x8, Child = (0x4|0x8), Trial = 0x10. When 'Data' is set, but not 'Executable', NCCH is a CFA. Otherwise when 'Executable' is set, NCCH is a CXI.
6 Content Unit Size i.e. u32 ContentUnitSize = 0x200*2^flags[6];
7 Bit-masks: FixedCryptoKey = 0x1, NoMountRomFs = 0x2, NoCrypto = 0x4, using a new keyY generator = 0x20(starting with FIRM 9.6.0-X).

CXIs NCCH header signature is verified using the RSA public key stored in the accessdesc,(which follows the exheader) while CFAs NCCH header is verified with a fixed RSA public key.

NCCH header example for Lego Starwars III[edit]

Signature:              720FF8F83F2A1E998322A026D1434165
                        ED19642ABC1CB2722135AA202BEAD60A
                        80BCD21C768C597B8268FEF2C64EA710
                        4C9BA5E12CFFBD1D0C619F4EF7B42CA7
                        DD8482CB4EB26720AD66CDA57ABCBCFB
                        D63268A6E2896A59B3B744E39E45B88A
                        ABB4C0980ACC6210818DCE6DAC838A10
                        95D0F66B352474D4B3DA4B333F49912D
                        29AF7EA58BC8C890B18C70B7D540A9FB
                        EBE24A5312055617D3353B28C3EB1D17
                        61021BEFF6AD22C384835B40BD44DFAD
                        981F6350F9458B17BCB5F768C92ABC93
                        2BCE9888855A8998F4CDE40C9543514A
                        C57B84EB75A680E7C742632614620D1D
                        A253284DF3DC01091EB3800C36FD62EE
                        BA15340F1FD498FAB67C0302E9CDA397
Magic:                  NCCH
Content size:           0x1cfef400
Partition id:           0004000000038c00
Maker code:             3436 ("46")
Version:                0002
Program id:             0004000000038c00
Temp flag:              00
Product code:           CTR-P-ALGP
Extended header hash:   0C27E3C1DE7B2AE2D3114F32A4EEBF46
                        9AFD0CF352C11D4984C2A9F1D2144C63
Extended header size:   00000400
Flags:                  0000030100000000
Plain region offset:    0x00004a00
Plain region size:      0x00000200
ExeFS offset:           0x00004c00
ExeFS size:             0x00143800
ExeFS hash region size: 0x00000200
RomFS offset:           0x00148400
RomFS size:             0x1ceab000
RomFS hash region size: 0x00000200
ExeFS Superblock Hash:  130C042615F647C4C63225EA9E67F8A2
                        7B15246B88FBC7A927257B84977B787B
RomFS Superblock Hash:  A65BEE1060BB6A6821BBCEC600035B7E
                        64FB6EACA7F0960CFB1F5A37087728F7
Note: Offsets and sizes in media units have been converted to byte sizes.

Plain region example for Lego Starwars III[edit]

0004a00: 5b 53 44 4b 2b 4e 49 4e 54 45 4e 44 4f 3a 43 54  [SDK+NINTENDO:CT    [SDK+NINTENDO:CTR_SDK-0_14_23_200_none]
0004a10: 52 5f 53 44 4b 2d 30 5f 31 34 5f 32 33 5f 32 30  R_SDK-0_14_23_20
0004a20: 30 5f 6e 6f 6e 65 5d 00 5b 53 44 4b 2b 4e 49 4e  0_none].[SDK+NIN    [SDK+NINTENDO:Firmware-02_27]
0004a30: 54 45 4e 44 4f 3a 46 69 72 6d 77 61 72 65 2d 30  TENDO:Firmware-0
0004a40: 32 5f 32 37 5d 00 5b 53 44 4b 2b 4d 6f 62 69 63  2_27].[SDK+Mobic    [SDK+Mobiclip:Deblocker_1_0_2]
0004a50: 6c 69 70 3a 44 65 62 6c 6f 63 6b 65 72 5f 31 5f  lip:Deblocker_1_
0004a60: 30 5f 32 5d 00 5b 53 44 4b 2b 4d 6f 62 69 63 6c  0_2].[SDK+Mobicl    [SDK+Mobiclip:ImaAdpcmDec_1_0_0]
0004a70: 69 70 3a 49 6d 61 41 64 70 63 6d 44 65 63 5f 31  ip:ImaAdpcmDec_1
0004a80: 5f 30 5f 30 5d 00 5b 53 44 4b 2b 4d 6f 62 69 63  _0_0].[SDK+Mobic    [SDK+Mobiclip:MobiclipDec_1_0_1]
0004a90: 6c 69 70 3a 4d 6f 62 69 63 6c 69 70 44 65 63 5f  lip:MobiclipDec_
0004aa0: 31 5f 30 5f 31 5d 00 5b 53 44 4b 2b 4d 6f 62 69  1_0_1].[SDK+Mobi    [SDK+Mobiclip:MoflexDemuxer_1_0_2]
0004ab0: 63 6c 69 70 3a 4d 6f 66 6c 65 78 44 65 6d 75 78  clip:MoflexDemux
0004ac0: 65 72 5f 31 5f 30 5f 32 5d 00 00 00 00 00 00 00  er_1_0_2].......
0004ad0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0004ae0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

Example dependency list from the extended header[edit]

00850 41 50 54 3A 55 00 00 00 24 68 69 6F 46 49 4F 00 APT:U...$hioFIO.
00860 24 68 6F 73 74 69 6F 30 24 68 6F 73 74 69 6F 31 $hostio0$hostio1
00870 61 63 3A 75 00 00 00 00 62 6F 73 73 3A 55 00 00 ac:u....boss:U..
00880 63 61 6D 3A 75 00 00 00 63 65 63 64 3A 75 00 00 cam:u...cecd:u..
00890 63 66 67 3A 75 00 00 00 64 6C 70 3A 46 4B 43 4C cfg:u...dlp:FKCL
008A0 64 6C 70 3A 53 52 56 52 64 73 70 3A 3A 44 53 50 dlp:SRVRdsp::DSP
008B0 66 72 64 3A 75 00 00 00 66 73 3A 55 53 45 52 00 frd:u...fs:USER.
008C0 67 73 70 3A 3A 47 70 75 68 69 64 3A 55 53 45 52 gsp::Gpuhid:USER
008D0 68 74 74 70 3A 43 00 00 6D 69 63 3A 75 00 00 00 http:C..mic:u...
008E0 6E 64 6D 3A 75 00 00 00 6E 65 77 73 3A 75 00 00 ndm:u...news:u..
008F0 6E 77 6D 3A 3A 55 44 53 70 74 6D 3A 75 00 00 00 nwm::UDSptm:u...
00900 70 78 69 3A 64 65 76 00 73 6F 63 3A 55 00 00 00 pxi:dev.soc:U...
00910 73 73 6C 3A 43 00 00 00 79 32 72 3A 75 00 00 00 ssl:C...y2r:u...
00920 69 72 3A 55 53 45 52 00 6C 64 72 3A 72 6F 00 00 ir:USER.ldr:ro..
00930 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00940 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00950 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00960 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
... ...
009D0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF                 
009E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
009F0 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 02 . .............

Tools[edit]

ctrtool - (CMD)(Windows/Linux) Parsing and decrypting (debug only) NCCH files