mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-22 11:56:40 +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
|
||||
};
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
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];
|
||||
nx_keyblob_t keyblob;
|
||||
nx_dec_keyblob_t dec_keyblob;
|
||||
|
||||
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
||||
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;
|
||||
}
|
||||
set_aes_keyslot(0xD, work_buffer, 0x10);
|
||||
|
||||
/* Get keyblob, always try to set up the highest possible master key. */
|
||||
/* TODO: Should we iterate, trying lower keys on failure? */
|
||||
if (get_keyblob(&keyblob, MASTERKEY_REVISION_500_CURRENT, keyblobs, available_revision) != 0) {
|
||||
return -1;
|
||||
|
||||
/* Decrypt all keyblobs. */
|
||||
for (unsigned int rev = MASTERKEY_REVISION_100_230; rev < MASTERKEY_REVISION_500_CURRENT; rev++) {
|
||||
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always try to set up the highest possible master key. */
|
||||
/* 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);
|
||||
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_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);
|
||||
|
||||
/* 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 latest keyblob. */
|
||||
dec_keyblob = g_dec_keyblobs[MASTERKEY_REVISION_500_CURRENT];
|
||||
|
||||
/* Get needed data. */
|
||||
set_aes_keyslot(0xC, keyblob.keys[0], 0x10);
|
||||
set_aes_keyslot(0xB, keyblob.keys[8], 0x10);
|
||||
|
||||
/* Clear keyblob. */
|
||||
memset(keyblob.data, 0, sizeof(keyblob.data));
|
||||
set_aes_keyslot(0xC, dec_keyblob.keys[0], 0x10);
|
||||
|
||||
/* Derive keys for Exosphere, lock critical keyslots. */
|
||||
switch (target_firmware) {
|
||||
|
|
|
@ -22,17 +22,22 @@ typedef enum BisPartition {
|
|||
BisPartition_UserSystem = 2,
|
||||
} BisPartition;
|
||||
|
||||
typedef struct {
|
||||
uint8_t keys[9][0x10];
|
||||
} nx_dec_keyblob_t;
|
||||
|
||||
typedef struct nx_keyblob_t {
|
||||
uint8_t mac[0x10];
|
||||
uint8_t ctr[0x10];
|
||||
union {
|
||||
uint8_t data[0x90];
|
||||
uint8_t keys[9][0x10];
|
||||
nx_dec_keyblob_t dec_blob;
|
||||
};
|
||||
} nx_keyblob_t;
|
||||
|
||||
/* 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 load_package1_key(uint32_t revision);
|
||||
void finalize_nx_keydata(uint32_t target_firmware);
|
||||
|
||||
void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmware);
|
||||
|
|
Loading…
Reference in a new issue