mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
Fusee: Decrypt all keyblobs during key derivation.
This commit is contained in:
parent
f84645e91f
commit
fa71e9cb15
2 changed files with 54 additions and 23 deletions
|
@ -33,6 +33,8 @@ static const uint8_t masterkey_4x_seed[0x10] = {
|
||||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static nx_dec_keyblob_t __attribute__((aligned(16))) g_dec_keyblobs[32];
|
||||||
|
|
||||||
static int get_tsec_key(void *dst, const void *tsec_fw, size_t tsec_fw_size, uint32_t tsec_key_id) {
|
static int get_tsec_key(void *dst, const void *tsec_fw, size_t tsec_fw_size, uint32_t tsec_key_id) {
|
||||||
return tsec_query((u32)tsec_fw, dst, tsec_key_id);
|
return tsec_query((u32)tsec_fw, dst, tsec_key_id);
|
||||||
}
|
}
|
||||||
|
@ -61,10 +63,43 @@ static bool safe_memcmp(uint8_t *a, uint8_t *b, size_t sz) {
|
||||||
return different != 0;
|
return different != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint32_t available_revision) {
|
||||||
|
nx_keyblob_t keyblob;
|
||||||
|
nx_dec_keyblob_t *dec = &g_dec_keyblobs[revision];
|
||||||
|
uint8_t work_buffer[0x10];
|
||||||
|
|
||||||
|
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
|
||||||
|
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, 0xE, work_buffer, 0x10);
|
||||||
|
decrypt_data_into_keyslot(0xB, KEYSLOT_SWITCH_TEMPKEY, keyblob_mac_seed, 0x10);
|
||||||
|
|
||||||
|
/* Validate keyblob. */
|
||||||
|
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
|
||||||
|
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt keyblob. */
|
||||||
|
se_aes_ctr_crypt(0xD, dec, sizeof(dec), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_package1_key(uint32_t revision) {
|
||||||
|
if (revision > MASTERKEY_REVISION_500_CURRENT) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_aes_keyslot(0xB, g_dec_keyblobs[revision].keys[8], 0x10);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Derive all Switch keys. */
|
/* Derive all Switch keys. */
|
||||||
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size) {
|
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size) {
|
||||||
uint8_t work_buffer[0x10];
|
uint8_t work_buffer[0x10];
|
||||||
nx_keyblob_t keyblob;
|
nx_dec_keyblob_t dec_keyblob;
|
||||||
|
|
||||||
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
||||||
set_aes_keyslot_flags(0xE, 0x15);
|
set_aes_keyslot_flags(0xE, 0x15);
|
||||||
|
@ -75,13 +110,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_aes_keyslot(0xD, work_buffer, 0x10);
|
set_aes_keyslot(0xD, work_buffer, 0x10);
|
||||||
|
|
||||||
/* Get keyblob, always try to set up the highest possible master key. */
|
/* Decrypt all keyblobs. */
|
||||||
/* TODO: Should we iterate, trying lower keys on failure? */
|
for (unsigned int rev = MASTERKEY_REVISION_100_230; rev < MASTERKEY_REVISION_500_CURRENT; rev++) {
|
||||||
if (get_keyblob(&keyblob, MASTERKEY_REVISION_500_CURRENT, keyblobs, available_revision) != 0) {
|
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
|
||||||
return -1;
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Always try to set up the highest possible master key. */
|
||||||
/* Derive both keyblob key 1, and keyblob key latest. */
|
/* Derive both keyblob key 1, and keyblob key latest. */
|
||||||
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[MASTERKEY_REVISION_100_230], 0x10);
|
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[MASTERKEY_REVISION_100_230], 0x10);
|
||||||
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
|
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
|
||||||
|
@ -90,24 +128,12 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||||
|
|
||||||
/* Clear the SBK. */
|
/* Clear the SBK. */
|
||||||
clear_aes_keyslot(0xE);
|
clear_aes_keyslot(0xE);
|
||||||
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_mac_seed, 0x10);
|
|
||||||
decrypt_data_into_keyslot(0xB, 0xD, keyblob_mac_seed, 0x10);
|
/* Get latest keyblob. */
|
||||||
|
dec_keyblob = g_dec_keyblobs[MASTERKEY_REVISION_500_CURRENT];
|
||||||
/* Validate keyblob. */
|
|
||||||
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
|
|
||||||
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decrypt keyblob. */
|
|
||||||
se_aes_ctr_crypt(0xD, keyblob.data, sizeof(keyblob.data), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
|
|
||||||
|
|
||||||
/* Get needed data. */
|
/* Get needed data. */
|
||||||
set_aes_keyslot(0xC, keyblob.keys[0], 0x10);
|
set_aes_keyslot(0xC, dec_keyblob.keys[0], 0x10);
|
||||||
set_aes_keyslot(0xB, keyblob.keys[8], 0x10);
|
|
||||||
|
|
||||||
/* Clear keyblob. */
|
|
||||||
memset(keyblob.data, 0, sizeof(keyblob.data));
|
|
||||||
|
|
||||||
/* Derive keys for Exosphere, lock critical keyslots. */
|
/* Derive keys for Exosphere, lock critical keyslots. */
|
||||||
switch (target_firmware) {
|
switch (target_firmware) {
|
||||||
|
|
|
@ -22,17 +22,22 @@ typedef enum BisPartition {
|
||||||
BisPartition_UserSystem = 2,
|
BisPartition_UserSystem = 2,
|
||||||
} BisPartition;
|
} BisPartition;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t keys[9][0x10];
|
||||||
|
} nx_dec_keyblob_t;
|
||||||
|
|
||||||
typedef struct nx_keyblob_t {
|
typedef struct nx_keyblob_t {
|
||||||
uint8_t mac[0x10];
|
uint8_t mac[0x10];
|
||||||
uint8_t ctr[0x10];
|
uint8_t ctr[0x10];
|
||||||
union {
|
union {
|
||||||
uint8_t data[0x90];
|
uint8_t data[0x90];
|
||||||
uint8_t keys[9][0x10];
|
nx_dec_keyblob_t dec_blob;
|
||||||
};
|
};
|
||||||
} nx_keyblob_t;
|
} nx_keyblob_t;
|
||||||
|
|
||||||
/* TSEC fw must be 0x100-byte-aligned. */
|
/* TSEC fw must be 0x100-byte-aligned. */
|
||||||
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size);
|
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size);
|
||||||
|
int load_package1_key(uint32_t revision);
|
||||||
void finalize_nx_keydata(uint32_t target_firmware);
|
void finalize_nx_keydata(uint32_t target_firmware);
|
||||||
|
|
||||||
void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmware);
|
void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmware);
|
||||||
|
|
Loading…
Reference in a new issue