Skip to content

Commit

Permalink
Add initial WiiConnect24 support
Browse files Browse the repository at this point in the history
Fix Lint and compilation errors

Merge vffFatFs with FatFs

Fix subtask support and conform to code style

Mark iv and in_buf arguments for AES_OFB as const
  • Loading branch information
noahpistilli authored and AdmiralCurtiss committed Sep 29, 2022
1 parent e9cbc59 commit b722a51
Show file tree
Hide file tree
Showing 13 changed files with 846 additions and 4 deletions.
18 changes: 17 additions & 1 deletion Source/Core/Common/Crypto/AES.cpp
Expand Up @@ -17,7 +17,6 @@
#if defined(_M_X86_64)
#include <x86intrin.h>
#elif defined(_M_ARM_64)
#include <arm_acle.h>
#include <arm_neon.h>
#endif
#endif
Expand Down Expand Up @@ -408,4 +407,21 @@ std::unique_ptr<Context> CreateContextDecrypt(const u8* key)
return CreateContext<Mode::Decrypt>(key);
}

// OFB encryption and decryption are the exact same. We don't encrypt though.
void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)
{
mbedtls_aes_context aes_ctx;
size_t iv_offset = 0;

std::array<u8, 16> iv_tmp{};
if (iv)
std::memcpy(&iv_tmp[0], iv, 16);

ASSERT(!mbedtls_aes_setkey_enc(&aes_ctx, key, 128));
mbedtls_aes_crypt_ofb(&aes_ctx, size, &iv_offset, &iv_tmp[0], buf_in, buf_out);

if (iv_out)
std::memcpy(iv_out, &iv_tmp[0], 16);
}

} // namespace Common::AES
3 changes: 3 additions & 0 deletions Source/Core/Common/Crypto/AES.h
Expand Up @@ -46,4 +46,7 @@ class Context
std::unique_ptr<Context> CreateContextEncrypt(const u8* key);
std::unique_ptr<Context> CreateContextDecrypt(const u8* key);

// OFB decryption for WiiConnect24
void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size);

} // namespace Common::AES
6 changes: 6 additions & 0 deletions Source/Core/Core/CMakeLists.txt
Expand Up @@ -358,6 +358,8 @@ add_library(core
IOS/Network/KD/NetKDTime.h
IOS/Network/KD/NWC24Config.cpp
IOS/Network/KD/NWC24Config.h
IOS/Network/KD/VFF/VFFUtil.cpp
IOS/Network/KD/VFF/VFFUtil.h
IOS/Network/MACUtils.cpp
IOS/Network/MACUtils.h
IOS/Network/NCD/Manage.cpp
Expand Down Expand Up @@ -496,6 +498,9 @@ add_library(core
WiiRoot.h
WiiUtils.cpp
WiiUtils.h
IOS/Network/KD/WC24File.h
IOS/Network/KD/NWC24DL.cpp
IOS/Network/KD/NWC24DL.h
)

if(_M_X86)
Expand Down Expand Up @@ -593,6 +598,7 @@ PUBLIC
videosoftware

PRIVATE
FatFs
fmt::fmt
${LZO}
ZLIB::ZLIB
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Core/IOS/IOSC.cpp
Expand Up @@ -370,6 +370,12 @@ ReturnCode IOSC::Decrypt(Handle key_handle, u8* iv, const u8* input, size_t size
return DecryptEncrypt(Common::AES::Mode::Decrypt, key_handle, iv, input, size, output, pid);
}

ReturnCode IOSC::CryptOFB(u8* key, u8* iv, u8* input, size_t size, u8* output)
{
Common::AES::CryptOFB(key, iv, iv, input, output, size);
return IPC_SUCCESS;
}

ReturnCode IOSC::VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle signer_handle,
const std::vector<u8>& signature, u32 pid) const
{
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/IOS/IOSC.h
Expand Up @@ -210,6 +210,8 @@ class IOSC final
ReturnCode Decrypt(Handle key_handle, u8* iv, const u8* input, size_t size, u8* output,
u32 pid) const;

ReturnCode CryptOFB(u8* key, u8* iv, u8* input, size_t size, u8* output);

ReturnCode VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle signer_handle,
const std::vector<u8>& signature, u32 pid) const;
// Import a certificate (signed by the certificate in signer_handle) into dest_handle.
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/Core/IOS/Network/KD/NWC24Config.h
Expand Up @@ -19,10 +19,15 @@ enum ErrorCode : s32
{
WC24_OK = 0,
WC24_ERR_FATAL = -1,
WC24_ERR_ID_NONEXISTANCE = -34,
WC24_ERR_NOT_FOUND = -13,
WC24_ERR_BROKEN = -14,
WC24_ERR_FILE_OPEN = -16,
WC24_ERR_FILE_CLOSE = -17,
WC24_ERR_FILE_WRITE = -19,
WC24_ERR_NETWORK = -31,
WC24_ERR_SERVER = -32,
WC24_ERR_ID_GENERATED = -35,
WC24_ERR_ID_REGISTERED = -36,
WC24_ERR_ID_NOT_REGISTERED = -44,
};

