Merge pull request #12244 from DacoTaco/feature/crypto

IOS: implement /dev/aes & /dev/sha
This commit is contained in:
Admiral H. Curtiss 2023-11-02 19:36:40 +01:00 committed by GitHub
commit b4c0da30bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 286 additions and 2 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();

View File

@ -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" />