mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-25 07:09:48 -06:00
IOS: Reuse more code for crypto operations
This changes some parts of IOS (actually just ES) to reuse more crypto code from IOSC or Common::AES. TicketReader still returns the title key directly as opposed to having ES use IOSC directly to avoid duplicating the title key IV stuff. Side effects: * A nasty unbounded array access bug is now fixed. * ES_Decrypt/ES_Encrypt now returns sane results for keys other than the SD key. * Titles with a Korean ticket can now be decrypted properly. And in the future, we can look into implementing ioctlv 0x3c and 0x3d now that we have the proper "infra" for IOSC calls.
This commit is contained in:
@ -49,9 +49,6 @@ public:
|
|||||||
static void LoadWAD(const std::string& _rContentFile);
|
static void LoadWAD(const std::string& _rContentFile);
|
||||||
bool LaunchTitle(u64 title_id, bool skip_reload = false);
|
bool LaunchTitle(u64 title_id, bool skip_reload = false);
|
||||||
|
|
||||||
// Internal implementation of the ES_DECRYPT ioctlv.
|
|
||||||
static void DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output);
|
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
ReturnCode Open(const OpenRequest& request) override;
|
ReturnCode Open(const OpenRequest& request) override;
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Crypto/AES.h"
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
#include "Core/ec_wii.h"
|
#include "Core/IOS/Device.h"
|
||||||
|
#include "Core/IOS/IOSC.h"
|
||||||
|
|
||||||
namespace IOS
|
namespace IOS
|
||||||
{
|
{
|
||||||
@ -313,15 +313,18 @@ u64 TicketReader::GetTitleId() const
|
|||||||
|
|
||||||
std::vector<u8> TicketReader::GetTitleKey() const
|
std::vector<u8> TicketReader::GetTitleKey() const
|
||||||
{
|
{
|
||||||
const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4,
|
|
||||||
0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7};
|
|
||||||
u8 iv[16] = {};
|
u8 iv[16] = {};
|
||||||
std::copy_n(&m_bytes[GetOffset() + offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv);
|
std::copy_n(&m_bytes[GetOffset() + offsetof(Ticket, title_id)], sizeof(Ticket::title_id), iv);
|
||||||
return Common::AES::Decrypt(common_key, iv, &m_bytes[GetOffset() + offsetof(Ticket, title_key)],
|
auto common_key_handle = m_bytes.at(GetOffset() + offsetof(Ticket, common_key_index)) == 0 ?
|
||||||
16);
|
HLE::IOSC::HANDLE_COMMON_KEY :
|
||||||
}
|
HLE::IOSC::HANDLE_NEW_COMMON_KEY;
|
||||||
|
|
||||||
constexpr s32 IOSC_OK = 0;
|
std::vector<u8> key(16);
|
||||||
|
HLE::IOSC iosc;
|
||||||
|
iosc.Decrypt(common_key_handle, iv, &m_bytes[GetOffset() + offsetof(Ticket, title_key)], 16,
|
||||||
|
key.data(), HLE::PID_ES);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
s32 TicketReader::Unpersonalise()
|
s32 TicketReader::Unpersonalise()
|
||||||
{
|
{
|
||||||
@ -329,24 +332,38 @@ s32 TicketReader::Unpersonalise()
|
|||||||
|
|
||||||
// IOS uses IOSC to compute an AES key from the peer public key and the device's private ECC key,
|
// IOS uses IOSC to compute an AES key from the peer public key and the device's private ECC key,
|
||||||
// which is used the decrypt the title key. The IV is the ticket ID (8 bytes), zero extended.
|
// which is used the decrypt the title key. The IV is the ticket ID (8 bytes), zero extended.
|
||||||
|
using namespace HLE;
|
||||||
|
IOSC iosc;
|
||||||
|
IOSC::Handle public_handle;
|
||||||
|
s32 ret = iosc.CreateObject(&public_handle, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES);
|
||||||
|
if (ret != IPC_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
const auto public_key_iter = ticket_begin + offsetof(Ticket, server_public_key);
|
const auto public_key_iter = ticket_begin + offsetof(Ticket, server_public_key);
|
||||||
EcWii::ECCKey public_key;
|
ret = iosc.ImportPublicKey(public_handle, &*public_key_iter, PID_ES);
|
||||||
std::copy_n(public_key_iter, sizeof(Ticket::server_public_key), public_key.begin());
|
if (ret != IPC_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
const EcWii& ec = EcWii::GetInstance();
|
IOSC::Handle key_handle;
|
||||||
const std::array<u8, 16> shared_secret = ec.GetSharedSecret(public_key);
|
ret = iosc.CreateObject(&key_handle, IOSC::TYPE_SECRET_KEY, IOSC::SUBTYPE_AES128, PID_ES);
|
||||||
|
if (ret != IPC_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = iosc.ComputeSharedKey(key_handle, IOSC::HANDLE_CONSOLE_KEY, public_handle, PID_ES);
|
||||||
|
if (ret != IPC_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
std::array<u8, 16> iv{};
|
std::array<u8, 16> iv{};
|
||||||
std::copy_n(ticket_begin + offsetof(Ticket, ticket_id), sizeof(Ticket::ticket_id), iv.begin());
|
std::copy_n(ticket_begin + offsetof(Ticket, ticket_id), sizeof(Ticket::ticket_id), iv.begin());
|
||||||
|
|
||||||
const std::vector<u8> key =
|
std::array<u8, 16> key{};
|
||||||
Common::AES::Decrypt(shared_secret.data(), iv.data(),
|
ret = iosc.Decrypt(key_handle, iv.data(), &*ticket_begin + offsetof(Ticket, title_key),
|
||||||
&*ticket_begin + offsetof(Ticket, title_key), sizeof(Ticket::title_key));
|
sizeof(Ticket::title_key), key.data(), PID_ES);
|
||||||
|
|
||||||
// Finally, IOS copies the decrypted title key back to the ticket buffer.
|
// Finally, IOS copies the decrypted title key back to the ticket buffer.
|
||||||
std::copy(key.cbegin(), key.cend(), ticket_begin + offsetof(Ticket, title_key));
|
if (ret == IPC_SUCCESS)
|
||||||
return IOSC_OK;
|
std::copy(key.cbegin(), key.cend(), ticket_begin + offsetof(Ticket, title_key));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SharedContentMap::Entry
|
struct SharedContentMap::Entry
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/aes.h>
|
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
@ -21,37 +19,6 @@ namespace HLE
|
|||||||
{
|
{
|
||||||
namespace Device
|
namespace Device
|
||||||
{
|
{
|
||||||
constexpr u8 s_key_sd[0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08,
|
|
||||||
0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
|
|
||||||
constexpr u8 s_key_ecc[0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
|
|
||||||
constexpr u8 s_key_empty[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
// default key table
|
|
||||||
constexpr const u8* s_key_table[11] = {
|
|
||||||
s_key_ecc, // ECC Private Key
|
|
||||||
s_key_empty, // Console ID
|
|
||||||
s_key_empty, // NAND AES Key
|
|
||||||
s_key_empty, // NAND HMAC
|
|
||||||
s_key_empty, // Common Key
|
|
||||||
s_key_empty, // PRNG seed
|
|
||||||
s_key_sd, // SD Key
|
|
||||||
s_key_empty, // Unknown
|
|
||||||
s_key_empty, // Unknown
|
|
||||||
s_key_empty, // Unknown
|
|
||||||
s_key_empty, // Unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
void ES::DecryptContent(u32 key_index, u8* iv, u8* input, u32 size, u8* new_iv, u8* output)
|
|
||||||
{
|
|
||||||
mbedtls_aes_context AES_ctx;
|
|
||||||
mbedtls_aes_setkey_dec(&AES_ctx, s_key_table[key_index], 128);
|
|
||||||
memcpy(new_iv, iv, 16);
|
|
||||||
mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, new_iv, input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPCCommandResult ES::GetConsoleID(const IOCtlVRequest& request)
|
IPCCommandResult ES::GetConsoleID(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(0, 1))
|
if (!request.HasNumberOfValidVectors(0, 1))
|
||||||
@ -69,20 +36,15 @@ IPCCommandResult ES::Encrypt(u32 uid, const IOCtlVRequest& request)
|
|||||||
return GetDefaultReply(ES_EINVAL);
|
return GetDefaultReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* IV = Memory::GetPointer(request.in_vectors[1].address);
|
|
||||||
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
||||||
u32 size = request.in_vectors[2].size;
|
u32 size = request.in_vectors[2].size;
|
||||||
u8* newIV = Memory::GetPointer(request.io_vectors[0].address);
|
u8* iv = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
u8* destination = Memory::GetPointer(request.io_vectors[1].address);
|
u8* destination = Memory::GetPointer(request.io_vectors[1].address);
|
||||||
|
|
||||||
mbedtls_aes_context AES_ctx;
|
// TODO: Check whether the active title is allowed to encrypt.
|
||||||
mbedtls_aes_setkey_enc(&AES_ctx, s_key_table[keyIndex], 128);
|
|
||||||
memcpy(newIV, IV, 16);
|
|
||||||
mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_ENCRYPT, size, newIV, source, destination);
|
|
||||||
|
|
||||||
_dbg_assert_msg_(IOS_ES, keyIndex == 6,
|
const ReturnCode ret = m_ios.GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES);
|
||||||
"IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap");
|
return GetDefaultReply(ret);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ES::Decrypt(u32 uid, const IOCtlVRequest& request)
|
IPCCommandResult ES::Decrypt(u32 uid, const IOCtlVRequest& request)
|
||||||
@ -91,17 +53,15 @@ IPCCommandResult ES::Decrypt(u32 uid, const IOCtlVRequest& request)
|
|||||||
return GetDefaultReply(ES_EINVAL);
|
return GetDefaultReply(ES_EINVAL);
|
||||||
|
|
||||||
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
u32 keyIndex = Memory::Read_U32(request.in_vectors[0].address);
|
||||||
u8* IV = Memory::GetPointer(request.in_vectors[1].address);
|
|
||||||
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
u8* source = Memory::GetPointer(request.in_vectors[2].address);
|
||||||
u32 size = request.in_vectors[2].size;
|
u32 size = request.in_vectors[2].size;
|
||||||
u8* newIV = Memory::GetPointer(request.io_vectors[0].address);
|
u8* iv = Memory::GetPointer(request.io_vectors[0].address);
|
||||||
u8* destination = Memory::GetPointer(request.io_vectors[1].address);
|
u8* destination = Memory::GetPointer(request.io_vectors[1].address);
|
||||||
|
|
||||||
DecryptContent(keyIndex, IV, source, size, newIV, destination);
|
// TODO: Check whether the active title is allowed to decrypt.
|
||||||
|
|
||||||
_dbg_assert_msg_(IOS_ES, keyIndex == 6,
|
const ReturnCode ret = m_ios.GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES);
|
||||||
"IOCTL_ES_DECRYPT: Key type is not SD, data will be crap");
|
return GetDefaultReply(ret);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request)
|
IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request)
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/aes.h>
|
|
||||||
#include <mbedtls/sha1.h>
|
#include <mbedtls/sha1.h>
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
|
#include "Common/Crypto/AES.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
@ -207,9 +207,6 @@ IPCCommandResult ES::AddContentFinish(Context& context, const IOCtlVRequest& req
|
|||||||
return GetDefaultReply(ES_NO_TICKET);
|
return GetDefaultReply(ES_NO_TICKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
mbedtls_aes_context aes_ctx;
|
|
||||||
mbedtls_aes_setkey_dec(&aes_ctx, ticket.GetTitleKey().data(), 128);
|
|
||||||
|
|
||||||
// The IV for title content decryption is the lower two bytes of the
|
// The IV for title content decryption is the lower two bytes of the
|
||||||
// content index, zero extended.
|
// content index, zero extended.
|
||||||
IOS::ES::Content content_info;
|
IOS::ES::Content content_info;
|
||||||
@ -220,9 +217,9 @@ IPCCommandResult ES::AddContentFinish(Context& context, const IOCtlVRequest& req
|
|||||||
u8 iv[16] = {0};
|
u8 iv[16] = {0};
|
||||||
iv[0] = (content_info.index >> 8) & 0xFF;
|
iv[0] = (content_info.index >> 8) & 0xFF;
|
||||||
iv[1] = content_info.index & 0xFF;
|
iv[1] = content_info.index & 0xFF;
|
||||||
std::vector<u8> decrypted_data(context.title_import.content_buffer.size());
|
std::vector<u8> decrypted_data = Common::AES::Decrypt(ticket.GetTitleKey().data(), iv,
|
||||||
mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, context.title_import.content_buffer.size(),
|
context.title_import.content_buffer.data(),
|
||||||
iv, context.title_import.content_buffer.data(), decrypted_data.data());
|
context.title_import.content_buffer.size());
|
||||||
if (!CheckIfContentHashMatches(decrypted_data, content_info))
|
if (!CheckIfContentHashMatches(decrypted_data, content_info))
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_ES, "AddContentFinish: Hash for content %08x doesn't match", content_info.id);
|
ERROR_LOG(IOS_ES, "AddContentFinish: Hash for content %08x doesn't match", content_info.id);
|
||||||
@ -480,18 +477,10 @@ IPCCommandResult ES::ExportContentData(Context& context, const IOCtlVRequest& re
|
|||||||
// IOS aligns the buffer to 32 bytes. Since we also need to align it to 16 bytes,
|
// IOS aligns the buffer to 32 bytes. Since we also need to align it to 16 bytes,
|
||||||
// let's just follow IOS here.
|
// let's just follow IOS here.
|
||||||
buffer.resize(Common::AlignUp(buffer.size(), 32));
|
buffer.resize(Common::AlignUp(buffer.size(), 32));
|
||||||
std::vector<u8> output(buffer.size());
|
|
||||||
|
|
||||||
mbedtls_aes_context aes_ctx;
|
const std::vector<u8> output =
|
||||||
mbedtls_aes_setkey_enc(&aes_ctx, context.title_export.title_key.data(), 128);
|
Common::AES::Encrypt(context.title_export.title_key.data(), iterator->second.iv.data(),
|
||||||
const int ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, buffer.size(),
|
buffer.data(), buffer.size());
|
||||||
iterator->second.iv.data(), buffer.data(), output.data());
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
|
||||||
// XXX: proper error code when IOSC_Encrypt fails.
|
|
||||||
ERROR_LOG(IOS_ES, "ExportContentData: Failed to encrypt content.");
|
|
||||||
return GetDefaultReply(ES_EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Memory::CopyToEmu(request.io_vectors[0].address, output.data(), output.size());
|
Memory::CopyToEmu(request.io_vectors[0].address, output.data(), output.size());
|
||||||
metadata.m_position += length;
|
metadata.m_position += length;
|
||||||
|
@ -546,6 +546,8 @@ void Kernel::DoState(PointerWrap& p)
|
|||||||
p.Do(m_ppc_uid);
|
p.Do(m_ppc_uid);
|
||||||
p.Do(m_ppc_gid);
|
p.Do(m_ppc_gid);
|
||||||
|
|
||||||
|
m_iosc.DoState(p);
|
||||||
|
|
||||||
if (m_title_id == MIOS_TITLE_ID)
|
if (m_title_id == MIOS_TITLE_ID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -615,6 +617,11 @@ void Kernel::DoState(PointerWrap& p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOSC& Kernel::GetIOSC()
|
||||||
|
{
|
||||||
|
return m_iosc;
|
||||||
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", [](u64 userdata, s64) {
|
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", [](u64 userdata, s64) {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
#include "Core/IOS/IOSC.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
@ -108,6 +109,8 @@ public:
|
|||||||
bool BootIOS(u64 ios_title_id);
|
bool BootIOS(u64 ios_title_id);
|
||||||
u32 GetVersion() const;
|
u32 GetVersion() const;
|
||||||
|
|
||||||
|
IOSC& GetIOSC();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ExecuteIPCCommand(u32 address);
|
void ExecuteIPCCommand(u32 address);
|
||||||
IPCCommandResult HandleIPCCommand(const Request& request);
|
IPCCommandResult HandleIPCCommand(const Request& request);
|
||||||
@ -133,6 +136,8 @@ private:
|
|||||||
IPCMsgQueue m_reply_queue; // arm -> ppc
|
IPCMsgQueue m_reply_queue; // arm -> ppc
|
||||||
IPCMsgQueue m_ack_queue; // arm -> ppc
|
IPCMsgQueue m_ack_queue; // arm -> ppc
|
||||||
u64 m_last_reply_time = 0;
|
u64 m_last_reply_time = 0;
|
||||||
|
|
||||||
|
IOSC m_iosc;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used for controlling and accessing an IOS instance that is tied to emulation.
|
// Used for controlling and accessing an IOS instance that is tied to emulation.
|
||||||
|
@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
|||||||
static std::thread g_save_thread;
|
static std::thread g_save_thread;
|
||||||
|
|
||||||
// Don't forget to increase this after doing changes on the savestate system
|
// Don't forget to increase this after doing changes on the savestate system
|
||||||
static const u32 STATE_VERSION = 83; // Last changed in PR 5340
|
static const u32 STATE_VERSION = 84; // Last changed in PR 5354
|
||||||
|
|
||||||
// Maps savestate versions to Dolphin versions.
|
// Maps savestate versions to Dolphin versions.
|
||||||
// Versions after 42 don't need to be added to this list,
|
// Versions after 42 don't need to be added to this list,
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "Core/ec_wii.h"
|
#include "Core/ec_wii.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
@ -180,19 +179,6 @@ const u8* EcWii::GetNGSig() const
|
|||||||
return BootMiiKeysBin.ng_sig;
|
return BootMiiKeysBin.ng_sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<u8, 16> EcWii::GetSharedSecret(const EcWii::ECCKey& peer_public_key) const
|
|
||||||
{
|
|
||||||
EcWii::ECCKey shared_secret;
|
|
||||||
point_mul(shared_secret.data(), GetNGPriv(), peer_public_key.data());
|
|
||||||
|
|
||||||
std::array<u8, 20> sha1;
|
|
||||||
mbedtls_sha1(shared_secret.data(), shared_secret.size() / 2, sha1.data());
|
|
||||||
|
|
||||||
std::array<u8, 16> aes_key;
|
|
||||||
std::copy_n(sha1.cbegin(), aes_key.size(), aes_key.begin());
|
|
||||||
return aes_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EcWii::InitDefaults()
|
void EcWii::InitDefaults()
|
||||||
{
|
{
|
||||||
memset(&BootMiiKeysBin, 0, sizeof(BootMiiKeysBin));
|
memset(&BootMiiKeysBin, 0, sizeof(BootMiiKeysBin));
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
void MakeNGCert(u8* ng_cert_out, u32 NG_id, u32 NG_key_id, const u8* NG_priv, const u8* NG_sig);
|
void MakeNGCert(u8* ng_cert_out, u32 NG_id, u32 NG_key_id, const u8* NG_priv, const u8* NG_sig);
|
||||||
void MakeAPSigAndCert(u8* sig_out, u8* ap_cert_out, u64 title_id, u8* data, u32 data_size,
|
void MakeAPSigAndCert(u8* sig_out, u8* ap_cert_out, u64 title_id, u8* data, u32 data_size,
|
||||||
const u8* NG_priv, u32 NG_id);
|
const u8* NG_priv, u32 NG_id);
|
||||||
@ -43,9 +41,6 @@ public:
|
|||||||
const u8* GetNGPriv() const;
|
const u8* GetNGPriv() const;
|
||||||
const u8* GetNGSig() const;
|
const u8* GetNGSig() const;
|
||||||
|
|
||||||
using ECCKey = std::array<u8, 0x3c>;
|
|
||||||
std::array<u8, 16> GetSharedSecret(const ECCKey& peer_public_key) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitDefaults();
|
void InitDefaults();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user