mirror of
https://github.com/SciresM/hactool
synced 2024-11-10 06:34:14 +00:00
pk11: add proper support for newer (and mariko) package1
This commit is contained in:
parent
55b13f0d67
commit
c3415cf25e
6 changed files with 371 additions and 61 deletions
4
aes.c
4
aes.c
|
@ -70,7 +70,7 @@ void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) {
|
||||||
mbedtls_cipher_reset(&ctx->cipher_enc);
|
mbedtls_cipher_reset(&ctx->cipher_enc);
|
||||||
|
|
||||||
/* XTS doesn't need per-block updating */
|
/* XTS doesn't need per-block updating */
|
||||||
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS)
|
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
|
||||||
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
|
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -110,7 +110,7 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
|
||||||
mbedtls_cipher_reset(&ctx->cipher_dec);
|
mbedtls_cipher_reset(&ctx->cipher_dec);
|
||||||
|
|
||||||
/* XTS doesn't need per-block updating */
|
/* XTS doesn't need per-block updating */
|
||||||
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS)
|
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
|
||||||
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
|
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
18
extkeys.c
18
extkeys.c
|
@ -284,7 +284,13 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
|
||||||
} else if (strcmp(key, "tsec_key") == 0) {
|
} else if (strcmp(key, "tsec_key") == 0) {
|
||||||
parse_hex_key(keyset->tsec_key, value, sizeof(keyset->tsec_key));
|
parse_hex_key(keyset->tsec_key, value, sizeof(keyset->tsec_key));
|
||||||
matched_key = 1;
|
matched_key = 1;
|
||||||
} else if (strcmp(key, "tsec_root_kek") == 0) {
|
} else if (strcmp(key, "mariko_kek") == 0) {
|
||||||
|
parse_hex_key(keyset->mariko_kek, value, sizeof(keyset->mariko_kek));
|
||||||
|
matched_key = 1;
|
||||||
|
} else if (strcmp(key, "mariko_bek") == 0) {
|
||||||
|
parse_hex_key(keyset->mariko_bek, value, sizeof(keyset->mariko_bek));
|
||||||
|
matched_key = 1;
|
||||||
|
} else if (strcmp(key, "tsec_root_kek") == 0) {
|
||||||
parse_hex_key(keyset->tsec_root_kek, value, sizeof(keyset->tsec_root_kek));
|
parse_hex_key(keyset->tsec_root_kek, value, sizeof(keyset->tsec_root_kek));
|
||||||
matched_key = 1;
|
matched_key = 1;
|
||||||
} else if (strcmp(key, "package1_mac_kek") == 0) {
|
} else if (strcmp(key, "package1_mac_kek") == 0) {
|
||||||
|
@ -365,6 +371,16 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 0xC && !matched_key; i++) {
|
||||||
|
snprintf(test_name, sizeof(test_name), "mariko_aes_class_key_%02"PRIx32, i);
|
||||||
|
if (strcmp(key, test_name) == 0) {
|
||||||
|
parse_hex_key(keyset->mariko_aes_class_keys[i], value, sizeof(keyset->mariko_aes_class_keys[i]));
|
||||||
|
matched_key = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
|
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
|
||||||
snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i);
|
snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i);
|
||||||
if (strcmp(key, test_name) == 0) {
|
if (strcmp(key, test_name) == 0) {
|
||||||
|
|
259
packages.c
259
packages.c
|
@ -5,6 +5,26 @@
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
|
|
||||||
|
static int pk11_is_mariko(pk11_ctx_t *ctx) {
|
||||||
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
if (fread(&ctx->mariko_oem_header, 1, sizeof(ctx->mariko_oem_header), ctx->file) != sizeof(ctx->mariko_oem_header)) {
|
||||||
|
fprintf(stderr, "Failed to read PK11 OEM Header!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 0x10; i++) {
|
||||||
|
if (ctx->mariko_oem_header.aes_mac[i] != 0 || ctx->mariko_oem_header._0x160[i] != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pk11_is_legacy(pk11_ctx_t *ctx) {
|
||||||
|
return ctx->metadata.version < 0x0E || memcmp(ctx->metadata.build_date, "20181107", 8) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
void pk11_process(pk11_ctx_t *ctx) {
|
void pk11_process(pk11_ctx_t *ctx) {
|
||||||
fseeko64(ctx->file, 0, SEEK_SET);
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
if (fread(&ctx->stage1, 1, sizeof(ctx->stage1), ctx->file) != sizeof(ctx->stage1)) {
|
if (fread(&ctx->stage1, 1, sizeof(ctx->stage1), ctx->file) != sizeof(ctx->stage1)) {
|
||||||
|
@ -12,50 +32,147 @@ void pk11_process(pk11_ctx_t *ctx) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if PK11 was built in 2016. */
|
// Detect mariko
|
||||||
/* This is a heuristic to detect an older layout for the PK11 binary. */
|
ctx->is_mariko = pk11_is_mariko(ctx);
|
||||||
if (ctx->stage1.build_date[0] == '2' && ctx->stage1.build_date[1] == '0' && ctx->stage1.build_date[2] == '1' && ctx->stage1.build_date[3] == '6') {
|
|
||||||
ctx->is_pilot = 1;
|
if (ctx->is_mariko) {
|
||||||
|
fseeko64(ctx->file, sizeof(ctx->mariko_oem_header), SEEK_SET);
|
||||||
|
|
||||||
|
if (ctx->mariko_oem_header.bl_size < sizeof(ctx->metadata)) {
|
||||||
|
fprintf(stderr, "PK11 seems corrupt!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->mariko_bl = calloc(1, ctx->mariko_oem_header.bl_size);
|
||||||
|
if (fread(ctx->mariko_bl, 1, ctx->mariko_oem_header.bl_size, ctx->file) != ctx->mariko_oem_header.bl_size) {
|
||||||
|
fprintf(stderr, "Failed to read Mariko PK11!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&ctx->metadata, ctx->mariko_bl, sizeof(ctx->metadata));
|
||||||
|
|
||||||
|
uint32_t enc_size = ctx->mariko_oem_header.bl_size - sizeof(ctx->metadata);
|
||||||
|
if (enc_size > 0) {
|
||||||
|
aes_ctx_t *crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.mariko_bek, 0x10, AES_MODE_CBC);
|
||||||
|
|
||||||
|
aes_setiv(crypt_ctx, ctx->mariko_bl + 0x10, 0x10);
|
||||||
|
aes_decrypt(crypt_ctx, ctx->mariko_bl + 0x20, ctx->mariko_bl + 0x20, enc_size);
|
||||||
|
|
||||||
|
free_aes_ctx(crypt_ctx);
|
||||||
|
|
||||||
|
if (memcmp(&ctx->metadata, ctx->mariko_bl + 0x20, sizeof(ctx->metadata)) != 0) {
|
||||||
|
fprintf(stderr, "Failed to decrypt Mariko PK11! Is correct key present?\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx->is_pilot = 0;
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (fread(&ctx->metadata, 1, sizeof(ctx->metadata), ctx->file) != sizeof(ctx->metadata)) {
|
||||||
|
fprintf(stderr, "Failed to read PK11 Metadata!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->pk11 = malloc(ctx->stage1.pk11_size);
|
ctx->is_modern = !pk11_is_legacy(ctx);
|
||||||
|
|
||||||
|
if (ctx->is_mariko) {
|
||||||
|
if (ctx->is_modern) {
|
||||||
|
memcpy(&ctx->stage1.modern, ctx->mariko_bl + 0x20, sizeof(ctx->stage1.modern));
|
||||||
|
ctx->pk11_size = ctx->stage1.modern.pk11_size;
|
||||||
|
} else {
|
||||||
|
memcpy(&ctx->stage1.legacy, ctx->mariko_bl + 0x20, sizeof(ctx->stage1.legacy));
|
||||||
|
ctx->pk11_size = ctx->stage1.legacy.pk11_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ctx->is_modern) {
|
||||||
|
if (fread(&ctx->stage1.modern, 1, sizeof(ctx->stage1.modern), ctx->file) != sizeof(ctx->stage1.modern)) {
|
||||||
|
fprintf(stderr, "Failed to read PK11 Stage1!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
ctx->pk11_size = ctx->stage1.modern.pk11_size;
|
||||||
|
} else {
|
||||||
|
if (fread(&ctx->stage1.legacy, 1, sizeof(ctx->stage1.legacy), ctx->file) != sizeof(ctx->stage1.legacy)) {
|
||||||
|
fprintf(stderr, "Failed to read PK11 Stage1!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
ctx->pk11_size = ctx->stage1.legacy.pk11_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pk11 = malloc(ctx->pk11_size);
|
||||||
if (ctx->pk11 == NULL) {
|
if (ctx->pk11 == NULL) {
|
||||||
fprintf(stderr, "Failed to allocate PK11!\n");
|
fprintf(stderr, "Failed to allocate PK11!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(ctx->pk11, 1, ctx->stage1.pk11_size, ctx->file) != ctx->stage1.pk11_size) {
|
if (ctx->is_mariko) {
|
||||||
fprintf(stderr, "Failed to read PK11!\n");
|
if (ctx->is_modern) {
|
||||||
exit(EXIT_FAILURE);
|
memcpy(ctx->pk11, ctx->mariko_bl + 0x20 + sizeof(ctx->stage1.modern), ctx->pk11_size);
|
||||||
}
|
} else {
|
||||||
|
memcpy(ctx->pk11, ctx->mariko_bl + 0x20 + sizeof(ctx->stage1.legacy), ctx->pk11_size);
|
||||||
aes_ctx_t *crypt_ctx = NULL;
|
}
|
||||||
pk11_t dec_header;
|
|
||||||
for (unsigned int i = 0; i < 0x20; i++) {
|
} else {
|
||||||
ctx->key_rev = i;
|
if (fread(ctx->pk11, 1, ctx->pk11_size, ctx->file) != ctx->pk11_size) {
|
||||||
crypt_ctx = new_aes_ctx(&ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CTR);
|
fprintf(stderr, "Failed to read PK11!\n");
|
||||||
aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10);
|
exit(EXIT_FAILURE);
|
||||||
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
|
}
|
||||||
if (dec_header.magic == MAGIC_PK11) {
|
|
||||||
break;
|
if (ctx->is_modern) {
|
||||||
|
if (fread(&ctx->pk11_mac, 1, sizeof(ctx->pk11_mac), ctx->file) != sizeof(ctx->pk11_mac)) {
|
||||||
|
fprintf(stderr, "Failed to read PK11 MAC!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free_aes_ctx(crypt_ctx);
|
|
||||||
crypt_ctx = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crypt_ctx == NULL) {
|
int decrypted = 0;
|
||||||
|
if (ctx->is_mariko) {
|
||||||
|
decrypted = ctx->pk11->magic == MAGIC_PK11;
|
||||||
|
} else {
|
||||||
|
pk11_t dec_header;
|
||||||
|
aes_ctx_t *crypt_ctx = NULL;
|
||||||
|
if (ctx->is_modern) {
|
||||||
|
for (unsigned int i = 6; i < 0x20 && !decrypted; i++) {
|
||||||
|
ctx->key_rev = i;
|
||||||
|
crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CBC);
|
||||||
|
aes_setiv(crypt_ctx, ctx->stage1.modern.iv, 0x10);
|
||||||
|
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
|
||||||
|
if (dec_header.magic == MAGIC_PK11) {
|
||||||
|
aes_setiv(crypt_ctx, ctx->stage1.modern.iv, 0x10);
|
||||||
|
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->pk11_size);
|
||||||
|
decrypted = 1;
|
||||||
|
}
|
||||||
|
free_aes_ctx(crypt_ctx);
|
||||||
|
crypt_ctx = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int i = 0; i < 6 && !decrypted; i++) {
|
||||||
|
ctx->key_rev = i;
|
||||||
|
crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CTR);
|
||||||
|
aes_setiv(crypt_ctx, ctx->stage1.legacy.ctr, 0x10);
|
||||||
|
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
|
||||||
|
if (dec_header.magic == MAGIC_PK11) {
|
||||||
|
aes_setiv(crypt_ctx, ctx->stage1.legacy.ctr, 0x10);
|
||||||
|
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->pk11_size);
|
||||||
|
decrypted = 1;
|
||||||
|
}
|
||||||
|
free_aes_ctx(crypt_ctx);
|
||||||
|
crypt_ctx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decrypted) {
|
||||||
fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n");
|
fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10);
|
|
||||||
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->stage1.pk11_size);
|
|
||||||
|
|
||||||
uint64_t pk11_size = 0x20 + ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size + ctx->pk11->secmon_size;
|
uint64_t pk11_size = 0x20 + pk11_get_warmboot_bin_size(ctx) + pk11_get_nx_bootloader_size(ctx) + pk11_get_secmon_size(ctx);
|
||||||
pk11_size = align64(pk11_size, 0x10);
|
pk11_size = align64(pk11_size, 0x10);
|
||||||
if (pk11_size != ctx->stage1.pk11_size) {
|
if (pk11_size != ctx->pk11_size) {
|
||||||
fprintf(stderr, "PK11 seems corrupt!\n");
|
fprintf(stderr, "PK11 seems corrupt!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -71,13 +188,20 @@ void pk11_process(pk11_ctx_t *ctx) {
|
||||||
|
|
||||||
void pk11_print(pk11_ctx_t *ctx) {
|
void pk11_print(pk11_ctx_t *ctx) {
|
||||||
printf("PK11:\n");
|
printf("PK11:\n");
|
||||||
printf(" Build Date: %s\n", ctx->stage1.build_date);
|
{
|
||||||
memdump(stdout, " Build Hash: ", ctx->stage1.build_hash, 0x10);
|
char build_date[sizeof(ctx->metadata.build_date) + 1] = {0};
|
||||||
|
memcpy(build_date, ctx->metadata.build_date, sizeof(ctx->metadata.build_date));
|
||||||
|
printf(" Build Date: %s\n", build_date);
|
||||||
|
}
|
||||||
|
memdump(stdout, " Package1ldr Hash: ", &ctx->metadata.ldr_hash, sizeof(uint32_t));
|
||||||
|
memdump(stdout, " Secure Monitor Hash: ", &ctx->metadata.sm_hash, sizeof(uint32_t));
|
||||||
|
memdump(stdout, " NX Bootloader Hash: ", &ctx->metadata.bl_hash, sizeof(uint32_t));
|
||||||
|
printf(" Version: %02"PRIx32"\n", ctx->metadata.version);
|
||||||
printf(" Key Revision: %02"PRIx32" (%s)\n", ctx->key_rev, get_key_revision_summary((uint8_t)ctx->key_rev));
|
printf(" Key Revision: %02"PRIx32" (%s)\n", ctx->key_rev, get_key_revision_summary((uint8_t)ctx->key_rev));
|
||||||
printf(" PK11 Size: %08"PRIx32"\n", ctx->stage1.pk11_size);
|
printf(" PK11 Size: %08"PRIx32"\n", ctx->pk11_size);
|
||||||
printf(" Warmboot.bin Size: %08"PRIx32"\n", ctx->pk11->warmboot_size);
|
printf(" Warmboot.bin Size: %08"PRIx32"\n", pk11_get_warmboot_bin_size(ctx));
|
||||||
printf(" NX_Bootloader.bin Size %08"PRIx32"\n", ctx->pk11->nx_bootloader_size);
|
printf(" NX_Bootloader.bin Size %08"PRIx32"\n", pk11_get_nx_bootloader_size(ctx));
|
||||||
printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", ctx->pk11->secmon_size);
|
printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", pk11_get_secmon_size(ctx));
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,27 +219,74 @@ void pk11_save(pk11_ctx_t *ctx) {
|
||||||
|
|
||||||
/* Save Decrypted.bin */
|
/* Save Decrypted.bin */
|
||||||
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
|
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
|
||||||
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->stage1.pk11_size);
|
if (ctx->is_mariko) {
|
||||||
if (decrypted_bin == NULL) {
|
char *decrypted_bin = malloc(sizeof(ctx->mariko_oem_header) + ctx->mariko_oem_header.bl_size);
|
||||||
fprintf(stderr, "Failed to allocate buffer!\n");
|
if (decrypted_bin == NULL) {
|
||||||
exit(EXIT_FAILURE);
|
fprintf(stderr, "Failed to allocate buffer!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
memcpy(decrypted_bin, &ctx->mariko_oem_header, sizeof(ctx->mariko_oem_header));
|
||||||
|
memcpy(decrypted_bin + sizeof(ctx->mariko_oem_header), ctx->mariko_bl, ctx->mariko_oem_header.bl_size);
|
||||||
|
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->pk11_size, dirpath, "Decrypted.bin");
|
||||||
|
free(decrypted_bin);
|
||||||
|
} else {
|
||||||
|
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->pk11_size);
|
||||||
|
if (decrypted_bin == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate buffer!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
memcpy(decrypted_bin, &ctx->stage1, sizeof(ctx->stage1));
|
||||||
|
memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->pk11_size);
|
||||||
|
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->pk11_size, dirpath, "Decrypted.bin");
|
||||||
|
free(decrypted_bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save Mariko_OEM_Bootloader.bin */
|
||||||
|
if (ctx->is_mariko) {
|
||||||
|
printf("Saving Mariko_OEM_Bootloader.bin to %s/Mariko_OEM_Bootloader.bin...\n", dirpath->char_path);
|
||||||
|
save_buffer_to_directory_file(ctx->mariko_bl, ctx->mariko_oem_header.bl_size, dirpath, "Mariko_OEM_Bootloader.bin");
|
||||||
}
|
}
|
||||||
memcpy(decrypted_bin, &ctx->stage1, sizeof(ctx->stage1));
|
|
||||||
memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->stage1.pk11_size);
|
|
||||||
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->stage1.pk11_size, dirpath, "Decrypted.bin");
|
|
||||||
free(decrypted_bin);
|
|
||||||
|
|
||||||
/* Save Warmboot.bin */
|
/* Save Warmboot.bin */
|
||||||
printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path);
|
printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path);
|
||||||
save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), ctx->pk11->warmboot_size, dirpath, "Warmboot.bin");
|
save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), pk11_get_warmboot_bin_size(ctx), dirpath, "Warmboot.bin");
|
||||||
|
|
||||||
|
if (ctx->is_mariko) {
|
||||||
|
|
||||||
|
uint32_t wb_size = pk11_get_warmboot_bin_size(ctx);
|
||||||
|
|
||||||
|
unsigned char *wb_dec = malloc(wb_size);
|
||||||
|
if (wb_dec == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate mariko warmboot binary!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(wb_dec, pk11_get_warmboot_bin(ctx), wb_size);
|
||||||
|
|
||||||
|
if (wb_size > 0x330) {
|
||||||
|
aes_ctx_t *crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.mariko_bek, 0x10, AES_MODE_CBC);
|
||||||
|
|
||||||
|
unsigned char iv[0x10] = {0};
|
||||||
|
aes_setiv(crypt_ctx, iv, 0x10);
|
||||||
|
|
||||||
|
aes_decrypt(crypt_ctx, wb_dec + 0x330, wb_dec + 0x330, wb_size - 0x330);
|
||||||
|
|
||||||
|
free_aes_ctx(crypt_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Saving Warmboot_Decrypted.bin to %s/Warmboot_Decrypted.bin...\n", dirpath->char_path);
|
||||||
|
save_buffer_to_directory_file(wb_dec, wb_size, dirpath, "Warmboot_Decrypted.bin");
|
||||||
|
|
||||||
|
free(wb_dec);
|
||||||
|
}
|
||||||
|
|
||||||
/* Save NX_Bootloader.bin */
|
/* Save NX_Bootloader.bin */
|
||||||
printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path);
|
printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path);
|
||||||
save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), ctx->pk11->nx_bootloader_size, dirpath, "NX_Bootloader.bin");
|
save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), pk11_get_nx_bootloader_size(ctx), dirpath, "NX_Bootloader.bin");
|
||||||
|
|
||||||
/* Save Secure_Monitor.bin */
|
/* Save Secure_Monitor.bin */
|
||||||
printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path);
|
printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path);
|
||||||
save_buffer_to_directory_file(pk11_get_secmon(ctx), ctx->pk11->secmon_size, dirpath, "Secure_Monitor.bin");
|
save_buffer_to_directory_file(pk11_get_secmon(ctx), pk11_get_secmon_size(ctx), dirpath, "Secure_Monitor.bin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
packages.h
141
packages.h
|
@ -11,46 +11,161 @@
|
||||||
#define MAGIC_KRNLLDR_STRCT_END 0xD51C403E
|
#define MAGIC_KRNLLDR_STRCT_END 0xD51C403E
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char build_hash[0x10];
|
unsigned char aes_mac[0x10];
|
||||||
unsigned char build_date[0x10];
|
unsigned char rsa_sig[0x100];
|
||||||
|
unsigned char salt[0x20];
|
||||||
|
unsigned char hash[0x20];
|
||||||
|
uint32_t bl_version;
|
||||||
|
uint32_t bl_size;
|
||||||
|
uint32_t bl_load_addr;
|
||||||
|
uint32_t bl_entrypoint;
|
||||||
|
unsigned char _0x160[0x10];
|
||||||
|
} pk11_mariko_oem_header_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t ldr_hash;
|
||||||
|
uint32_t sm_hash;
|
||||||
|
uint32_t bl_hash;
|
||||||
|
uint32_t _0xC;
|
||||||
|
char build_date[0xE];
|
||||||
|
unsigned char _0x1E;
|
||||||
|
unsigned char version;
|
||||||
|
} pk11_metadata_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
unsigned char stage1[0x3FC0];
|
unsigned char stage1[0x3FC0];
|
||||||
uint32_t pk11_size;
|
uint32_t pk11_size;
|
||||||
unsigned char _0x3FE4[0xC];
|
unsigned char _0x3FC4[0xC];
|
||||||
unsigned char ctr[0x10];
|
unsigned char ctr[0x10];
|
||||||
|
} pk11_legacy_stage1_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char stage1[0x6FC0];
|
||||||
|
uint32_t pk11_size;
|
||||||
|
unsigned char _0x6FC4[0xC];
|
||||||
|
unsigned char iv[0x10];
|
||||||
|
} pk11_modern_stage1_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
pk11_legacy_stage1_t legacy;
|
||||||
|
pk11_modern_stage1_t modern;
|
||||||
} pk11_stage1_t;
|
} pk11_stage1_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t warmboot_size;
|
uint32_t wb_size;
|
||||||
uint32_t _0x8;
|
uint32_t wb_ep;
|
||||||
uint32_t _0xC;
|
uint32_t _0xC;
|
||||||
uint32_t nx_bootloader_size;
|
uint32_t bl_size;
|
||||||
uint32_t _0x14;
|
uint32_t bl_ep;
|
||||||
uint32_t secmon_size;
|
uint32_t sm_size;
|
||||||
uint32_t _0x1C;
|
uint32_t sm_ep;
|
||||||
unsigned char data[];
|
unsigned char data[];
|
||||||
} pk11_t;
|
} pk11_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
hactool_ctx_t *tool_ctx;
|
hactool_ctx_t *tool_ctx;
|
||||||
int is_pilot;
|
int is_modern;
|
||||||
|
int is_mariko;
|
||||||
unsigned int key_rev;
|
unsigned int key_rev;
|
||||||
|
pk11_mariko_oem_header_t mariko_oem_header;
|
||||||
|
pk11_metadata_t metadata;
|
||||||
pk11_stage1_t stage1;
|
pk11_stage1_t stage1;
|
||||||
|
uint32_t pk11_size;
|
||||||
|
uint8_t *mariko_bl;
|
||||||
pk11_t *pk11;
|
pk11_t *pk11;
|
||||||
|
unsigned char pk11_mac[0x10];
|
||||||
} pk11_ctx_t;
|
} pk11_ctx_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PK11_SECTION_BL,
|
||||||
|
PK11_SECTION_SM,
|
||||||
|
PK11_SECTION_WB,
|
||||||
|
} pk11_section_id_t;
|
||||||
|
|
||||||
|
static inline int pk11_get_section_idx(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
|
||||||
|
if (ctx->metadata.version >= 0x07) {
|
||||||
|
switch (section_id) {
|
||||||
|
case PK11_SECTION_BL: return 0;
|
||||||
|
case PK11_SECTION_SM: return 1;
|
||||||
|
case PK11_SECTION_WB: return 2;
|
||||||
|
}
|
||||||
|
} else if (ctx->metadata.version >= 0x02) {
|
||||||
|
switch (section_id) {
|
||||||
|
case PK11_SECTION_BL: return 1;
|
||||||
|
case PK11_SECTION_SM: return 2;
|
||||||
|
case PK11_SECTION_WB: return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (section_id) {
|
||||||
|
case PK11_SECTION_BL: return 1;
|
||||||
|
case PK11_SECTION_SM: return 0;
|
||||||
|
case PK11_SECTION_WB: return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline pk11_section_id_t pk11_get_section_id(pk11_ctx_t *ctx, int id) {
|
||||||
|
if (pk11_get_section_idx(ctx, PK11_SECTION_BL) == id) {
|
||||||
|
return PK11_SECTION_BL;
|
||||||
|
} else if (pk11_get_section_idx(ctx, PK11_SECTION_SM) == id) {
|
||||||
|
return PK11_SECTION_SM;
|
||||||
|
} else {
|
||||||
|
return PK11_SECTION_WB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t pk11_get_section_size(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
|
||||||
|
switch (section_id) {
|
||||||
|
case PK11_SECTION_BL: return ctx->pk11->bl_size;
|
||||||
|
case PK11_SECTION_SM: return ctx->pk11->sm_size;
|
||||||
|
case PK11_SECTION_WB: return ctx->pk11->wb_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t pk11_get_section_ofs(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
|
||||||
|
switch (pk11_get_section_idx(ctx, section_id)) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return pk11_get_section_size(ctx, pk11_get_section_id(ctx, 0));
|
||||||
|
case 2:
|
||||||
|
return pk11_get_section_size(ctx, pk11_get_section_id(ctx, 0)) + pk11_get_section_size(ctx, pk11_get_section_id(ctx, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned char *pk11_get_section(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
|
||||||
|
return &ctx->pk11->data[pk11_get_section_ofs(ctx, section_id)];
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned char *pk11_get_warmboot_bin(pk11_ctx_t *ctx) {
|
static inline unsigned char *pk11_get_warmboot_bin(pk11_ctx_t *ctx) {
|
||||||
return ctx->is_pilot ? &ctx->pk11->data[ctx->pk11->secmon_size + ctx->pk11->nx_bootloader_size] : &ctx->pk11->data[0];
|
return pk11_get_section(ctx, PK11_SECTION_WB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned char *pk11_get_secmon(pk11_ctx_t *ctx) {
|
static inline unsigned char *pk11_get_secmon(pk11_ctx_t *ctx) {
|
||||||
return ctx->is_pilot ? &ctx->pk11->data[0] : &ctx->pk11->data[ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size];
|
return pk11_get_section(ctx, PK11_SECTION_SM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned char *pk11_get_nx_bootloader(pk11_ctx_t *ctx) {
|
static inline unsigned char *pk11_get_nx_bootloader(pk11_ctx_t *ctx) {
|
||||||
return ctx->is_pilot ? &ctx->pk11->data[ctx->pk11->secmon_size] : &ctx->pk11->data[ctx->pk11->warmboot_size];
|
return pk11_get_section(ctx, PK11_SECTION_BL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pk11_get_warmboot_bin_size(pk11_ctx_t *ctx) {
|
||||||
|
return pk11_get_section_size(ctx, PK11_SECTION_WB);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pk11_get_secmon_size(pk11_ctx_t *ctx) {
|
||||||
|
return pk11_get_section_size(ctx, PK11_SECTION_SM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pk11_get_nx_bootloader_size(pk11_ctx_t *ctx) {
|
||||||
|
return pk11_get_section_size(ctx, PK11_SECTION_BL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
7
pki.c
7
pki.c
|
@ -65,7 +65,6 @@ const unsigned char *pki_get_beta_nca0_label_hash(void) {
|
||||||
return beta_nca0_label_hash;
|
return beta_nca0_label_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const nca_keyset_t nca_keys_retail = {
|
static const nca_keyset_t nca_keys_retail = {
|
||||||
.nca_hdr_fixed_key_moduli = { /* Fixed RSA key used to validate NCA signature 0. */
|
.nca_hdr_fixed_key_moduli = { /* Fixed RSA key used to validate NCA signature 0. */
|
||||||
{
|
{
|
||||||
|
@ -509,6 +508,12 @@ void pki_print_keys(nca_keyset_t *keyset) {
|
||||||
PRINT_KEY_WITH_NAME_IDX(keyset->master_kek_sources[i], master_kek_source, i);
|
PRINT_KEY_WITH_NAME_IDX(keyset->master_kek_sources[i], master_kek_source, i);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
PRINT_KEY_WITH_NAME(keyset->mariko_kek, mariko_kek);
|
||||||
|
PRINT_KEY_WITH_NAME(keyset->mariko_bek, mariko_bek);
|
||||||
|
for (unsigned int i = 0x0; i < 0xC; i++) {
|
||||||
|
PRINT_KEY_WITH_NAME_IDX(keyset->mariko_aes_class_keys[i], mariko_aes_class_key, i);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
for (unsigned int i = 0x0; i < 0x20; i++) {
|
for (unsigned int i = 0x0; i < 0x20; i++) {
|
||||||
PRINT_KEY_WITH_NAME_IDX(keyset->master_keks[i], master_kek, i);
|
PRINT_KEY_WITH_NAME_IDX(keyset->master_keks[i], master_kek, i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@ typedef struct {
|
||||||
unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
|
unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
|
||||||
unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
|
unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
|
||||||
unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
|
unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
|
||||||
|
unsigned char mariko_aes_class_keys[0xC][0x10]; /* AES Class Keys set by mariko bootrom. */
|
||||||
|
unsigned char mariko_kek[0x10]; /* Key Encryption Key for mariko. */
|
||||||
|
unsigned char mariko_bek[0x10]; /* Boot Encryption Key for mariko. */
|
||||||
unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */
|
unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */
|
||||||
unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */
|
unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */
|
||||||
unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */
|
unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */
|
||||||
|
|
Loading…
Reference in a new issue