enum class NWC24CreationStage : u32
Expand Down
148 changes: 148 additions & 0 deletions Source/Core/Core/IOS/Network/KD/NWC24DL.cpp
@@ -0,0 +1,148 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "Core/IOS/Network/KD/NWC24DL.h"

#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/Swap.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/Uids.h"

namespace IOS::HLE::NWC24
{
constexpr const char DL_LIST_PATH[] = "/" WII_WC24CONF_DIR "/nwc24dl.bin";

NWC24Dl::NWC24Dl(std::shared_ptr<FS::FileSystem> fs) : m_fs{std::move(fs)}
{
ReadDlList();
}

void NWC24Dl::ReadDlList()
{
const auto file = m_fs->OpenFile(PID_KD, PID_KD, DL_LIST_PATH, FS::Mode::Read);
if (!file || !file->Read(&m_data, 1))
return;

const s32 file_error = CheckNwc24DlList();
if (file_error)
ERROR_LOG_FMT(IOS_WC24, "There is an error in the DL list for WC24: {}", file_error);
}

s32 NWC24Dl::CheckNwc24DlList() const
{
// 'WcDl' magic
if (Magic() != DL_LIST_MAGIC)
{
ERROR_LOG_FMT(IOS_WC24, "DL list magic mismatch");
return -1;
}

if (Version() != 1)
{
ERROR_LOG_FMT(IOS_WC24, "DL list version mismatch");
return -1;
}

return 0;
}

void NWC24Dl::WriteDlList() const
{
constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
m_fs->CreateFullPath(PID_KD, PID_KD, DL_LIST_PATH, 0, public_modes);
const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, DL_LIST_PATH, public_modes);

if (!file || !file->Write(&m_data, 1))
ERROR_LOG_FMT(IOS_WC24, "Failed to open or write WC24 DL list file");
}

void NWC24Dl::ResetConfig()
{
// m_fs->Delete(PID_KD, PID_KD, CONFIG_PATH);
// TODO: implement
}

std::string NWC24Dl::GetDownloadURL(u16 entry_index, std::optional<u8> subtask_id) const
{
std::string url(m_data.entries[entry_index].dl_url);

// Determine if we need to append the subtask to the URL.
if ((Common::swap32(m_data.entries[entry_index].subtask_bitmask) & (1 << (2 - 1))) == 2 &&
subtask_id)
{
url.append(fmt::format(".{:02d}", *subtask_id));
}

return url;
}

std::string NWC24Dl::GetVFFContentName(u16 entry_index, std::optional<u8> subtask_id) const
{
std::string content(m_data.entries[entry_index].filename);

// Determine if we need to append the subtask to the name.
if ((Common::swap32(m_data.entries[entry_index].subtask_bitmask) & (1 << (1 - 1))) == 1 &&
subtask_id)
{
content.append(fmt::format(".{:02d}", *subtask_id));
}

return content;
}

std::string NWC24Dl::GetVFFPath(u16 entry_index) const
{
const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id);
const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id);

return fmt::format("/title/{0:08x}/{1:08x}/data/wc24dl.vff", lower_title_id, high_title_id);
}

WC24PubkMod NWC24Dl::GetWC24PubkMod(u16 entry_index) const
{
WC24PubkMod pubkMod;
const u32 lower_title_id = Common::swap32(m_data.entries[entry_index].low_title_id);
const u32 high_title_id = Common::swap32(m_data.entries[entry_index].high_title_id);

const std::string path =
fmt::format("/title/{0:08x}/{1:08x}/data/wc24pubk.mod", lower_title_id, high_title_id);

const auto file = m_fs->OpenFile(PID_KD, PID_KD, path, IOS::HLE::FS::Mode::Read);
file->Read(&pubkMod, 1);

return pubkMod;
}

