diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index ea3b5de9d4..498b9c7e71 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -49,9 +49,6 @@ public: static void LoadWAD(const std::string& _rContentFile); 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; ReturnCode Open(const OpenRequest& request) override; diff --git a/Source/Core/Core/IOS/ES/Formats.cpp b/Source/Core/Core/IOS/ES/Formats.cpp index 2c91dc923f..ad80683739 100644 --- a/Source/Core/Core/IOS/ES/Formats.cpp +++ b/Source/Core/Core/IOS/ES/Formats.cpp @@ -16,12 +16,12 @@ #include "Common/Assert.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/Crypto/AES.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Swap.h" -#include "Core/ec_wii.h" +#include "Core/IOS/Device.h" +#include "Core/IOS/IOSC.h" namespace IOS { @@ -313,15 +313,18 @@ u64 TicketReader::GetTitleId() const std::vector 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] = {}; 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)], - 16); -} + auto common_key_handle = m_bytes.at(GetOffset() + offsetof(Ticket, common_key_index)) == 0 ? + HLE::IOSC::HANDLE_COMMON_KEY : + HLE::IOSC::HANDLE_NEW_COMMON_KEY; -constexpr s32 IOSC_OK = 0; + std::vector 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() { @@ -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, // 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); - EcWii::ECCKey public_key; - std::copy_n(public_key_iter, sizeof(Ticket::server_public_key), public_key.begin()); + ret = iosc.ImportPublicKey(public_handle, &*public_key_iter, PID_ES); + if (ret != IPC_SUCCESS) + return ret; - const EcWii& ec = EcWii::GetInstance(); - const std::array shared_secret = ec.GetSharedSecret(public_key); + IOSC::Handle key_handle; + 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 iv{}; std::copy_n(ticket_begin + offsetof(Ticket, ticket_id), sizeof(Ticket::ticket_id), iv.begin()); - const std::vector key = - Common::AES::Decrypt(shared_secret.data(), iv.data(), - &*ticket_begin + offsetof(Ticket, title_key), sizeof(Ticket::title_key)); - + std::array key{}; + ret = iosc.Decrypt(key_handle, iv.data(), &*ticket_begin + offsetof(Ticket, title_key), + sizeof(Ticket::title_key), key.data(), PID_ES); // Finally, IOS copies the decrypted title key back to the ticket buffer. - std::copy(key.cbegin(), key.cend(), ticket_begin + offsetof(Ticket, title_key)); - return IOSC_OK; + if (ret == IPC_SUCCESS) + std::copy(key.cbegin(), key.cend(), ticket_begin + offsetof(Ticket, title_key)); + + return ret; } struct SharedContentMap::Entry diff --git a/Source/Core/Core/IOS/ES/Identity.cpp b/Source/Core/Core/IOS/ES/Identity.cpp index 3ae6ba5083..832bd302bc 100644 --- a/Source/Core/Core/IOS/ES/Identity.cpp +++ b/Source/Core/Core/IOS/ES/Identity.cpp @@ -7,8 +7,6 @@ #include #include -#include - #include "Common/Assert.h" #include "Common/Logging/Log.h" #include "Core/HW/Memmap.h" @@ -21,37 +19,6 @@ namespace HLE { 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) { if (!request.HasNumberOfValidVectors(0, 1)) @@ -69,20 +36,15 @@ IPCCommandResult ES::Encrypt(u32 uid, const IOCtlVRequest& request) return GetDefaultReply(ES_EINVAL); 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); 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); - mbedtls_aes_context AES_ctx; - 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); + // TODO: Check whether the active title is allowed to encrypt. - _dbg_assert_msg_(IOS_ES, keyIndex == 6, - "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"); - return GetDefaultReply(IPC_SUCCESS); + const ReturnCode ret = m_ios.GetIOSC().Encrypt(keyIndex, iv, source, size, destination, PID_ES); + return GetDefaultReply(ret); } IPCCommandResult ES::Decrypt(u32 uid, const IOCtlVRequest& request) @@ -91,17 +53,15 @@ IPCCommandResult ES::Decrypt(u32 uid, const IOCtlVRequest& request) return GetDefaultReply(ES_EINVAL); 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); 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); - DecryptContent(keyIndex, IV, source, size, newIV, destination); + // TODO: Check whether the active title is allowed to decrypt. - _dbg_assert_msg_(IOS_ES, keyIndex == 6, - "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"); - return GetDefaultReply(IPC_SUCCESS); + const ReturnCode ret = m_ios.GetIOSC().Decrypt(keyIndex, iv, source, size, destination, PID_ES); + return GetDefaultReply(ret); } IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request) diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 8426b15582..93dfbee95c 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -9,10 +9,10 @@ #include #include -#include #include #include "Common/Align.h" +#include "Common/Crypto/AES.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/NandPaths.h" @@ -207,9 +207,6 @@ IPCCommandResult ES::AddContentFinish(Context& context, const IOCtlVRequest& req 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 // content index, zero extended. IOS::ES::Content content_info; @@ -220,9 +217,9 @@ IPCCommandResult ES::AddContentFinish(Context& context, const IOCtlVRequest& req u8 iv[16] = {0}; iv[0] = (content_info.index >> 8) & 0xFF; iv[1] = content_info.index & 0xFF; - std::vector decrypted_data(context.title_import.content_buffer.size()); - mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, context.title_import.content_buffer.size(), - iv, context.title_import.content_buffer.data(), decrypted_data.data()); + std::vector decrypted_data = Common::AES::Decrypt(ticket.GetTitleKey().data(), iv, + context.title_import.content_buffer.data(), + context.title_import.content_buffer.size()); if (!CheckIfContentHashMatches(decrypted_data, content_info)) { 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, // let's just follow IOS here. buffer.resize(Common::AlignUp(buffer.size(), 32)); - std::vector output(buffer.size()); - mbedtls_aes_context aes_ctx; - mbedtls_aes_setkey_enc(&aes_ctx, context.title_export.title_key.data(), 128); - const int ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, 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); - } + const std::vector output = + Common::AES::Encrypt(context.title_export.title_key.data(), iterator->second.iv.data(), + buffer.data(), buffer.size()); Memory::CopyToEmu(request.io_vectors[0].address, output.data(), output.size()); metadata.m_position += length; diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 5fce675168..8720882bac 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -546,6 +546,8 @@ void Kernel::DoState(PointerWrap& p) p.Do(m_ppc_uid); p.Do(m_ppc_gid); + m_iosc.DoState(p); + if (m_title_id == MIOS_TITLE_ID) return; @@ -615,6 +617,11 @@ void Kernel::DoState(PointerWrap& p) } } +IOSC& Kernel::GetIOSC() +{ + return m_iosc; +} + void Init() { s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", [](u64 userdata, s64) { diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h index d9c6d8e785..ffc469c882 100644 --- a/Source/Core/Core/IOS/IOS.h +++ b/Source/Core/Core/IOS/IOS.h @@ -15,6 +15,7 @@ #include "Common/CommonTypes.h" #include "Core/CoreTiming.h" #include "Core/HW/SystemTimers.h" +#include "Core/IOS/IOSC.h" class PointerWrap; @@ -108,6 +109,8 @@ public: bool BootIOS(u64 ios_title_id); u32 GetVersion() const; + IOSC& GetIOSC(); + private: void ExecuteIPCCommand(u32 address); IPCCommandResult HandleIPCCommand(const Request& request); @@ -133,6 +136,8 @@ private: IPCMsgQueue m_reply_queue; // arm -> ppc IPCMsgQueue m_ack_queue; // arm -> ppc u64 m_last_reply_time = 0; + + IOSC m_iosc; }; // Used for controlling and accessing an IOS instance that is tied to emulation. diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 25b65dc8a7..064f959223 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // 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. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/Core/ec_wii.cpp b/Source/Core/Core/ec_wii.cpp index e726cf0699..fc3b031e49 100644 --- a/Source/Core/Core/ec_wii.cpp +++ b/Source/Core/Core/ec_wii.cpp @@ -9,7 +9,6 @@ #include "Core/ec_wii.h" -#include #include #include @@ -180,19 +179,6 @@ const u8* EcWii::GetNGSig() const return BootMiiKeysBin.ng_sig; } -std::array 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 sha1; - mbedtls_sha1(shared_secret.data(), shared_secret.size() / 2, sha1.data()); - - std::array aes_key; - std::copy_n(sha1.cbegin(), aes_key.size(), aes_key.begin()); - return aes_key; -} - void EcWii::InitDefaults() { memset(&BootMiiKeysBin, 0, sizeof(BootMiiKeysBin)); diff --git a/Source/Core/Core/ec_wii.h b/Source/Core/Core/ec_wii.h index a51e44a881..99b1bafeaf 100644 --- a/Source/Core/Core/ec_wii.h +++ b/Source/Core/Core/ec_wii.h @@ -26,8 +26,6 @@ #include "Common/CommonTypes.h" -#include - 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, const u8* NG_priv, u32 NG_id); @@ -43,9 +41,6 @@ public: const u8* GetNGPriv() const; const u8* GetNGSig() const; - using ECCKey = std::array; - std::array GetSharedSecret(const ECCKey& peer_public_key) const; - private: void InitDefaults();