Difference between revisions of "AES Registers"

From 3dbrew
Jump to navigation Jump to search
 
(70 intermediate revisions by 18 users not shown)
Line 1: Line 1:
 
== Registers ==
 
== Registers ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
NAME
+
Old3DS
PHYSICAL ADDRESS
+
Name
WIDTH
+
Address
 +
!  Width
 
!  RW
 
!  RW
 
|-
 
|-
| REG_AESCNT
+
| style="background: green" | Yes
 +
| [[#AES_CNT|AES_CNT]]
 
| 0x10009000
 
| 0x10009000
 
| 4
 
| 4
 
| RW
 
| RW
 
|-
 
|-
| REG_AESBLKCNT
+
| style="background: green" | Yes
 +
| [[#AES_MACEXTRABLKCNT|AES_MACBLKCNT]]
 
| 0x10009004
 
| 0x10009004
| 4
+
| 2
| W?
+
| W
 +
|-
 +
| style="background: green" | Yes
 +
| [[#AES_BLKCNT|AES_BLKCNT]]
 +
| 0x10009006
 +
| 2
 +
| W
 
|-
 
|-
| REG_AESWRFIFO
+
| style="background: green" | Yes
 +
| [[#AES_WRFIFO/AES_RDFIFO|AES_WRFIFO]]
 
| 0x10009008
 
| 0x10009008
 
| 4
 
| 4
 
| W
 
| W
 
|-
 
|-
| REG_AESRDFIFO
+
| style="background: green" | Yes
 +
| [[#AES_WRFIFO/AES_RDFIFO|AES_RDFIFO]]
 
| 0x1000900C
 
| 0x1000900C
 
| 4
 
| 4
 
| R
 
| R
 
|-
 
|-
| REG_AESKEYSEL
+
| style="background: green" | Yes
 +
| AES_KEYSEL
 
| 0x10009010
 
| 0x10009010
 
| 1
 
| 1
 
| RW
 
| RW
 
|-
 
|-
| REG_AESKEYCNT
+
| style="background: green" | Yes
 +
| [[#AES_KEYCNT|AES_KEYCNT]]
 
| 0x10009011
 
| 0x10009011
 
| 1
 
| 1
 
| RW
 
| RW
 
|-
 
|-
| REG_AESCTR
+
| style="background: green" | Yes
 +
| [[#AES_CTR|AES_CTR]]
 
| 0x10009020
 
| 0x10009020
 
| 16
 
| 16
 
| W
 
| W
 
|-
 
|-
| REG_AESMAC
+
| style="background: green" | Yes
 +
| [[#AES_MAC|AES_MAC]]
 
| 0x10009030
 
| 0x10009030
 
| 16
 
| 16
 
| W
 
| W
 
|-
 
|-
| REG_AESKEY0
+
| style="background: green" | Yes
 +
| AES_KEY0
 
| 0x10009040
 
| 0x10009040
 
| 48
 
| 48
 
| W
 
| W
 
|-
 
|-
| REG_AESKEY1
+
| style="background: green" | Yes
 +
| AES_KEY1
 
| 0x10009070
 
| 0x10009070
 
| 48
 
| 48
 
| W
 
| W
 
|-
 
|-
| REG_AESKEY2
+
| style="background: green" | Yes
 +
| AES_KEY2
 
| 0x100090A0
 
| 0x100090A0
 
| 48
 
| 48
 
| W
 
| W
 
|-
 
|-
| REG_AESKEY3
+
| style="background: green" | Yes
 +
| AES_KEY3
 
| 0x100090D0
 
| 0x100090D0
 
| 48
 
| 48
 
| W
 
| W
 
|-
 
|-
| REG_AESKEYFIFO
+
| style="background: green" | Yes
 +
| AES_KEYFIFO
 
| 0x10009100
 
| 0x10009100
 
| 4
 
| 4
 
| W
 
| W
 
|-
 
|-
| REG_AESKEYXFIFO
+
| style="background: green" | Yes
 +
| AES_KEYXFIFO
 
| 0x10009104
 
| 0x10009104
 
| 4
 
| 4
 
| W
 
| W
 
|-
 
|-
| REG_AESKEYYFIFO
+
| style="background: green" | Yes
 +
| AES_KEYYFIFO
 
| 0x10009108
 
| 0x10009108
 
| 4
 
| 4
Line 82: Line 104:
 
|}
 
|}
  
== REG_AESCNT ==
+
== AES_CNT ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
!  Bit
 
!  Bit
Line 98: Line 120:
 
| 11
 
| 11
 
| Flush read fifo (1=Clear read FIFO)
 
| Flush read fifo (1=Clear read FIFO)
 +
|-
 +
| 12-13
 +
| Write FIFO DMA size (0=16, 1=12, 2=8, 3=4 words)
 +
|-
 +
| 14-15
 +
| Read FIFO DMA size (0=4, 1=8, 2=12, 3=16 words)
 
|-
 
|-
 
| 18-16
 
| 18-16
Line 122: Line 150:
 
| 25
 
| 25
 
| Input word order (1=Normal order, 0=Reversed order)
 
| Input word order (1=Normal order, 0=Reversed order)
|-
 
 
|-
 
|-
 
| 26
 
| 26
| Update keyslot (selects the keyslot specified by REG_AESKEYSEL when this bit is set)
+
| Update keyslot (selects the keyslot specified by AES_KEYSEL when this bit is set)
 
|-
 
|-
 
| 29-27
 
| 29-27
Line 137: Line 164:
 
|}
 
|}
  
When bit31 is clear, the AES engine will handle keyslot-selection when bit26 is set immediately. When bit31 is set, the AES engine won't handle bit26 immediately, instead the AES engine will automatically handle the already-set bit26 once bit31 clears(current AES operation finishes).
+
When bit31 is set, this register essentially becomes locked and doesn't change when written to. However if bit26 is "set", keyslot-selection is cued to be handled when bit31 is cleared.
  
 
Clearing bit31 while the AES engine is doing crypto will result in the AES engine stopping crypto, once it finishes processing the current block.
 
Clearing bit31 while the AES engine is doing crypto will result in the AES engine stopping crypto, once it finishes processing the current block.
  
== REG_AESBLKCNT ==
+
Read/Write FIFO counts and the MAC status can never be set by writing to AES_CNT, they are read-only.
  
{| class="wikitable" border="1"
+
Changing the input word order triggers the key/keyX/keyY FIFOs to be flushed.
!  Bit
+
 
!  Description
+
== AES_MACEXTRABLKCNT ==
|-
+
(CCM-MAC extra data length)>>4, i.e. the number of block of CCM-MAC extra data.
| 16-31
+
 
| (Data length)>>4
+
== AES_BLKCNT ==
|}
+
(Data length)>>4, i.e. the number of blocks to process
 +
 
 +
== AES_WRFIFO/AES_RDFIFO ==
 +
The AES engine can accept up to 64 bytes of input data (16 32-bit words) and can hold up to 64 bytes of output data at a time (for a total of 128 bytes of buffered data). Bits 12-13 and 14-15 in AES_CNT configure the DMA request for the relevant FIFO (see above).
 +
 
 +
The input data for the AES crypto operation is written to AES_WRFIFO, the output data is read from AES_RDFIFO.
  
== REG_AESWRFIFO/REG_AESRDFIFO ==
+
Reading from AES_RDFIFO when there's no data available in the RDFIFO will result in reading the last word that was in the RDFIFO.
TODO: Explain what this does.
 
  
Up to 128 bytes of input data can be buffered.
+
When triggering either RDFIFO or WRFIFO to be flushed, the AES Engine does not clear either buffer.
  
 +
Word order and endianness can be changed between each read/write to these FIFOs. However changing the word order when writing to WRFIFO can cause the word to be written outside the current block, leaving uninitialized data in its place. Attempts to change endianness or word order are not honored when reading from RDFIFO when no more data is available.
  
== REG_AESKEYCNT ==
+
== AES_KEYCNT ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
!  Bit
 
!  Bit
Line 174: Line 206:
 
Bit6 is only used when keyslots >=4 are used, value1 has the same affect as doing key-init with the TWL keyslots. Bit6 is only checked when a keyY was completely written, for when the final-normalkey needs updated via the key-generator. Changing bit6 has no affect on the generated normalkey when writing to this bit immediately after writing the last keyY word.
 
Bit6 is only used when keyslots >=4 are used, value1 has the same affect as doing key-init with the TWL keyslots. Bit6 is only checked when a keyY was completely written, for when the final-normalkey needs updated via the key-generator. Changing bit6 has no affect on the generated normalkey when writing to this bit immediately after writing the last keyY word.
  
== REG_AESCTR ==
+
== AES_CTR ==
 
This register specifies the counter (CTR mode), nonce (CCM mode) or the initialization vector (CBC mode) depending on the mode of operation.
 
This register specifies the counter (CTR mode), nonce (CCM mode) or the initialization vector (CBC mode) depending on the mode of operation.
 
For CBC and CTR mode this register takes up the full 16 bytes, but for CCM mode the nonce is only the first 12 bytes.
 
For CBC and CTR mode this register takes up the full 16 bytes, but for CCM mode the nonce is only the first 12 bytes.
 +
The AES engine will automatically increment the counter up to the maximum BLKCNT, after which point it must be manually incremented and set again.
  
== REG_AESMAC ==
+
== AES_MAC ==
 
This register specifies the message authentication code (MAC) for use in CCM mode.
 
This register specifies the message authentication code (MAC) for use in CCM mode.
 +
 +
== AES_KEY0/1/2/3 ==
 +
{| class="wikitable" border="1"
 +
!  Byte
 +
!  Description
 +
|-
 +
| 0-15
 +
| Normalkey
 +
|-
 +
| 16-31
 +
| KeyX
 +
|-
 +
| 32-47
 +
| KeyY
 +
|-}
 +
 +
These registers are the same as they were on TWL, and are likely preserved for compatibility reasons. The keyslot is updated immediately after *any* data(u8/u32/...) is written here, which was used on DSi to [[3DS_System_Flaws|break]] the key-generator.
  
 
== Endianness and word order ==
 
== Endianness and word order ==
When writing to the REG_AESCTR or REG_AESMAC register, the hardware will process the written data according to the current input endianness specified in AESCNT. However, the current specified input word order will not be honored for this register, and always defaults to reversed word order. Therefore, for normal word order, the reversal must be carried out manually if required.
+
 
 +
=== AES_CNT.input_endianness ===
 +
 
 +
Swaps the bytes of 32-bit writes to AES_CTR, AES_WRFIFO, AES_KEY*FIFO according to specified endianness. AES_MAC?
 +
 
 +
=== AES_CNT.output_endianness ===
 +
 
 +
Swaps the bytes of 32-bit reads from AES_RDFIFO.
 +
 
 +
=== AES_CNT.input_word_order ===
 +
 
 +
If reversed, writes to AES_KEY*FIFO and AES_WRFIFO fill the FIFO backwards. For AES_WRFIFO, this means that every 16-byte block will have its words in the reverse order, but the order of these blocks remains the same. AES_CTR is unaffected by this field. AES_MAC?
 +
 
 +
=== AES_CNT.output_word_order ===
 +
 
 +
If reversed, reads from AES_RDFIFO will drain the FIFO backwards. This means that every 16-byte output block will have its words in the reverse order, but the order of these blocks remains the same.
 +
 
 +
== CCM mode pitfall ==
 +
Non-standard AES-CCM behaviour is observed on [[APT:Wrap|Wrap]]/[[APT:Unwrap|Unwrap]] function. According to [https://tools.ietf.org/html/rfc3610 RFC 3610], the first block B_0 for authentication should be generated from the message length and some other parameters. Using these function, it seems that the message length is aligned up to 16 when generating B_0. This makes the generated MAC not compliant with the standard when (inputsize-noncesize)%16!=0. It is very likely that this non-standard behaviour happens on the hardware level, but not confirmed yet.
 +
 
 +
== Keyslot ranges ==
 +
This is approximately a table of what is set by bootrom before booting into FIRM. Often it appears that keyslots in groups of 4 have the same keyX, and sometimes also same keyY set.
 +
 
 +
{| class="wikitable" border="1"
 +
!  Keyslot
 +
!  Name
 +
!  KeyX
 +
!  KeyY/Normal-key
 +
!  Console unique.
 +
|-
 +
| 0x00-0x03
 +
| TWL keys.
 +
| Probably unset.
 +
| Probably unset.
 +
| -
 +
|-
 +
| 0x04-0x07
 +
| NAND partition keys.
 +
| Same for all.
 +
| Different for all.
 +
| style="background: green" | Yes
 +
|-
 +
| 0x08-0x0B
 +
| See below.
 +
| Same for all.
 +
| Different for all.
 +
| style="background: green" | Yes
 +
|-
 +
| 0x0C-0x0F
 +
| SSL cert key.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: orange" | The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
 +
|-
 +
| 0x10-0x17
 +
| -
 +
| Set for all except 0x11..0x13. Keydata is different for these.
 +
| Normalkey, same for all except the last 4 are all different.
 +
| -
 +
|-
 +
| 0x18-0x1B
 +
| Never used.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: orange" | The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
 +
|-
 +
| 0x1C-0x1F
 +
| Never used.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: orange" | The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
 +
|-
 +
| 0x20-0x23
 +
| Never used.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: orange" | The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
 +
|-
 +
| 0x24
 +
| Never used.
 +
| Individually set.
 +
| Individually set, normalkey-only.
 +
| style="background: orange" | The keyX is console-unique, however the normalkey setup by Boot9 later during keyinit is not console-unique.
 +
|-
 +
| 0x25-0x27
 +
| -
 +
| Not set.
 +
| Same for all, normalkeys-only. Same keydata as keyslot 0x24.
 +
| style="background: red" | No
 +
|-
 +
| 0x28-0x2B
 +
| Never used.
 +
| Individually set.
 +
| Individually set, normalkeys-only. Keyslot 0x28 has same normalkey as keyslot 0x24.
 +
| style="background: orange" | The keyX is console-unique, however the normalkey setup by Boot9 later during keyinit is not console-unique.
 +
|-
 +
| 0x2C-0x2F
 +
| Various uniques.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: red" | No
 +
|-
 +
| 0x30-0x33
 +
| Various uniques.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: red" | No
 +
|-
 +
| 0x34-0x37
 +
| Various uniques.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: red" | No
 +
|-
 +
| 0x38-0x3B
 +
| Various uniques.
 +
| Same for all.
 +
| Same for all, normalkeys-only.
 +
| style="background: red" | No
 +
|-
 +
| 0x3C-0x3F
 +
| Various uniques.
 +
| Individually set.
 +
| Individually set, normalkeys-only. Keyslot 0x3C has same normalkey as 0x38-0x3B.
 +
| style="background: red" | No
 +
|}
 +
 
 +
Keyslot pairs (0x24, 0x28) and (0x38, 0x3C) shares the same normal-key, while at the same time having different keyX's. This suggests they were set to same normal-key by bootrom.
  
 
== Keyslots ==
 
== Keyslots ==
There are 0x40 keyslots, each of which stores three keys called keyX, keyY and normalkey. All keys can be set explicitly, but the normalkey can optionally be generated using a hardware key scrambler instead (see below). There is no way to read the contents of a keyslot.
+
There are 0x40 keyslots, each of which stores three keys called keyX, keyY and normalkey. All keys can be set explicitly, but the normalkey can optionally be generated using a hardware key generator instead (see [[#Hardware_key_generator|below]]). There is no way to read the contents of a keyslot.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
!  Keyslot
 
!  Keyslot
 
!  Description
 
!  Description
!  KeyX
+
!  KeyX set by
!  KeyY
+
!  KeyY set by
 
!  Normal-key
 
!  Normal-key
 
!  Old3DS
 
!  Old3DS
 
|-
 
|-
 
| 0x00-0x03
 
| 0x00-0x03
| TWL keyslots.  
+
| TWL keys.
 
| NATIVE_FIRM hard-boot.
 
| NATIVE_FIRM hard-boot.
 
| NATIVE_FIRM hard-boot.
 
| NATIVE_FIRM hard-boot.
Line 203: Line 380:
 
|-
 
|-
 
| 0x04..0x07
 
| 0x04..0x07
| These keyslots use the same console-unique keyX. Each keyslot has a separate keyY. These are the [[Flash_Filesystem|NAND]] encryption keyslots, which keyslot gets used is determined by the [[NCSD]] partition FS type and the partition encryption type.
+
| [[Flash_Filesystem|NAND]] partition keys.
The New3DS Process9 sets the keyY for keyslot 0x05(New3DS CTRNAND) to a key from .(ro)data.
+
 
 +
Keyslot is determined by [[NCSD]] partition FS type and encryption type.  
 +
The New3DS Process9 sets the keyY for keyslot 0x05 (New3DS CTRNAND) to a key from .(ro)data. Its keyX is console-unique and set by the bootloader.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
Line 210: Line 389:
 
| Yes
 
| Yes
 
|-
 
|-
| 0x08..0x0B
+
| 0x0A
| These keyslots use the same console-unique keyX. Each keyslot has a separate keyY.
+
| DSiWare export key.
| Bootrom.
+
 
| Bootrom.
+
Used for encrypting the all-zero 0x10-byte block in the [[DSiWare_Exports|DSiWare_Exports]] header. Console-unique.
 +
| See above keyslot info.
 +
| See above keyslot info.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
| 0x0A
+
| 0x0B
| This is the console-unique keyslot used for encrypting the all-zero 0x10-byte block in the [[DSiWare_Exports|DSiWare_Exports]] header.
+
| This is console-unique. This keyslot is used for the NAND [[Title_Database|dbs]] images AES-CMACs, and the [[Nand/private/movable.sed]] AES-CMAC(when used).
 
| See above keyslot info.
 
| See above keyslot info.
 
| See above keyslot info.
 
| See above keyslot info.
 
| -
 
| -
| Yes
 
|-
 
| 0x0C..0x0F
 
| All of these keyslots are set to the same key-data, which is a regular normal-key. The keyX written before the normal-key is console-unique, this keyX is the same for all of these keyslots.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x0D
 
| 0x0D
| SSL-certificate key. See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
+
| SSL-certificate key.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| -
 
| -
 
| -
 
| -
| Bootrom.
 
| Yes
 
|-
 
| 0x10
 
| The console-unique keyX is set before the normal-key.
 
| Bootrom.
 
| Bootrom?
 
 
| Bootrom.
 
| Bootrom.
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x11
 
| 0x11
| This is used for general normal-key crypto, where the normal-key is set by FIRM. This keyslot is also used by the New3DS [[FIRM]] arm9 binary loader.
+
| Temporary keyslot.
 +
 
 +
Used by FIRM for general normal-key crypto. Also used by the New3DS [[FIRM]] arm9 binary loader.
 
| Arm9Loader.  
 
| Arm9Loader.  
 
| Arm9Loader.
 
| Arm9Loader.
 
| NATIVE_FIRM.
 
| NATIVE_FIRM.
 
| Yes
 
| Yes
|-
 
| 0x12
 
| Unused
 
| -
 
| -
 
| -
 
| -
 
|-
 
| 0x13
 
| Unused
 
| -
 
| -
 
| -
 
| -
 
 
|-
 
|-
 
| 0x14
 
| 0x14
Line 271: Line 428:
 
| NATIVE_FIRM boot.
 
| NATIVE_FIRM boot.
 
| -
 
| -
| Yes
 
|-
 
| 0x15..0x16
 
| The console-unique keyX is set before the normal-key.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
 
| Yes
 
| Yes
 
|-
 
|-
Line 293: Line 443:
 
| See previous info for this keyslot.
 
| See previous info for this keyslot.
 
| No
 
| No
|-
 
| 0x17
 
| The console-unique keyX is set before the normal-key.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x18..0x1B
 
| All of these keyslots are set to the same key-data, which is a regular normal-key. The console-unique keyX is set before the normal-key, this keyX is the same for all of these keyslots.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x1C..0x1F
 
| All of these keyslots are set to the same key-data, which is a regular normal-key. The console-unique keyX is set before the normal-key, this keyX is the same for all of these keyslots.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
 
|-
 
|-
 
| 0x18..0x1F
 
| 0x18..0x1F
| These are the New3DS keyslots, where the keyX is generated with keyslot 0x11 by the New3DS arm9 binary [[FIRM|loader]]. As of [[FIRM]] [[9.5.0-22|9.5.0-X]] keyslots 0x1B..0x1F are not yet used by Process9.
+
| These are the New3DS keyslots, where the keyX is generated with keyslot 0x11 by the New3DS arm9 binary [[FIRM|loader]]. As of [[FIRM]] [[9.6.0-24|9.6.0-X]] keyslots 0x1C..0x1F are not yet used by Process9.
 
| Arm9Loader.
 
| Arm9Loader.
 
| NATIVE_FIRM / see previous info for these keyslots.
 
| NATIVE_FIRM / see previous info for these keyslots.
Line 323: Line 452:
 
|-
 
|-
 
| 0x18
 
| 0x18
| New3DS [[NCCH]] keyslot, starting with [[9.3.0-21|9.3.0-X]].
+
| New3DS [[9.3.0-21|9.3.0-X]] [[NCCH]] key, when ncchflag[3] is 0x0A.
| See above keyslot info.
+
| Arm9Loader.
 
| NATIVE_FIRM
 
| NATIVE_FIRM
 
| -
 
| -
| Yes
+
| No
 
|-
 
|-
 
| 0x19
 
| 0x19
| New3DS gamecard [[Savegames|savedata]] keyslot equalivant of keyslot 0x33, used when a [[NCSD]] flag is set to a certain value(implemented with [[9.3.0-21|9.3.0-X]]).
+
| New3DS gamecard [[Savegames|savedata]] AES-CMAC key.
| See above keyslot info.
+
 
 +
Equivalent of keyslot 0x33, used when a [[NCSD]] flag is set to a certain value (implemented with [[9.3.0-21|9.3.0-X]]).
 +
| Arm9Loader.
 
| NATIVE_FIRM
 
| NATIVE_FIRM
 
| -
 
| -
| Yes
+
| No
 
|-
 
|-
 
| 0x1A
 
| 0x1A
| New3DS gamecard [[Savegames|savedata]] keyslot equalivant of keyslot 0x37, used when a [[NCSD]] flag is set to a certain value(implemented with [[9.3.0-21|9.3.0-X]]).
+
| New3DS gamecard [[Savegames|savedata]] actual key.
| See above keyslot info.
+
 
 +
Equivalent of keyslot 0x37, used when a [[NCSD]] flag is set to a certain value (implemented with [[9.3.0-21|9.3.0-X]]).
 +
| Arm9Loader.
 
| NATIVE_FIRM
 
| NATIVE_FIRM
 
| -
 
| -
| Yes
+
| No
 
|-
 
|-
| 0x20..0x23
+
| 0x1B
| All of these keyslots are set to the same key-data, which is a regular normal-key. The keyX written to these keyslots before writing the normal-key by the bootrom, is console-unique.
+
| New3DS [[9.6.0-24|9.6.0-X]] [[NCCH]] key, when ncchflag[3] is 0x0B.
| Bootrom.
+
| Arm9Loader.
 +
| NATIVE_FIRM
 
| -
 
| -
| Bootrom.
+
| No
| Yes
 
 
|-
 
|-
 
| 0x24
 
| 0x24
| This is set to a normal-key by bootrom. The keyX written to this keyslot before writing the normal-key by the bootrom, is console-unique.
+
| AGB_FIRM savegame AES-CMAC key.
| Bootrom.
 
| Bootrom?
 
 
| Bootrom.
 
| Bootrom.
 +
| AGB/NATIVE_FIRM.
 +
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x25
 
| 0x25
| [[7.0.0-13|v7.0]] [[NCCH]] key.
+
| [[7.0.0-13|v7.0]] [[NCCH]] key, when ncchflag[3] is 0x01.
<!--
 
The keyX and keyY initialized by bootrom for this keyslot are console-unique.
 
-->
 
 
| NATIVE_FIRM [[Savegames#6.0.0-11_Savegame_keyY|boot]].
 
| NATIVE_FIRM [[Savegames#6.0.0-11_Savegame_keyY|boot]].
 
| NATIVE_FIRM.
 
| NATIVE_FIRM.
| -
 
| Yes
 
|-
 
| 0x26
 
| Unused
 
| -
 
| -
 
| -
 
| Yes
 
|-
 
| 0x27
 
| Unused
 
| -
 
| -
 
| -
 
| Yes
 
|-
 
| 0x28
 
| Unknown. The normal-key for this is the same as keyslot 0x24, the console-unique keyX written before the normal-key is different from keyslot 0x24.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x29
 
| Unknown. The keyX written before the normal-key is console-unique.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x2A
 
| Unknown. The keyX written before the normal-key is console-unique.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x2B
 
| Unknown. The keyX written before the normal-key is console-unique.
 
| Bootrom.
 
| Bootrom?
 
| Bootrom.
 
| Yes
 
|-
 
| 0x2C..0x2F
 
| All of these keyslots use the same keyX initialized by bootrom. During key-init in arm9 bootrom, keyslots 0x2D and 0x2F are set to the same keyY.
 
| Bootrom.
 
| Bootrom, then NATIVE_FIRM for keyslots 0x2C and 0x2F on >=v6.0 FIRM.
 
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x2C
 
| 0x2C
| [[NCCH|NCCH]] key. Keyslots 0x2C..0x2F all use the same keyX, set by bootrom.
+
| Original [[NCCH|NCCH]] key, when ncchflag[3] is 0x00 and always for certain NCCH sections.
 
| Bootrom.
 
| Bootrom.
 
| Process9.
 
| Process9.
Line 424: Line 505:
 
|-
 
|-
 
| 0x2D
 
| 0x2D
| UDS local-WLAN CCMP key. See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
+
| UDS local-WLAN CCMP key.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
Line 431: Line 514:
 
|-
 
|-
 
| 0x2E
 
| 0x2E
| See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
+
| Streetpass key.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| Bootrom.
 
| Bootrom.
 
| NATIVE_FIRM.
 
| NATIVE_FIRM.
Line 440: Line 525:
 
| [[Savegames#6.0.0-11_Savegame_keyY|v6.0]] save key.
 
| [[Savegames#6.0.0-11_Savegame_keyY|v6.0]] save key.
 
| Bootrom.
 
| Bootrom.
| Bootrom, then later NATIVE_FIRM.
+
| NATIVE_FIRM.
| -
 
| Yes
 
|-
 
| 0x30-0x33
 
| All of these keyslots use the same keyX. The keyY for keyslots 0x32 and 0x33 are set to the same keyY by bootrom.
 
| Bootrom.
 
| Bootrom, then later NATIVE_FIRM except for keyslot 0x32.
 
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x30
 
| 0x30
| This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for calculating the AESMACs under SD [[SD_Filesystem|/Nintendo 3DS/<ID0>/<ID1>/]](except [[DSiWare_Exports]]) and [[Flash_Filesystem|NAND]] /data/.
+
| SD/NAND AES-CMAC key.
 +
 
 +
This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for calculating the AES-CMACs under SD [[SD_Filesystem|/Nintendo 3DS/<ID0>/<ID1>/]] (except [[DSiWare_Exports]]) and [[Flash_Filesystem|NAND]] /data/.
 
| Bootrom.
 
| Bootrom.
| Bootrom(?), then later NATIVE_FIRM.
+
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x31
 
| 0x31
| APT wrap key. See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]]
+
| APT wrap key.
  
NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.
+
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]]. NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.
 
| Bootrom.
 
| Bootrom.
| Bootrom(?), then later NATIVE_FIRM.
+
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x32
 
| 0x32
| See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
+
| Unknown.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
Line 475: Line 557:
 
|-
 
|-
 
| 0x33
 
| 0x33
| This is the keyslot for the gamecard [[Savegames|savedata]] AESMAC.
+
| Gamecard [[Savegames|savedata]] AES-CMAC.
 
| Bootrom.
 
| Bootrom.
| Bootrom, then later NATIVE_FIRM.
+
| NATIVE_FIRM.
| -
 
| Yes
 
|-
 
| 0x34-0x37
 
| All four of these keyslots use the same keyX. Keyslots 0x35, 0x36, and 0x37 use the same bootrom keyY. See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]] for keyslot 0x36.
 
| Bootrom.
 
| Bootrom, then NATIVE_FIRM for keyslot 0x37.
 
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x34
 
| 0x34
| This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for encrypting *all* SD card data under [[SD_Filesystem|/Nintendo 3DS/<ID0>/<ID1>/]].
+
| SD key.
 +
 
 +
This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for encrypting *all* SD card data under [[SD_Filesystem|/Nintendo 3DS/<ID0>/<ID1>/]].
 
| Bootrom.
 
| Bootrom.
| Bootrom(?), then later NATIVE_FIRM.
+
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x35
 
| 0x35
| This is the keyslot used for movable.sed encryption + AESMAC with the import/export [[FSPXI:ImportIntegrityVerificationSeed|commands]].
+
| Movable.sed key.
| Bootrom.
+
 
 +
This is the keyslot used for movable.sed encryption + AES-CBC MAC with the import/export [[FSPXI:ImportIntegrityVerificationSeed|commands]]. The keyYs used for crypto/CMAC are different, but both can be found in process9 rodata.
 
| Bootrom.
 
| Bootrom.
 +
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x36
 
| 0x36
| Unknown.
+
| Unknown. Used by friends module.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
Line 510: Line 591:
 
|-
 
|-
 
| 0x37
 
| 0x37
| This is the keyslot for the actual gamecard [[Savegames|savedata]] encryption.
+
| Gamecard [[Savegames|savedata]] actual key.
 
| Bootrom.
 
| Bootrom.
| Bootrom, then later NATIVE_FIRM.
+
| NATIVE_FIRM.
| -
 
| Yes
 
|-
 
| 0x38-0x3B
 
| All of these keyslots use the same keyX. Keyslot 0x3B uses an unique keyY initialized by bootrom.
 
| Bootrom.
 
| Bootrom, then NATIVE_FIRM for keyslot 0x3A.
 
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x38
 
| 0x38
| See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
+
| BOSS key.
 +
 
 +
See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]].
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
Line 531: Line 607:
 
|-
 
|-
 
| 0x39
 
| 0x39
| See [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]]. NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.
+
| Download Play key, and the actual NFC key for generating retail [[Amiibo]] keys.
 +
 
 +
This keyslot is used for two different keys. Both are available via [[PSPXI:EncryptDecryptAes|EncryptDecryptAes]]. NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.
 
| Bootrom.
 
| Bootrom.
| Bootrom, then NATIVE_FIRM.
+
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x3A
 
| 0x3A
| This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for calculating the AESMACs for SD [[DSiWare_Exports]].
+
| DSiWare export key.
 +
 
 +
This keyY is initialized via [[Nand/private/movable.sed|movable.sed]]. This is used for calculating the AES-CMACs for SD [[DSiWare_Exports]].
 
| Bootrom.
 
| Bootrom.
| Bootrom(?), then later NATIVE_FIRM.
+
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x3B
 
| 0x3B
| Unknown.
+
| [[CTRCARD_Registers#CTRCARD_SECSEED|CTR-CARD hardware-crypto seed]] decryption key.
| Bootrom.
+
 
| Bootrom.
+
AES-CCM is used, the keyY, nonce and MAC are stored in the [[NCSD#Card_Info_Header|Card Info Header]].
| -
 
| Yes
 
|-
 
| 0x3C
 
| Unknown. The keyX for this is unique for this keyslot. The keyY for this initialized by bootrom is the same as keyslot 0x38.
 
| Bootrom.
 
 
| Bootrom.
 
| Bootrom.
 +
| NATIVE_FIRM.
 
| -
 
| -
 
| Yes
 
| Yes
 
|-
 
|-
 
| 0x3D
 
| 0x3D
| Common key. Used to decrypt title keys in [[Ticket]]. Used by Gateway.
+
| Common key.
 +
 
 +
Used to decrypt title keys in [[Ticket]].
 
| Bootrom.
 
| Bootrom.
 
| NATIVE_FIRM.
 
| NATIVE_FIRM.
Line 565: Line 642:
 
| Yes
 
| Yes
 
|-
 
|-
| 0x3E
+
| 0x3F
| Unknown. This keyslot uses an unique keyX/keyY.
+
| Used for various internal Boot9 crypto operations, different keydata for each one. Used to decrypt the [[OTP_Registers|OTP]], the FIRM sections when [[Bootloader#Non-NAND_FIRM_boot|booting from non-NAND]], and when generating the console-unique keys.
 +
 
 +
The keydata for this keyslot is overwritten with other keydata before booting FIRM. This keyslot is not known to be used post-Boot9.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
 
| Bootrom.
| -
 
| Yes
 
|-
 
| 0x3F
 
| Unknown. This keyslot uses an unique keyX/keyY.
 
 
| Bootrom.
 
| Bootrom.
| Bootrom.
 
| -
 
 
| Yes
 
| Yes
 
|}
 
|}
  
 
=== Updating keydata ===
 
=== Updating keydata ===
The contents of the keyslot specified in REG_AESKEYCNT can be updated by consecutively writing four words to REG_AESKEYXFIFO (keyX), REG_AESKEYYFIFO(keyY), or REG_AESKEYFIFO (normalkey).
+
The contents of the keyslot specified in AES_KEYCNT can be updated by consecutively writing four words to AES_KEYXFIFO (keyX), AES_KEYYFIFO(keyY), or AES_KEYFIFO (normalkey).
  
After writing to a keyslot when that same keyslot is already selected via REG_AESKEYSEL, the keyslot must be selected again(write REG_AESKEYSEL + set REG_AESCNT bit26), in order for the AES engine to use the new key-data.
+
After writing to a keyslot, the keyslot must be selected again(write AES_KEYSEL + set AES_CNT bit26), even when writing to the same keyslot. Writing the last word to a key FIFO immediately after selecting a keyslot will not affect the keyslot keydata that gets used at that time, the new keydata will not get used until the keyslot gets selected again.
  
 
Writing to the key FIFOs with byte writes results in the AES engine converting the byte to a word for setting the key word, with this: word = (byteval) | (byteval<<8) | (byteval<<16) | (byteval<<24). The result is the same regardless of which FIFO register byte was written to.
 
Writing to the key FIFOs with byte writes results in the AES engine converting the byte to a word for setting the key word, with this: word = (byteval) | (byteval<<8) | (byteval<<16) | (byteval<<24). The result is the same regardless of which FIFO register byte was written to.
  
The TWL keyslots 0x00-0x03 can be set directly by writing to the REG_AESKEY0-REG_AESKEY3 registers.
+
The TWL keyslots 0x00-0x03 can be set directly by writing to the AES_KEY0-AES_KEY3 registers.
  
The key FIFOs can be written simultaneously. For example, executing the following 4 times will result in the keyX and keyY being set to all-zero(unknown for normalkey): memset(0x10009100, 0, 0x100);
+
The key FIFOs can be written simultaneously. For example, executing the following will result in the keyX and keyY being set to all-zero(unknown for normalkey): memset(0x10009100, 0, 0x100);
  
Each key FIFO has a 0x10-byte tmp-buffer for storing the words written to that FIFO. Once the last word is written to a key FIFO, the filled tmp-buffer is then written to the key-data for the keyslot selected by REG_AESKEYCNT at the time the last word was written.
+
Each key FIFO has a 0x10-byte tmp-buffer for storing the words written to that FIFO. Once the last word is written to a key FIFO, the filled tmp-buffer is then written to the key-data for the keyslot selected by AES_KEYCNT at the time the last word was written.
  
=== keyX ===
+
=== Hardware key generator ===
The ARM9 bootrom initializes the keyX for certain 3DS keyslots, the ARM9 bootrom may also initialize the keyY for certain keyslots. In certain cases Process9 may also set the keyX.
+
A dedicated hardware key generator can be used to generate a keyslot's normal-key from its keyX and keyY. The hardware key generator is triggered by writing the keyY, which is the only way to trigger it with the 3DS keyslots.
  
=== Hardware key generator ===
+
The algorithm for generating the normal-key from keyX and keyY is as follows, in big-endian 128-bit unsigned wraparound arithmetic:
A dedicated hardware key generator can be used to generate a keyslot's normalkey from its keyX and keyY. The hardware key generator is triggered by writing the keyY, which is the only way to trigger it with the 3DS keyslots. The algorithm used for key generation is unknown.
+
 
 +
{| class="wikitable" border="1"
 +
! Mode
 +
! Formula
 +
|-
 +
| 3DS
 +
| NormalKey = (((KeyX ROL 2) XOR KeyY) + C1) ROR 41
 +
|-
 +
| DSi
 +
| NormalKey = ((KeyX XOR KeyY) + C2) ROL 42
 +
|}
  
Unless noted otherwise, all keyslots on retail units use the hardware key-generator.
+
Unless noted otherwise, all keyslots on retail units use the hardware key generator.
  
 
=== FIRM-launch key clearing ===
 
=== FIRM-launch key clearing ===
 
Starting with [[9.0.0-20]] the Process9 FIRM-launch code now "clears" the following AES keyslots, with certain keydata by writing the normal-key: 0x15 and 0x18-0x20. These are the keyslots used by the New3DS [[FIRM]] arm9bin loader(minus keyslot 0x11), the New3DS Process9 does this too.
 
Starting with [[9.0.0-20]] the Process9 FIRM-launch code now "clears" the following AES keyslots, with certain keydata by writing the normal-key: 0x15 and 0x18-0x20. These are the keyslots used by the New3DS [[FIRM]] arm9bin loader(minus keyslot 0x11), the New3DS Process9 does this too.
 +
 +
=== AES key-init ===
 +
See [[Bootloader|here]] for how Boot9 initializes the AES keyslots.
 +
 +
For an issue with console-unique key-init, see [[OTP_Registers|here]].
 +
 +
Some of the Boot9 key-init appears to have a bug(?) when initializing a chunk of keyslots at once: normally it does <code>for(i=0; i<4; i++){... <setup_keyslot_keydata(keyslotbase+i, keydata)> ...}</code>, however in some cases it does that except with <code>(keyslotbase,</code> instead. This results in the keyslot specified by keyslotbase being initialized 4 times in a row, with the remaining 3 keyslots following keyslotbase being left uninitialized.
 +
 +
initialize_aeskeys() works as follows:
 +
* Validates input, calls panic() on failure. conunique_dataptr and bootrom_dataptr are both input parameters for initialize_aeskeys().
 +
* Calls crypto_initialize().
 +
* Then it ''basically'': copies 0x1C-bytes from conunique_dataptr to tmpbuf+0(sp+12), and copies data from bootrom_dataptr with size 0x40-0x1C to tmpbuf+0x1C(conunique_dataptr and bootrom_dataptr are updated afterwards).
 +
* The 0x40-byte tmpbuf is hashed with SHA256.
 +
* Keyslot 0x3F is then initialized using the above hash: keyX = first 0x10-bytes of the hash, keyY = last 0x10-bytes of the hash.
 +
* Then with each console-unique key-init code-block: IV is loaded from bootrom_dataptr(which is updated afterwards), then the 0x40-bytes from bootrom_dataptr is encrypted with AES-CBC. The output is then used as 4 keyXs for initializing keyslots. How bootrom_dataptr is updated if at all varies per code-block. Hashing similar to the code at the start of this function is also run(when the remaining size for conunique_dataptr is non-zero), but the output hash isn't used(this code is also slightly different for one code-block).
 +
* Once finished with that, the non-console-unique keyslots are initialized. This is done with keydata loaded directly from bootrom_dataptr.
 +
* The last initialized keyslot is 0x3F, via normalkey. The keydata for this is copied to 0xFFF00618. This is for restoring the keydata when non-NAND FIRM boot ''fails'', since those use keyslot 0x3F with other keydata.
 +
* Lastly it clears the 0x40-bytes at tmpbuf with the u32 loaded from bootrom_dataptr(the word following the above keyslot 0x3F keydata), then returns.
 +
 +
The keyslots are initialized with the same order of keyslots+keydata_type listed below:
 +
 +
Console-unique keydata, after the initialization for the key-generation keyslot(0x3F):
 +
  0x04..0x07 keyX
 +
  0x08..0x0B keyX
 +
  0x0C..0x0F keyX
 +
  0x10      keyX
 +
  0x14..0x17 keyX
 +
  0x18..0x1B keyX
 +
  0x1C..0x1F keyX
 +
  0x20..0x23 keyX
 +
  0x24      keyX
 +
  0x28..0x2B keyX
 +
 +
Common keydata:
 +
 +
  0x2C..0x2F keyX
 +
  0x30..0x33 keyX
 +
  0x34..0x37 keyX
 +
  0x38..0x3B keyX
 +
  0x3C..0x3F keyX
 +
  0x04..0x0B keyY
 +
  0x0C..0x0F normalkey
 +
  0x10..0x13 normalkey
 +
  0x14..0x17 normalkey
 +
  0x18..0x1B normalkey
 +
  0x1C..0x1F normalkey
 +
  0x20..0x23 normalkey
 +
  0x24..0x27 normalkey
 +
  0x28..0x2B normalkey
 +
  0x2C..0x2F normalkey
 +
  0x30..0x33 normalkey
 +
  0x34..0x37 normalkey
 +
  0x38..0x3B normalkey
 +
  0x3C..0x3F normalkey

Latest revision as of 11:30, 28 July 2020

Registers[edit]

Old3DS Name Address Width RW
Yes AES_CNT 0x10009000 4 RW
Yes AES_MACBLKCNT 0x10009004 2 W
Yes AES_BLKCNT 0x10009006 2 W
Yes AES_WRFIFO 0x10009008 4 W
Yes AES_RDFIFO 0x1000900C 4 R
Yes AES_KEYSEL 0x10009010 1 RW
Yes AES_KEYCNT 0x10009011 1 RW
Yes AES_CTR 0x10009020 16 W
Yes AES_MAC 0x10009030 16 W
Yes AES_KEY0 0x10009040 48 W
Yes AES_KEY1 0x10009070 48 W
Yes AES_KEY2 0x100090A0 48 W
Yes AES_KEY3 0x100090D0 48 W
Yes AES_KEYFIFO 0x10009100 4 W
Yes AES_KEYXFIFO 0x10009104 4 W
Yes AES_KEYYFIFO 0x10009108 4 W

AES_CNT[edit]

Bit Description
4-0 Write FIFO count (0-16)
9-5 Read FIFO count (0-16)
10 Flush write FIFO (1=Clear write FIFO)
11 Flush read fifo (1=Clear read FIFO)
12-13 Write FIFO DMA size (0=16, 1=12, 2=8, 3=4 words)
14-15 Read FIFO DMA size (0=4, 1=8, 2=12, 3=16 words)
18-16 MAC size (encoding = (maclen-2)/2)
19 ? (MAC related)
20 MAC input control (0 = read MAC from FIFO, 1 = read from MAC register)
21 MAC status (0 = invalid, 1 = verified)
22 Output endianness (1=Big endian, 0=Little endian)
23 Input endianness (1=Big endian, 0=Little endian)
24 Output word order (1=Normal order, 0=Reversed order)
25 Input word order (1=Normal order, 0=Reversed order)
26 Update keyslot (selects the keyslot specified by AES_KEYSEL when this bit is set)
29-27 Mode (0=CCM decrypt, 1=CCM encrypt, 2=CTR, 3=CTR, 4=CBC decrypt, 5=CBC encrypt, 6=ECB decrypt, 7=ECB encrypt)
30 Interrupt enable (1=enable, 0=disable)
31 Start (1=enable/busy, 0=idle)

When bit31 is set, this register essentially becomes locked and doesn't change when written to. However if bit26 is "set", keyslot-selection is cued to be handled when bit31 is cleared.

Clearing bit31 while the AES engine is doing crypto will result in the AES engine stopping crypto, once it finishes processing the current block.

Read/Write FIFO counts and the MAC status can never be set by writing to AES_CNT, they are read-only.

Changing the input word order triggers the key/keyX/keyY FIFOs to be flushed.

AES_MACEXTRABLKCNT[edit]

(CCM-MAC extra data length)>>4, i.e. the number of block of CCM-MAC extra data.

AES_BLKCNT[edit]

(Data length)>>4, i.e. the number of blocks to process

AES_WRFIFO/AES_RDFIFO[edit]

The AES engine can accept up to 64 bytes of input data (16 32-bit words) and can hold up to 64 bytes of output data at a time (for a total of 128 bytes of buffered data). Bits 12-13 and 14-15 in AES_CNT configure the DMA request for the relevant FIFO (see above).

The input data for the AES crypto operation is written to AES_WRFIFO, the output data is read from AES_RDFIFO.

Reading from AES_RDFIFO when there's no data available in the RDFIFO will result in reading the last word that was in the RDFIFO.

When triggering either RDFIFO or WRFIFO to be flushed, the AES Engine does not clear either buffer.

Word order and endianness can be changed between each read/write to these FIFOs. However changing the word order when writing to WRFIFO can cause the word to be written outside the current block, leaving uninitialized data in its place. Attempts to change endianness or word order are not honored when reading from RDFIFO when no more data is available.

AES_KEYCNT[edit]

Bit Description
5-0 Keyslot
6 Hardware key-generator type: 0 = 3DS, 1 = DSi.
7 This normally has value 1 written here when updating keys. 0 = disable key FIFO flush, 1 = enable key FIFO flush.

Bit6 is only used when keyslots >=4 are used, value1 has the same affect as doing key-init with the TWL keyslots. Bit6 is only checked when a keyY was completely written, for when the final-normalkey needs updated via the key-generator. Changing bit6 has no affect on the generated normalkey when writing to this bit immediately after writing the last keyY word.

AES_CTR[edit]

This register specifies the counter (CTR mode), nonce (CCM mode) or the initialization vector (CBC mode) depending on the mode of operation. For CBC and CTR mode this register takes up the full 16 bytes, but for CCM mode the nonce is only the first 12 bytes. The AES engine will automatically increment the counter up to the maximum BLKCNT, after which point it must be manually incremented and set again.

AES_MAC[edit]

This register specifies the message authentication code (MAC) for use in CCM mode.

AES_KEY0/1/2/3[edit]

These registers are the same as they were on TWL, and are likely preserved for compatibility reasons. The keyslot is updated immediately after *any* data(u8/u32/...) is written here, which was used on DSi to break the key-generator.

Endianness and word order[edit]

AES_CNT.input_endianness[edit]

Swaps the bytes of 32-bit writes to AES_CTR, AES_WRFIFO, AES_KEY*FIFO according to specified endianness. AES_MAC?

AES_CNT.output_endianness[edit]

Swaps the bytes of 32-bit reads from AES_RDFIFO.

AES_CNT.input_word_order[edit]

If reversed, writes to AES_KEY*FIFO and AES_WRFIFO fill the FIFO backwards. For AES_WRFIFO, this means that every 16-byte block will have its words in the reverse order, but the order of these blocks remains the same. AES_CTR is unaffected by this field. AES_MAC?

AES_CNT.output_word_order[edit]

If reversed, reads from AES_RDFIFO will drain the FIFO backwards. This means that every 16-byte output block will have its words in the reverse order, but the order of these blocks remains the same.

CCM mode pitfall[edit]

Non-standard AES-CCM behaviour is observed on Wrap/Unwrap function. According to RFC 3610, the first block B_0 for authentication should be generated from the message length and some other parameters. Using these function, it seems that the message length is aligned up to 16 when generating B_0. This makes the generated MAC not compliant with the standard when (inputsize-noncesize)%16!=0. It is very likely that this non-standard behaviour happens on the hardware level, but not confirmed yet.

Keyslot ranges[edit]

This is approximately a table of what is set by bootrom before booting into FIRM. Often it appears that keyslots in groups of 4 have the same keyX, and sometimes also same keyY set.

Byte Description
0-15 Normalkey
16-31 KeyX
32-47 KeyY
Keyslot Name KeyX KeyY/Normal-key Console unique.
0x00-0x03 TWL keys. Probably unset. Probably unset. -
0x04-0x07 NAND partition keys. Same for all. Different for all. Yes
0x08-0x0B See below. Same for all. Different for all. Yes
0x0C-0x0F SSL cert key. Same for all. Same for all, normalkeys-only. The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
0x10-0x17 - Set for all except 0x11..0x13. Keydata is different for these. Normalkey, same for all except the last 4 are all different. -
0x18-0x1B Never used. Same for all. Same for all, normalkeys-only. The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
0x1C-0x1F Never used. Same for all. Same for all, normalkeys-only. The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
0x20-0x23 Never used. Same for all. Same for all, normalkeys-only. The keyXs are console-unique, however the normalkeys setup by Boot9 later during keyinit are not console-unique.
0x24 Never used. Individually set. Individually set, normalkey-only. The keyX is console-unique, however the normalkey setup by Boot9 later during keyinit is not console-unique.
0x25-0x27 - Not set. Same for all, normalkeys-only. Same keydata as keyslot 0x24. No
0x28-0x2B Never used. Individually set. Individually set, normalkeys-only. Keyslot 0x28 has same normalkey as keyslot 0x24. The keyX is console-unique, however the normalkey setup by Boot9 later during keyinit is not console-unique.
0x2C-0x2F Various uniques. Same for all. Same for all, normalkeys-only. No
0x30-0x33 Various uniques. Same for all. Same for all, normalkeys-only. No
0x34-0x37 Various uniques. Same for all. Same for all, normalkeys-only. No
0x38-0x3B Various uniques. Same for all. Same for all, normalkeys-only. No
0x3C-0x3F Various uniques. Individually set. Individually set, normalkeys-only. Keyslot 0x3C has same normalkey as 0x38-0x3B. No

Keyslot pairs (0x24, 0x28) and (0x38, 0x3C) shares the same normal-key, while at the same time having different keyX's. This suggests they were set to same normal-key by bootrom.

Keyslots[edit]

There are 0x40 keyslots, each of which stores three keys called keyX, keyY and normalkey. All keys can be set explicitly, but the normalkey can optionally be generated using a hardware key generator instead (see below). There is no way to read the contents of a keyslot.

Keyslot Description KeyX set by KeyY set by Normal-key Old3DS
0x00-0x03 TWL keys. NATIVE_FIRM hard-boot. NATIVE_FIRM hard-boot. - Yes
0x04..0x07 NAND partition keys.

Keyslot is determined by NCSD partition FS type and encryption type. The New3DS Process9 sets the keyY for keyslot 0x05 (New3DS CTRNAND) to a key from .(ro)data. Its keyX is console-unique and set by the bootloader.

Bootrom. Bootrom. - Yes
0x0A DSiWare export key.

Used for encrypting the all-zero 0x10-byte block in the DSiWare_Exports header. Console-unique.

See above keyslot info. See above keyslot info. - Yes
0x0B This is console-unique. This keyslot is used for the NAND dbs images AES-CMACs, and the Nand/private/movable.sed AES-CMAC(when used). See above keyslot info. See above keyslot info. - Yes
0x0D SSL-certificate key.

See EncryptDecryptAes.

- - Bootrom. Yes
0x11 Temporary keyslot.

Used by FIRM for general normal-key crypto. Also used by the New3DS FIRM arm9 binary loader.

Arm9Loader. Arm9Loader. NATIVE_FIRM. Yes
0x14 Starting with 5.0.0-11, NATIVE_FIRM Process9 now sets the keyY for this to the same one it uses for initializing 3 of the keyslots' keyYs from here. Bootrom. NATIVE_FIRM boot. - Yes
0x15 Used/initialized by the New3DS arm9 binary loader, see here. Arm9Loader. Arm9Loader. See previous info for this keyslot. No
0x16 Used/initialized by the New3DS arm9 binary loader starting with 9.5.0-X, see here. Arm9Loader. Arm9Loader. See previous info for this keyslot. No
0x18..0x1F These are the New3DS keyslots, where the keyX is generated with keyslot 0x11 by the New3DS arm9 binary loader. As of FIRM 9.6.0-X keyslots 0x1C..0x1F are not yet used by Process9. Arm9Loader. NATIVE_FIRM / see previous info for these keyslots. See previous info for these keyslots. No
0x18 New3DS 9.3.0-X NCCH key, when ncchflag[3] is 0x0A. Arm9Loader. NATIVE_FIRM - No
0x19 New3DS gamecard savedata AES-CMAC key.

Equivalent of keyslot 0x33, used when a NCSD flag is set to a certain value (implemented with 9.3.0-X).

Arm9Loader. NATIVE_FIRM - No
0x1A New3DS gamecard savedata actual key.

Equivalent of keyslot 0x37, used when a NCSD flag is set to a certain value (implemented with 9.3.0-X).

Arm9Loader. NATIVE_FIRM - No
0x1B New3DS 9.6.0-X NCCH key, when ncchflag[3] is 0x0B. Arm9Loader. NATIVE_FIRM - No
0x24 AGB_FIRM savegame AES-CMAC key. Bootrom. AGB/NATIVE_FIRM. - Yes
0x25 v7.0 NCCH key, when ncchflag[3] is 0x01. NATIVE_FIRM boot. NATIVE_FIRM. - Yes
0x2C Original NCCH key, when ncchflag[3] is 0x00 and always for certain NCCH sections. Bootrom. Process9. - Yes
0x2D UDS local-WLAN CCMP key.

See EncryptDecryptAes.

Bootrom. Bootrom. - Yes
0x2E Streetpass key.

See EncryptDecryptAes.

Bootrom. NATIVE_FIRM. - Yes
0x2F v6.0 save key. Bootrom. NATIVE_FIRM. - Yes
0x30 SD/NAND AES-CMAC key.

This keyY is initialized via movable.sed. This is used for calculating the AES-CMACs under SD /Nintendo 3DS/<ID0>/<ID1>/ (except DSiWare_Exports) and NAND /data/.

Bootrom. NATIVE_FIRM. - Yes
0x31 APT wrap key.

See EncryptDecryptAes. NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.

Bootrom. NATIVE_FIRM. - Yes
0x32 Unknown.

See EncryptDecryptAes.

Bootrom. Bootrom. - Yes
0x33 Gamecard savedata AES-CMAC. Bootrom. NATIVE_FIRM. - Yes
0x34 SD key.

This keyY is initialized via movable.sed. This is used for encrypting *all* SD card data under /Nintendo 3DS/<ID0>/<ID1>/.

Bootrom. NATIVE_FIRM. - Yes
0x35 Movable.sed key.

This is the keyslot used for movable.sed encryption + AES-CBC MAC with the import/export commands. The keyYs used for crypto/CMAC are different, but both can be found in process9 rodata.

Bootrom. NATIVE_FIRM. - Yes
0x36 Unknown. Used by friends module.

See EncryptDecryptAes.

Bootrom. Bootrom. - Yes
0x37 Gamecard savedata actual key. Bootrom. NATIVE_FIRM. - Yes
0x38 BOSS key.

See EncryptDecryptAes.

Bootrom. Bootrom. - Yes
0x39 Download Play key, and the actual NFC key for generating retail Amiibo keys.

This keyslot is used for two different keys. Both are available via EncryptDecryptAes. NATIVE_FIRM sets this keyY to the same one used for keyslot 0x2E.

Bootrom. NATIVE_FIRM. - Yes
0x3A DSiWare export key.

This keyY is initialized via movable.sed. This is used for calculating the AES-CMACs for SD DSiWare_Exports.

Bootrom. NATIVE_FIRM. - Yes
0x3B CTR-CARD hardware-crypto seed decryption key.

AES-CCM is used, the keyY, nonce and MAC are stored in the Card Info Header.

Bootrom. NATIVE_FIRM. - Yes
0x3D Common key.

Used to decrypt title keys in Ticket.

Bootrom. NATIVE_FIRM. - Yes
0x3F Used for various internal Boot9 crypto operations, different keydata for each one. Used to decrypt the OTP, the FIRM sections when booting from non-NAND, and when generating the console-unique keys.

The keydata for this keyslot is overwritten with other keydata before booting FIRM. This keyslot is not known to be used post-Boot9.

Bootrom. Bootrom. Bootrom. Yes

Updating keydata[edit]

The contents of the keyslot specified in AES_KEYCNT can be updated by consecutively writing four words to AES_KEYXFIFO (keyX), AES_KEYYFIFO(keyY), or AES_KEYFIFO (normalkey).

After writing to a keyslot, the keyslot must be selected again(write AES_KEYSEL + set AES_CNT bit26), even when writing to the same keyslot. Writing the last word to a key FIFO immediately after selecting a keyslot will not affect the keyslot keydata that gets used at that time, the new keydata will not get used until the keyslot gets selected again.

Writing to the key FIFOs with byte writes results in the AES engine converting the byte to a word for setting the key word, with this: word = (byteval) | (byteval<<8) | (byteval<<16) | (byteval<<24). The result is the same regardless of which FIFO register byte was written to.

The TWL keyslots 0x00-0x03 can be set directly by writing to the AES_KEY0-AES_KEY3 registers.

The key FIFOs can be written simultaneously. For example, executing the following will result in the keyX and keyY being set to all-zero(unknown for normalkey): memset(0x10009100, 0, 0x100);

Each key FIFO has a 0x10-byte tmp-buffer for storing the words written to that FIFO. Once the last word is written to a key FIFO, the filled tmp-buffer is then written to the key-data for the keyslot selected by AES_KEYCNT at the time the last word was written.

Hardware key generator[edit]

A dedicated hardware key generator can be used to generate a keyslot's normal-key from its keyX and keyY. The hardware key generator is triggered by writing the keyY, which is the only way to trigger it with the 3DS keyslots.

The algorithm for generating the normal-key from keyX and keyY is as follows, in big-endian 128-bit unsigned wraparound arithmetic:

Mode Formula
3DS NormalKey = (((KeyX ROL 2) XOR KeyY) + C1) ROR 41
DSi NormalKey = ((KeyX XOR KeyY) + C2) ROL 42

Unless noted otherwise, all keyslots on retail units use the hardware key generator.

FIRM-launch key clearing[edit]

Starting with 9.0.0-20 the Process9 FIRM-launch code now "clears" the following AES keyslots, with certain keydata by writing the normal-key: 0x15 and 0x18-0x20. These are the keyslots used by the New3DS FIRM arm9bin loader(minus keyslot 0x11), the New3DS Process9 does this too.

AES key-init[edit]

See here for how Boot9 initializes the AES keyslots.

For an issue with console-unique key-init, see here.

Some of the Boot9 key-init appears to have a bug(?) when initializing a chunk of keyslots at once: normally it does for(i=0; i<4; i++){... <setup_keyslot_keydata(keyslotbase+i, keydata)> ...}, however in some cases it does that except with (keyslotbase, instead. This results in the keyslot specified by keyslotbase being initialized 4 times in a row, with the remaining 3 keyslots following keyslotbase being left uninitialized.

initialize_aeskeys() works as follows:

  • Validates input, calls panic() on failure. conunique_dataptr and bootrom_dataptr are both input parameters for initialize_aeskeys().
  • Calls crypto_initialize().
  • Then it basically: copies 0x1C-bytes from conunique_dataptr to tmpbuf+0(sp+12), and copies data from bootrom_dataptr with size 0x40-0x1C to tmpbuf+0x1C(conunique_dataptr and bootrom_dataptr are updated afterwards).
  • The 0x40-byte tmpbuf is hashed with SHA256.
  • Keyslot 0x3F is then initialized using the above hash: keyX = first 0x10-bytes of the hash, keyY = last 0x10-bytes of the hash.
  • Then with each console-unique key-init code-block: IV is loaded from bootrom_dataptr(which is updated afterwards), then the 0x40-bytes from bootrom_dataptr is encrypted with AES-CBC. The output is then used as 4 keyXs for initializing keyslots. How bootrom_dataptr is updated if at all varies per code-block. Hashing similar to the code at the start of this function is also run(when the remaining size for conunique_dataptr is non-zero), but the output hash isn't used(this code is also slightly different for one code-block).
  • Once finished with that, the non-console-unique keyslots are initialized. This is done with keydata loaded directly from bootrom_dataptr.
  • The last initialized keyslot is 0x3F, via normalkey. The keydata for this is copied to 0xFFF00618. This is for restoring the keydata when non-NAND FIRM boot fails, since those use keyslot 0x3F with other keydata.
  • Lastly it clears the 0x40-bytes at tmpbuf with the u32 loaded from bootrom_dataptr(the word following the above keyslot 0x3F keydata), then returns.

The keyslots are initialized with the same order of keyslots+keydata_type listed below:

Console-unique keydata, after the initialization for the key-generation keyslot(0x3F):

 0x04..0x07 keyX
 0x08..0x0B keyX
 0x0C..0x0F keyX
 0x10       keyX
 0x14..0x17 keyX
 0x18..0x1B keyX
 0x1C..0x1F keyX
 0x20..0x23 keyX
 0x24       keyX
 0x28..0x2B keyX

Common keydata:

 0x2C..0x2F keyX
 0x30..0x33 keyX
 0x34..0x37 keyX
 0x38..0x3B keyX
 0x3C..0x3F keyX
 0x04..0x0B keyY
 0x0C..0x0F normalkey
 0x10..0x13 normalkey
 0x14..0x17 normalkey
 0x18..0x1B normalkey
 0x1C..0x1F normalkey
 0x20..0x23 normalkey
 0x24..0x27 normalkey
 0x28..0x2B normalkey
 0x2C..0x2F normalkey
 0x30..0x33 normalkey
 0x34..0x37 normalkey
 0x38..0x3B normalkey
 0x3C..0x3F normalkey