From d4c18f3f31c6b16e38d36572412745ca19cfe44c Mon Sep 17 00:00:00 2001 From: DacoTaco Date: Wed, 18 Oct 2023 21:48:19 +0200 Subject: [PATCH 1/2] IOS: implement /dev/sha --- Source/Core/Core/CMakeLists.txt | 2 + Source/Core/Core/IOS/Crypto/Sha.cpp | 101 ++++++++++++++++++++++++++++ Source/Core/Core/IOS/Crypto/Sha.h | 37 ++++++++++ Source/Core/Core/IOS/IOS.cpp | 23 ++++++- Source/Core/Core/IOS/IOS.h | 1 + Source/Core/DolphinLib.props | 2 + 6 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 Source/Core/Core/IOS/Crypto/Sha.cpp create mode 100644 Source/Core/Core/IOS/Crypto/Sha.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 4a40eb7ec8..efb1916621 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -336,6 +336,8 @@ add_library(core IOS/Device.h IOS/DeviceStub.cpp IOS/DeviceStub.h + IOS/Crypto/Sha.cpp + IOS/Crypto/Sha.h IOS/DI/DI.cpp IOS/DI/DI.h IOS/DolphinDevice.cpp diff --git a/Source/Core/Core/IOS/Crypto/Sha.cpp b/Source/Core/Core/IOS/Crypto/Sha.cpp new file mode 100644 index 0000000000..1844020587 --- /dev/null +++ b/Source/Core/Core/IOS/Crypto/Sha.cpp @@ -0,0 +1,101 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/IOS/Crypto/Sha.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "Common/Assert.h" +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" +#include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" +#include "Core/System.h" + +namespace IOS::HLE +{ +ShaDevice::ShaDevice(EmulationKernel& ios, const std::string& device_name) + : EmulationDevice(ios, device_name) +{ +} + +std::optional ShaDevice::Open(const OpenRequest& request) +{ + return Device::Open(request); +} + +static void ConvertContext(const ShaDevice::ShaContext& src, mbedtls_sha1_context* dest) +{ + std::copy(std::begin(src.length), std::end(src.length), std::begin(dest->total)); + std::copy(std::begin(src.states), std::end(src.states), std::begin(dest->state)); +} + +static void ConvertContext(const mbedtls_sha1_context& src, ShaDevice::ShaContext* dest) +{ + std::copy(std::begin(src.total), std::end(src.total), std::begin(dest->length)); + std::copy(std::begin(src.state), std::end(src.state), std::begin(dest->states)); +} + +HLE::ReturnCode ShaDevice::ProcessShaCommand(ShaIoctlv command, const IOCtlVRequest& request) +{ + auto& system = GetSystem(); + auto& memory = system.GetMemory(); + auto ret = 0; + std::array output_hash{}; + mbedtls_sha1_context context; + ShaDevice::ShaContext engine_context; + memory.CopyFromEmu(&engine_context, request.io_vectors[0].address, sizeof(ShaDevice::ShaContext)); + ConvertContext(engine_context, &context); + + // reset the context + if (command == ShaIoctlv::InitState) + { + ret = mbedtls_sha1_starts_ret(&context); + } + else + { + std::vector input_data(request.in_vectors[0].size); + memory.CopyFromEmu(input_data.data(), request.in_vectors[0].address, input_data.size()); + ret = mbedtls_sha1_update_ret(&context, input_data.data(), input_data.size()); + if (!ret && command == ShaIoctlv::FinalizeState) + { + ret = mbedtls_sha1_finish_ret(&context, output_hash.data()); + } + } + + ConvertContext(context, &engine_context); + memory.CopyToEmu(request.io_vectors[0].address, &engine_context, sizeof(ShaDevice::ShaContext)); + if (!ret && command == ShaIoctlv::FinalizeState) + memory.CopyToEmu(request.io_vectors[1].address, output_hash.data(), output_hash.size()); + + mbedtls_sha1_free(&context); + return ret ? HLE::ReturnCode::IPC_EACCES : HLE::ReturnCode::IPC_SUCCESS; +} + +std::optional ShaDevice::IOCtlV(const IOCtlVRequest& request) +{ + HLE::ReturnCode return_code = IPC_EINVAL; + ShaIoctlv command = static_cast(request.request); + + switch (command) + { + case ShaIoctlv::InitState: + case ShaIoctlv::ContributeState: + case ShaIoctlv::FinalizeState: + if (!request.HasNumberOfValidVectors(1, 2)) + break; + + return_code = ProcessShaCommand(command, request); + } + + return IPCReply(return_code); +} + +} // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/Crypto/Sha.h b/Source/Core/Core/IOS/Crypto/Sha.h new file mode 100644 index 0000000000..94f23f670c --- /dev/null +++ b/Source/Core/Core/IOS/Crypto/Sha.h @@ -0,0 +1,37 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "Common/Crypto/SHA1.h" +#include "Core/IOS/Device.h" + +namespace IOS::HLE +{ +class ShaDevice final : public EmulationDevice +{ +public: + ShaDevice(EmulationKernel& ios, const std::string& device_name); + std::optional Open(const OpenRequest& request) override; + std::optional IOCtlV(const IOCtlVRequest& request) override; + + enum class ShaIoctlv : u32 + { + InitState = 0x00, + ContributeState = 0x01, + FinalizeState = 0x02, + ShaCommandUnknown = 0x0F + }; + + struct ShaContext + { + std::array states; + std::array length; // length in bits of total data contributed to SHA-1 hash + }; + +private: + HLE::ReturnCode ProcessShaCommand(ShaIoctlv command, const IOCtlVRequest& request); +}; +} // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index abee77bf27..329b912950 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -28,6 +28,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" #include "Core/HW/WII_IPC.h" +#include "Core/IOS/Crypto/Sha.h" #include "Core/IOS/DI/DI.h" #include "Core/IOS/Device.h" #include "Core/IOS/DeviceStub.h" @@ -333,6 +334,8 @@ EmulationKernel::EmulationKernel(Core::System& system, u64 title_id) m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects()); ASSERT(m_fs); + + AddDevice(std::make_unique(*this, "/dev/sha")); m_fs_core = std::make_unique(*this); AddDevice(std::make_unique(*this, *m_fs_core, "/dev/fs")); @@ -649,6 +652,20 @@ std::shared_ptr EmulationKernel::GetDeviceByName(std::string_view device return iterator != m_device_map.end() ? iterator->second : nullptr; } +std::shared_ptr EmulationKernel::GetDeviceByFileDescriptor(const int fd) +{ + if (fd < IPC_MAX_FDS) + return m_fdmap[fd]; + + switch (fd) + { + case 0x10001: + return GetDeviceByName("/dev/sha"); + default: + return nullptr; + } +} + // Returns the FD for the newly opened device (on success) or an error code. std::optional EmulationKernel::OpenDevice(OpenRequest& request) { @@ -703,7 +720,7 @@ std::optional EmulationKernel::HandleIPCCommand(const Request& request return OpenDevice(open_request); } - const auto device = (request.fd < IPC_MAX_FDS) ? m_fdmap[request.fd] : nullptr; + const auto device = GetDeviceByFileDescriptor(request.fd); if (!device) return IPCReply{IPC_EINVAL, 550_tbticks}; @@ -713,7 +730,9 @@ std::optional EmulationKernel::HandleIPCCommand(const Request& request switch (request.command) { case IPC_CMD_CLOSE: - m_fdmap[request.fd].reset(); + // if the fd is not a special IOS FD, we need to reset it too + if (request.fd < IPC_MAX_FDS) + m_fdmap[request.fd].reset(); ret = device->Close(request.fd); break; case IPC_CMD_READ: diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h index 0339ad13bb..2133e155c8 100644 --- a/Source/Core/Core/IOS/IOS.h +++ b/Source/Core/Core/IOS/IOS.h @@ -154,6 +154,7 @@ public: // Get a resource manager by name. // This only works for devices which are part of the device map. std::shared_ptr GetDeviceByName(std::string_view device_name); + std::shared_ptr GetDeviceByFileDescriptor(const int fd); std::shared_ptr GetFSDevice(); std::shared_ptr GetESDevice(); diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 8c86b02051..37d1c13795 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -343,6 +343,7 @@ + @@ -983,6 +984,7 @@ + From 2241aaf168dcf60050f01fa74e15ae1ae434f9d2 Mon Sep 17 00:00:00 2001 From: DacoTaco Date: Tue, 17 Oct 2023 20:09:04 +0200 Subject: [PATCH 2/2] IOS: implement /dev/aes --- Source/Core/Core/CMakeLists.txt | 2 + Source/Core/Core/IOS/Crypto/AesDevice.cpp | 89 +++++++++++++++++++++++ Source/Core/Core/IOS/Crypto/AesDevice.h | 25 +++++++ Source/Core/Core/IOS/IOS.cpp | 6 +- Source/Core/DolphinLib.props | 2 + 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 Source/Core/Core/IOS/Crypto/AesDevice.cpp create mode 100644 Source/Core/Core/IOS/Crypto/AesDevice.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index efb1916621..bddb4f04b0 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -336,6 +336,8 @@ add_library(core IOS/Device.h IOS/DeviceStub.cpp IOS/DeviceStub.h + IOS/Crypto/AesDevice.cpp + IOS/Crypto/AesDevice.h IOS/Crypto/Sha.cpp IOS/Crypto/Sha.h IOS/DI/DI.cpp diff --git a/Source/Core/Core/IOS/Crypto/AesDevice.cpp b/Source/Core/Core/IOS/Crypto/AesDevice.cpp new file mode 100644 index 0000000000..04614a37ca --- /dev/null +++ b/Source/Core/Core/IOS/Crypto/AesDevice.cpp @@ -0,0 +1,89 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/IOS/Crypto/AesDevice.h" + +#include +#include +#include +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" +#include "Common/Crypto/AES.h" +#include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" +#include "Core/System.h" + +namespace IOS::HLE +{ +AesDevice::AesDevice(EmulationKernel& ios, const std::string& device_name) + : EmulationDevice(ios, device_name) +{ +} + +std::optional AesDevice::Open(const OpenRequest& request) +{ + return Device::Open(request); +} + +std::optional AesDevice::IOCtlV(const IOCtlVRequest& request) +{ + auto& system = GetSystem(); + auto& memory = system.GetMemory(); + HLE::ReturnCode return_code = IPC_EINVAL; + AesIoctlv command = static_cast(request.request); + + switch (command) + { + case AesIoctlv::Copy: + { + if (!request.HasNumberOfValidVectors(1, 1)) + break; + + std::vector input = std::vector(request.in_vectors[0].size); + memory.CopyFromEmu(input.data(), request.in_vectors[0].address, input.size()); + memory.CopyToEmu(request.io_vectors[0].address, input.data(), input.size()); + return_code = ReturnCode::IPC_SUCCESS; + break; + } + case AesIoctlv::Decrypt: + case AesIoctlv::Encrypt: + { + if (!request.HasNumberOfValidVectors(2, 2)) + break; + + if (request.in_vectors[1].size != 0x10 || (request.in_vectors[1].address & 3) != 0 || + request.io_vectors[1].size != 0x10 || (request.io_vectors[1].address & 3) != 0) + { + break; + } + + std::vector input = std::vector(request.in_vectors[0].size); + std::vector output = std::vector(request.io_vectors[0].size); + std::array key = {0}; + std::array iv = {0}; + memory.CopyFromEmu(input.data(), request.in_vectors[0].address, input.size()); + memory.CopyFromEmu(key.data(), request.in_vectors[1].address, key.size()); + memory.CopyFromEmu(iv.data(), request.io_vectors[1].address, iv.size()); + + auto context = command == AesIoctlv::Encrypt ? Common::AES::CreateContextEncrypt(key.data()) : + Common::AES::CreateContextDecrypt(key.data()); + + context->Crypt(iv.data(), iv.data(), input.data(), output.data(), + std::min(output.size(), input.size())); + + memory.CopyToEmu(request.io_vectors[0].address, output.data(), output.size()); + memory.CopyToEmu(request.io_vectors[1].address, iv.data(), iv.size()); + return_code = ReturnCode::IPC_SUCCESS; + break; + } + } + + return IPCReply(return_code); +} + +} // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/Crypto/AesDevice.h b/Source/Core/Core/IOS/Crypto/AesDevice.h new file mode 100644 index 0000000000..4ec83fc156 --- /dev/null +++ b/Source/Core/Core/IOS/Crypto/AesDevice.h @@ -0,0 +1,25 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "Common/Crypto/AES.h" +#include "Core/IOS/Device.h" + +namespace IOS::HLE +{ +class AesDevice final : public EmulationDevice +{ +public: + AesDevice(EmulationKernel& ios, const std::string& device_name); + std::optional Open(const OpenRequest& request) override; + std::optional IOCtlV(const IOCtlVRequest& request) override; + + enum class AesIoctlv : u32 + { + Copy = 0x00, + Encrypt = 0x02, + Decrypt = 0x03, + }; +}; +} // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 329b912950..8c08c64001 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -28,6 +28,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" #include "Core/HW/WII_IPC.h" +#include "Core/IOS/Crypto/AesDevice.h" #include "Core/IOS/Crypto/Sha.h" #include "Core/IOS/DI/DI.h" #include "Core/IOS/Device.h" @@ -334,7 +335,8 @@ EmulationKernel::EmulationKernel(Core::System& system, u64 title_id) m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects()); ASSERT(m_fs); - + + AddDevice(std::make_unique(*this, "/dev/aes")); AddDevice(std::make_unique(*this, "/dev/sha")); m_fs_core = std::make_unique(*this); @@ -659,6 +661,8 @@ std::shared_ptr EmulationKernel::GetDeviceByFileDescriptor(const int fd) switch (fd) { + case 0x10000: + return GetDeviceByName("/dev/aes"); case 0x10001: return GetDeviceByName("/dev/sha"); default: diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 37d1c13795..2cf663e399 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -344,6 +344,7 @@ + @@ -985,6 +986,7 @@ +