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 @@ +