Merge pull request #12244 from DacoTaco/feature/crypto
IOS: implement /dev/aes & /dev/sha
This commit is contained in:
commit
b4c0da30bd
|
@ -336,6 +336,10 @@ 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
|
||||
IOS/DI/DI.h
|
||||
IOS/DolphinDevice.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 <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#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<IPCReply> AesDevice::Open(const OpenRequest& request)
|
||||
{
|
||||
return Device::Open(request);
|
||||
}
|
||||
|
||||
std::optional<IPCReply> AesDevice::IOCtlV(const IOCtlVRequest& request)
|
||||
{
|
||||
auto& system = GetSystem();
|
||||
auto& memory = system.GetMemory();
|
||||
HLE::ReturnCode return_code = IPC_EINVAL;
|
||||
AesIoctlv command = static_cast<AesIoctlv>(request.request);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case AesIoctlv::Copy:
|
||||
{
|
||||
if (!request.HasNumberOfValidVectors(1, 1))
|
||||
break;
|
||||
|
||||
std::vector<u8> input = std::vector<u8>(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<u8> input = std::vector<u8>(request.in_vectors[0].size);
|
||||
std::vector<u8> output = std::vector<u8>(request.io_vectors[0].size);
|
||||
std::array<u8, 10> key = {0};
|
||||
std::array<u8, 10> 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
|
|
@ -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<IPCReply> Open(const OpenRequest& request) override;
|
||||
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||
|
||||
enum class AesIoctlv : u32
|
||||
{
|
||||
Copy = 0x00,
|
||||
Encrypt = 0x02,
|
||||
Decrypt = 0x03,
|
||||
};
|
||||
};
|
||||
} // namespace IOS::HLE
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/IOS/Crypto/Sha.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <mbedtls/sha1.h>
|
||||
|
||||
#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<IPCReply> 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<u8, 20> 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<u8> 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<IPCReply> ShaDevice::IOCtlV(const IOCtlVRequest& request)
|
||||
{
|
||||
HLE::ReturnCode return_code = IPC_EINVAL;
|
||||
ShaIoctlv command = static_cast<ShaIoctlv>(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
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#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<IPCReply> Open(const OpenRequest& request) override;
|
||||
std::optional<IPCReply> IOCtlV(const IOCtlVRequest& request) override;
|
||||
|
||||
enum class ShaIoctlv : u32
|
||||
{
|
||||
InitState = 0x00,
|
||||
ContributeState = 0x01,
|
||||
FinalizeState = 0x02,
|
||||
ShaCommandUnknown = 0x0F
|
||||
};
|
||||
|
||||
struct ShaContext
|
||||
{
|
||||
std::array<u32, 5> states;
|
||||
std::array<u32, 2> length; // length in bits of total data contributed to SHA-1 hash
|
||||
};
|
||||
|
||||
private:
|
||||
HLE::ReturnCode ProcessShaCommand(ShaIoctlv command, const IOCtlVRequest& request);
|
||||
};
|
||||
} // namespace IOS::HLE
|
|
@ -28,6 +28,8 @@
|
|||
#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"
|
||||
#include "Core/IOS/DeviceStub.h"
|
||||
|
@ -334,6 +336,9 @@ 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<AesDevice>(*this, "/dev/aes"));
|
||||
AddDevice(std::make_unique<ShaDevice>(*this, "/dev/sha"));
|
||||
|
||||
m_fs_core = std::make_unique<FSCore>(*this);
|
||||
AddDevice(std::make_unique<FSDevice>(*this, *m_fs_core, "/dev/fs"));
|
||||
m_es_core = std::make_unique<ESCore>(*this);
|
||||
|
@ -649,6 +654,22 @@ std::shared_ptr<Device> EmulationKernel::GetDeviceByName(std::string_view device
|
|||
return iterator != m_device_map.end() ? iterator->second : nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Device> EmulationKernel::GetDeviceByFileDescriptor(const int fd)
|
||||
{
|
||||
if (fd < IPC_MAX_FDS)
|
||||
return m_fdmap[fd];
|
||||
|
||||
switch (fd)
|
||||
{
|
||||
case 0x10000:
|
||||
return GetDeviceByName("/dev/aes");
|
||||
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<IPCReply> EmulationKernel::OpenDevice(OpenRequest& request)
|
||||
{
|
||||
|
@ -703,7 +724,7 @@ std::optional<IPCReply> 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 +734,9 @@ std::optional<IPCReply> 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:
|
||||
|
|
|
@ -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<Device> GetDeviceByName(std::string_view device_name);
|
||||
std::shared_ptr<Device> GetDeviceByFileDescriptor(const int fd);
|
||||
|
||||
std::shared_ptr<FSDevice> GetFSDevice();
|
||||
std::shared_ptr<ESDevice> GetESDevice();
|
||||
|
|
|
@ -343,6 +343,8 @@
|
|||
<ClInclude Include="Core\HW\WiimoteReal\WiimoteReal.h" />
|
||||
<ClInclude Include="Core\HW\WiiSave.h" />
|
||||
<ClInclude Include="Core\HW\WiiSaveStructs.h" />
|
||||
<ClInclude Include="Core\IOS\Crypto\Sha.h" />
|
||||
<ClInclude Include="Core\IOS\Crypto\AesDevice.h" />
|
||||
<ClInclude Include="Core\IOS\Device.h" />
|
||||
<ClInclude Include="Core\IOS\DeviceStub.h" />
|
||||
<ClInclude Include="Core\IOS\DI\DI.h" />
|
||||
|
@ -983,6 +985,8 @@
|
|||
<ClCompile Include="Core\HW\WiimoteReal\IOWin.cpp" />
|
||||
<ClCompile Include="Core\HW\WiimoteReal\WiimoteReal.cpp" />
|
||||
<ClCompile Include="Core\HW\WiiSave.cpp" />
|
||||
<ClCompile Include="Core\IOS\Crypto\Sha.cpp" />
|
||||
<ClCompile Include="Core\IOS\Crypto\AesDevice.cpp" />
|
||||
<ClCompile Include="Core\IOS\Device.cpp" />
|
||||
<ClCompile Include="Core\IOS\DeviceStub.cpp" />
|
||||
<ClCompile Include="Core\IOS\DI\DI.cpp" />
|
||||
|
|
Loading…
Reference in New Issue