Load RSA slot_0 data from bootrom; load and decrypt data from native firm for NCCHSecure2 keyslot

This commit is contained in:
B3n30 2020-02-26 16:43:53 +01:00
parent 5b54a99f96
commit ebeea43fb8
4 changed files with 204 additions and 4 deletions

View file

@ -8,6 +8,7 @@
#include <sstream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/sha.h>
#include <fmt/format.h>
#include "common/common_paths.h"
#include "common/file_util.h"
@ -17,6 +18,7 @@
#include "core/hle/service/fs/archive.h"
#include "core/hw/aes/arithmetic128.h"
#include "core/hw/aes/key.h"
#include "core/hw/rsa/rsa.h"
namespace HW::AES {
@ -26,7 +28,7 @@ namespace {
// normal key dumped from a Wii U solving the equation:
// NormalKey = (((KeyX ROL 2) XOR KeyY) + constant) ROL 87
// On a real 3DS the generation for the normal key is hardware based, and thus the constant can't
// get dumped . generated normal keys are also not accesible on a 3DS. The used formula for
// get dumped. Generated normal keys are also not accesible on a 3DS. The used formula for
// calculating the constant is a software implementation of what the hardware generator does.
constexpr AESKey generator_constant = {{0x1F, 0xF9, 0xE9, 0xAA, 0xC5, 0xFE, 0x04, 0x08, 0x02, 0x45,
0x91, 0xDC, 0x5D, 0x52, 0x76, 0x8A}};
@ -203,13 +205,69 @@ void LoadBootromKeys() {
}
void LoadNativeFirmKeysOld3DS() {
constexpr u64 native_firm_id = 0x00040138'00000002;
FileSys::NCCHArchive archive(native_firm_id, Service::FS::MediaType::NAND);
std::array<char, 8> exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0};
FileSys::Path file_path = FileSys::MakeNCCHFilePath(
FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath);
FileSys::Mode open_mode = {};
open_mode.read_flag.Assign(1);
auto file_result = archive.OpenFile(file_path, open_mode);
if (file_result.Failed())
return;
auto firm = std::move(file_result).Unwrap();
const std::size_t size = firm->GetSize();
if (size != 966656) {
LOG_ERROR(HW_AES, "native firm has wrong size {}", size);
return;
}
auto rsa = RSA::GetSlot(0);
if (!rsa) {
LOG_ERROR(HW_AES, "RSA slot is missing");
return;
}
std::vector<u8> firm_buffer(size);
firm->Read(0, firm_buffer.size(), firm_buffer.data());
firm->Close();
constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 934444;
constexpr std::size_t SLOT_0x25_KEY_X_SECRET_SIZE = 64;
std::vector<u8> secret_data(SLOT_0x25_KEY_X_SECRET_SIZE);
std::memcpy(secret_data.data(), firm_buffer.data() + SLOT_0x25_KEY_X_SECRET_OFFSET,
secret_data.size());
auto asn1 = RSA::CreateASN1Message(secret_data);
auto result = rsa.GetSignature(asn1);
if (result.size() < 0x100) {
std::vector<u8> temp;
temp.resize(0x100 - result.size());
std::fill(temp.begin(), temp.end(), 0);
std::copy(result.begin(), result.end(), std::back_inserter(temp));
result = temp;
} else if (result.size() > 0x100) {
std::vector<u8> temp(result.begin(), result.begin() + 0x100);
result = temp;
}
CryptoPP::SHA256 sha;
std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash_result;
sha.CalculateDigest(hash_result.data(), result.data(), result.size());
AESKey key;
std::memcpy(key.data(), hash_result.data(), sizeof(key));
key_slots.at(0x2F).SetKeyY(key);
std::memcpy(key.data(), hash_result.data() + sizeof(key), sizeof(key));
key_slots.at(0x25).SetKeyX(key);
}
void LoadSaveModeNativeFirmKeysOld3DS() {
// Use the save mode native firm instead of the normal mode since there are only 2 version of it
// and thus we can use fixed offsets
constexpr u64 save_mode_native_firm_id = 0x00040138'00000003;
// TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm
FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND);
std::array<char, 8> exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0};
FileSys::Path file_path = FileSys::MakeNCCHFilePath(
@ -443,11 +501,13 @@ void InitKeys() {
static bool initialized = false;
if (initialized)
return;
initialized = true;
HW::RSA::InitSlots();
LoadBootromKeys();
LoadNativeFirmKeysOld3DS();
LoadSaveModeNativeFirmKeysOld3DS();
LoadNativeFirmKeysNew3DS();
LoadPresetKeys();
initialized = true;
}
void SetKeyX(std::size_t slot_id, const AESKey& key) {