bool NWC24Dl::isEncrypted(u16 entry_index) const
{
return (Common::swap32(m_data.entries[entry_index].flags) & (1 << (4 - 1))) == 8;
}

u32 NWC24Dl::Magic() const
{
return Common::swap32(m_data.header.magic);
}

void NWC24Dl::SetMagic(u32 magic)
{
m_data.header.magic = Common::swap32(magic);
}

u8 NWC24Dl::SubtaskID(u16 entry_index) const
{
return m_data.entries[entry_index].subtask_flags;
}

u32 NWC24Dl::Version() const
{
return Common::swap32(m_data.header.version);
}

void NWC24Dl::SetVersion(u32 version)
{
m_data.header.version = Common::swap32(version);
}

} // namespace IOS::HLE::NWC24
120 changes: 120 additions & 0 deletions Source/Core/Core/IOS/Network/KD/NWC24DL.h
@@ -0,0 +1,120 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>
#include <optional>
#include <string>
#include "Common/CommonTypes.h"
#include "Core/IOS/Network/KD/WC24File.h"

namespace IOS::HLE
{
namespace FS
{
class FileSystem;
}
namespace NWC24
{
// TODO: -3 for error code

class NWC24Dl final
{
public:
explicit NWC24Dl(std::shared_ptr<FS::FileSystem> fs);

void ReadDlList();
void WriteDlList() const;
void ResetConfig();

s32 CheckNwc24DlList() const;

bool isEncrypted(u16 entry_index) const;
std::string GetVFFContentName(u16 entry_index, std::optional<u8> subtask_id) const;
std::string GetDownloadURL(u16 entry_index, std::optional<u8> subtask_id) const;
std::string GetVFFPath(u16 entry_index) const;
WC24PubkMod GetWC24PubkMod(u16 entry_index) const;
u8 SubtaskID(u16 entry_index) const;

u32 Magic() const;
void SetMagic(u32 magic);

u32 Version() const;
void SetVersion(u32 version);

private:
enum
{
DL_LIST_MAGIC = 'WcDl', // 'WcDl'
MAX_SUBENTRIES = 0x20, // 32
MAX_ENTRIES = 0x78, // 120
};

#pragma pack(push, 1)
// The following format is partially based off of https://wiibrew.org/wiki//dev/net/kd/request.
struct DLListHeader final
{
u32 magic; // 'WcDl' 0x5763446c
u32 version; // must be 1
u32 unk1;
u32 unk2;
u16 max_subentries; // Asserted to be less than max_entries
u16 reserved_mailnum;
u16 max_entries;
u8 reserved[106];
};

struct DLListRecord final
{
u32 low_title_id;
u32 next_dl_timestamp;
u32 last_modified_timestamp;
u8 flags;
u8 padding[3];
};

struct DLListEntry final
{
uint16_t index;
uint8_t type; /* TODO: make enum */
uint8_t record_flags;
uint32_t flags;
uint32_t high_title_id;
u32 low_title_id;
u32 _;
uint16_t group_id;
uint16_t field7_0x16;
uint16_t count; /* count of what??? */
uint16_t error_count;
uint16_t dl_frequency; /* ???????? */
uint16_t other_dl_freq; /* ???????? */
int32_t error_code;
uint8_t subtask_id;
uint8_t subtask_type;
uint8_t subtask_flags;
uint8_t field16_0x27;
uint32_t subtask_bitmask;
int unknownOtherValue;
uint32_t dl_timestamp; /* Last DL time */
uint32_t subtask_timestamps[32];
char dl_url[236];
char filename[64]; /* Null-terminated */
uint8_t unk6[29];
uint8_t should_use_rootca;
uint16_t field25_0x1fe;
};

struct DLList final
{
DLListHeader header;
DLListRecord records[MAX_ENTRIES];
DLListEntry entries[MAX_ENTRIES];
};
#pragma pack(pop)

std::shared_ptr<FS::FileSystem> m_fs;
DLList m_data;
};
} // namespace NWC24
} // namespace IOS::HLE

0 comments on commit b722a51

Please sign in to comment.