Cryptosystem: Difference between revisions
nintendo and nvidia don't know what a microscope is :P |
→Versions: fix M1-M4 |
||
(40 intermediate revisions by 11 users not shown) | |||
Line 1: | Line 1: | ||
= BootROM = | |||
The bootrom initializes two keyslots in the hardware engine: | |||
* the SBK (Secure Boot Key) in keyslot 14 | |||
* the SSK (Secure Storage Key) in keyslot 15. | |||
Reads from both of these keyslots are disabled by the bootROM. | |||
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes. | |||
SBK is '''unique''' per console, and not shared among consoles as originally believed. | |||
The | The SSK is derived on boot via the SBK, the 32-bit console-unique "Device Key", and hardware information stored in fuses. | ||
== | Pseudocode for the derivation is as follows: | ||
void generateSSK() { | |||
char keyBuffer[0x10]; // Used to store keydata | |||
uint hwInfoBuffer[4]; // Used to store info about hardware from fuses | |||
uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4. | |||
for (int i = 0; i < 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey | |||
((uint *)keyBuffer)[i] = deviceKey; | |||
} | |||
encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...}) | |||
// Set up Hardware info buffer | |||
uint vendor_code = *((uint *)0x7000FA00) & 0x0000000F; // FUSE_VENDOR_CODE | |||
uint fab_code = *((uint *)0x7000FA04) & 0x0000003F; // FUSE_FAB_CODE | |||
uint lot_code_0 = *((uint *)0x7000FA08) & 0xFFFFFFFF; // FUSE_LOT_CODE_0 | |||
uint lot_code_1 = *((uint *)0x7000FA0C) & 0x0FFFFFFF; // FUSE_LOT_CODE_1 | |||
uint wafer_id = *((uint *)0x7000FA10) & 0x0000003F; // FUSE_WAFER_ID | |||
uint x_coord = *((uint *)0x7000FA14) & 0x000001FF; // FUSE_X_COORDINATE | |||
uint y_coord = *((uint *)0x7000FA18) & 0x000001FF; // FUSE_Y_COORDINATE | |||
uint unk_hw_fuse = *((uint *)0x7000FA20) & 0x0000003F; // Unknown cached fuse. | |||
// HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID | |||
hwInfoBuffer[0] = (lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | unk_hw_fuse; | |||
hwInfoBuffer[1] = (lot_code_0 << 26) | (lot_code_1 >> 2); | |||
hwInfoBuffer[2] = (fab_code << 26) | (lot_code_0 >> 6); | |||
hwInfoBuffer[3] = vendor_code; | |||
for (int i = 0; i < 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER) | |||
keyBuffer[i] ^= ((char *)hwInfoBuffer)[i]; | |||
} | |||
encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)) | |||
setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer. | |||
} | |||
= Falcon coprocessor = | |||
The falcon processor (TSEC) generates a special console-unique key (that will be referred to as the "tsec key"). | |||
This is presumably using data stored in fuses that only microcode authenticated by NVidia has access to. | |||
= Package1ldr = | |||
== Key table == | |||
[1.0.0-3.0.2] During package1ldr: | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 19: | Line 61: | ||
! Name | ! Name | ||
! Set by | ! Set by | ||
! Per-console | ! Per-console | ||
! Per-firmware | |||
|- | |- | ||
| | | 11 | ||
| | | Package1Key | ||
| [[Package1 | | [[Package1#Package1ldr|Package1ldr]] | ||
| | |||
| No | | No | ||
| Yes | |||
|- | |||
| 14 | |||
| SecureBootKey | |||
| Bootrom | |||
| Yes | |||
| No | |||
|- | |||
| 15 | |||
| SecureStorageKey | |||
| Bootrom | |||
| Yes | |||
| No | |||
|} | |||
[1.0.0-3.0.2] After package1ldr: | |||
{| class="wikitable" border="1" | |||
|- | |- | ||
| | ! Keyslot | ||
! Name | |||
! Set by | |||
! Per-console | |||
! Per-firmware | |||
|- | |||
| 12 | |||
| MasterKey | | MasterKey | ||
| [[Package1]] | | [[Package1#Package1ldr|Package1ldr]] | ||
| | | No | ||
| Yes, on security updates | |||
|- | |||
| 13 | |||
| PerConsoleKey | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| Yes | |||
| No | |||
|} | |||
[4.0.0+] After package1ldr (Secure Monitor boot): | |||
{| class="wikitable" border="1" | |||
|- | |||
! Keyslot | |||
! Name | |||
! Set by | |||
! Per-console | |||
! Per-firmware | |||
|- | |||
| 12 | |||
| MasterKey | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| No | |||
| Yes, on security updates | |||
|- | |||
| 13 | |||
| PerConsoleKeyForFirmwareSpecificPerConsoleKeyGen | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| Yes | |||
| No | |||
|- | |||
| 14 | |||
| StaticKeyForFirmwareSpecificPerConsoleKeyGen | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| No | |||
| Yes, on security updates | |||
|- | |||
| 15 | |||
| PerConsoleKey | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| Yes | |||
| No | |||
|} | |||
[4.0.0+] After package1ldr (Secure Monitor runtime): | |||
{| class="wikitable" border="1" | |||
|- | |||
! Keyslot | |||
! Name | |||
! Set by | |||
! Per-console | |||
! Per-firmware | |||
|- | |||
| 12 | |||
| MasterKey | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| No | |||
| Yes, on security updates | |||
|- | |||
| 13 | |||
| FirmwareSpecificPerConsoleKey | |||
| Secure Monitor init | |||
| Yes | |||
| Yes, on security updates | |||
|- | |||
| 15 | |||
| PerConsoleKey | |||
| [[Package1#Package1ldr|Package1ldr]] | |||
| Yes | |||
| No | | No | ||
|} | |||
[6.2.0+] After package1ldr/TSEC Payload (Secure Monitor boot): | |||
{| class="wikitable" border="1" | |||
|- | |- | ||
| | ! Keyslot | ||
| | ! Name | ||
| [[ | ! Set by | ||
! Per-console | |||
! Per-firmware | |||
|- | |||
| 12 | |||
| TsecKey | |||
| [[TSEC#Payload|Package1ldr TSEC Firmware]] | |||
| Yes | | Yes | ||
| No | |||
|- | |- | ||
| | | 13 | ||
| TsecRootKey | |||
| [[TSEC#Payload|Package1ldr TSEC Firmware]] | |||
| No | |||
| Unknown | |||
|- | |||
| 14 | |||
| SecureBootKey | | SecureBootKey | ||
| Bootrom | | Bootrom | ||
| | | Yes | ||
| No | | No | ||
|- | |- | ||
| | | 15 | ||
| SecureStorageKey | | SecureStorageKey | ||
| Bootrom | | Bootrom | ||
| Yes | | Yes | ||
| No | |||
|} | |} | ||
== Key generation == | |||
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption. | |||
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only): | |||
// Final keys: | |||
package1_key /* slot11 */ = aes_unwrap(f5b1eadb.., sbk) | |||
master_key /* slot12 */ = aes_unwrap(bct->pubkey[0] == 0x11 ? simpleseed_dev0 : simpleseed_dev1, aes_unwrap(5ff9c2d9.., sbk)) | |||
per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk)) | |||
[4.0.0+] Above method was removed. | |||
Normal key generation looks like this on 1.0.0/2.0.0: | |||
keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */) | |||
cmac_key /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key) | |||
if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]: | |||
panic() | |||
aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key) | |||
// Final keys: | |||
package1_key /* slot11 */ = keyblob[0x80:0x90] | |||
master_key /* slot12 */ = aes_unwrap(bct->pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20) | |||
per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key) | |||
.. and on 3.0.0, they moved keyslots around a little to generate the same per-console key as 1.0.0: | |||
old_keyblob_key /* slot10 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */) | |||
keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */) | |||
cmac_key /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key) | |||
if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]: | |||
panic() | |||
aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key) | |||
// Final keys: | |||
package1_key /* slot11 */ = keyblob[0x80:0x90] | |||
master_key /* slot12 */ = aes_unwrap(bct->pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20) | |||
per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., old_keyblob_key) | |||
.. and on 4.0.0 it was further moved around: | |||
keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */) | |||
cmac_key /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key) | |||
if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]: | |||
panic() | |||
aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key) | |||
// Final keys: | |||
package1_key /* slot11 */ = keyblob[0x80:0x90] | |||
master_key /* slot12 */ = aes_unwrap(normalseed_retail, keyblob+0x20) | |||
new_master_key /* slot14 */ = aes_unwrap(2dc1f48d.., keyblob+0x20) | |||
new_per_console_key /* slot13 */ = aes_unwrap(0c9109db.., old_keyblob_key) | |||
per_console_key /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key) | |||
.. and on 6.2.0, they moved key generation out of package1ldr, and into the Secure Monitor's boot section: | |||
clear_keyslots_other_than_12_13_and_14() | |||
old_keyblob_key /* slot15 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot12 */), sbk /* slot14 */) | |||
/* Previously, master_kek was stored at keyblob+0x20) */ | |||
master_kek /* slot13 */ = aes_unwrap(374b7729.. /* probably firmware specific */, tsec_root_key /* slot13 */) | |||
clear_keyslot(12) | |||
// Final keys: | |||
new_master_key /* slot12 */ = aes_unwrap(2dc1f48d.., master_kek) | |||
master_key /* slot13 */ = aes_unwrap(normalseed_retail, master_kek) | |||
new_per_console_key /* slot14 */ = aes_unwrap(0c9109db.., old_keyblob_key) | |||
per_console_key /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key) | |||
SBK and SSK keyslots are cleared after keys have been generated. | |||
See table above for which keys are console unique. | |||
The key used to verify a keyblob's MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob. | The key used to verify a keyblob's MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob. | ||
The bootloader only stores the | The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants. | ||
This | This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob. | ||
Dumping the | Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system, prior to 6.2.0. | ||
The key-derivation is described [[Package1#Key_generation|here]]. | The key-derivation is described in more detail [[Package1#Key_generation|here]]. | ||
=== | === Keyblob === | ||
There are 32 keyblobs written to NAND at factory, with each keyblob encrypted with a console-unique key derived from the console's SBK, the console's tsec key, and a constant specific to each keyblob. | |||
Despite being encrypted with console unique keys, though, the decrypted keyblob contents are shared for all consoles. | |||
Used keyblobs are as follows: | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 86: | Line 310: | ||
| 3.0.0 | | 3.0.0 | ||
| 2 | | 2 | ||
| 1 | |||
|- | |||
| 3.0.1-3.0.2 | |||
| 3 | |||
| 1 | |||
|- | |||
| 4.0.0-4.1.0 | |||
| 4 | |||
| 1 | |||
|- | |||
| 5.0.0-5.1.0 | |||
| 5 | |||
| 1 | |||
|- | |||
| 6.0.0-6.1.0 | |||
| 6 | |||
| 1 | | 1 | ||
|} | |} | ||
== | Starting from 6.2.0, key generation no longer uses keyblobs. | ||
=== Seeds === | |||
normalseed_retail = d8a2410a... | |||
[1.0.0] wrapped_keyblob_key = df206f59... | |||
[1.0.0] simpleseed_dev0 = aff11423... | |||
[1.0.0] simpleseed_dev1 = 5e177ee1... | |||
[1.0.0] normalseed_dev = 0542a0fd... | |||
[3.0.0] wrapped_keyblob_key = 0c25615d... | |||
[3.0.0] simpleseed_dev0 = de00216a... | |||
[3.0.0] simpleseed_dev1 = 2db7c0a1... | |||
[3.0.0] normalseed_dev = 678c5a03... | |||
[3.0.1] wrapped_keyblob_key = 337685ee... | |||
[3.0.1] simpleseed_dev0 = e045f5ba... | |||
[3.0.1] simpleseed_dev1 = 84d92e0d... | |||
[3.0.1] normalseed_dev = cd88155b... | |||
[4.0.0] wrapped_keyblob_key = 2d1f4880... | |||
=== Versions === | |||
The key generation system has historically been revised several times. Each version is bound to a specific BCT public key and can be identified by its first byte as follows: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Version | |||
! BCT public key's first byte | |||
! Description | |||
|- | |||
| K1 | |||
| 0x11 | |||
| Erista prototype development | |||
|- | |||
| K2 | |||
| 0xFB | |||
| Erista prototype development | |||
|- | |||
| K3 | |||
| 0x4F | |||
| Erista prototype development | |||
|- | |||
| K4 | |||
| | |||
| Erista prototype retail | |||
|- | |||
| K5 | |||
| 0x37 | |||
| Erista development | |||
|- | |||
| K6 | |||
| 0xF7 | |||
| Erista retail | |||
|- | |||
| M1 | |||
| 0x19 | |||
| Mariko prototype development | |||
|- | |||
| M2 | |||
| 0xC3 | |||
| Mariko development | |||
|- | |||
| M3 | |||
| 0xDD | |||
| Mariko prototype retail (pre-6.0.0) | |||
|- | |||
| M4 | |||
| 0x9B | |||
| Mariko retail | |||
|} | |||
= Secure Monitor Init = | |||
On all versions, the key to decrypt [[Package2]] is generated by decrypting a constant seed with the master key. The key is erased after use. | |||
Additionally, starting from 4.0.0, the Secure Monitor init will decrypt another constant seed successively with a special per console key and a special static key passed by package1loader, to generate the firmware specific per-console key. The operation will erase these special keys passed by package1loader. | |||
= Secure Monitor = | |||
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides. | The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides. |