Skip to content
Permalink
Browse files
Merge pull request #11072 from SketchMaster2001/wiiconnect24
Add initial WiiConnect24 support
  • Loading branch information
AdmiralCurtiss committed Oct 16, 2022
2 parents fbe782f + e413d7f commit c0476fd
Show file tree
Hide file tree
Showing 12 changed files with 863 additions and 1 deletion.
@@ -408,4 +408,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
@@ -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
@@ -363,6 +363,11 @@ add_library(core
IOS/Network/KD/NetKDTime.h
IOS/Network/KD/NWC24Config.cpp
IOS/Network/KD/NWC24Config.h
IOS/Network/KD/NWC24DL.cpp
IOS/Network/KD/NWC24DL.h
IOS/Network/KD/VFF/VFFUtil.cpp
IOS/Network/KD/VFF/VFFUtil.h
IOS/Network/KD/WC24File.h
IOS/Network/MACUtils.cpp
IOS/Network/MACUtils.h
IOS/Network/NCD/Manage.cpp
@@ -598,6 +603,7 @@ PUBLIC
videosoftware

PRIVATE
FatFs
fmt::fmt
${LZO}
ZLIB::ZLIB
@@ -19,6 +19,14 @@ enum ErrorCode : s32
{
WC24_OK = 0,
WC24_ERR_FATAL = -1,
WC24_ERR_NOT_FOUND = -13,
WC24_ERR_BROKEN = -14,
WC24_ERR_FILE_OPEN = -16,
WC24_ERR_FILE_CLOSE = -17,
WC24_ERR_FILE_READ = -18,
WC24_ERR_FILE_WRITE = -19,
WC24_ERR_NETWORK = -31,
WC24_ERR_SERVER = -32,
WC24_ERR_ID_NONEXISTANCE = -34,
WC24_ERR_ID_GENERATED = -35,
WC24_ERR_ID_REGISTERED = -36,
@@ -0,0 +1,143 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

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

#include "Common/BitUtils.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");
}

bool NWC24Dl::DoesEntryExist(u16 entry_index)
{
return m_data.entries[entry_index].low_title_id != 0;
}

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 (subtask_id &&
Common::ExtractBit(Common::swap32(m_data.entries[entry_index].subtask_bitmask), 1))
{
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 (subtask_id &&
Common::ExtractBit(Common::swap32(m_data.entries[entry_index].subtask_bitmask), 0))
{
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::ExtractBit(Common::swap32(m_data.entries[entry_index].flags), 3);
}

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

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

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
@@ -0,0 +1,123 @@
// 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
{
class NWC24Dl final
{
public:
explicit NWC24Dl(std::shared_ptr<FS::FileSystem> fs);

void ReadDlList();
void WriteDlList() const;

s32 CheckNwc24DlList() const;

bool DoesEntryExist(u16 entry_index);
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;

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

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

static constexpr u32 MAX_ENTRIES = 120;

private:
static constexpr u32 DL_LIST_MAGIC = 0x5763446C; // WcDl
static constexpr u32 MAX_SUBENTRIES = 32;

enum EntryType : u8
{
UNK = 1,
MAIL,
CHANNEL_CONTENT,
UNUSED = 0xff
};

#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
{
u16 index;
EntryType type;
u8 record_flags;
u32 flags;
u32 high_title_id;
u32 low_title_id;
u32 unknown1;
u16 group_id;
u16 padding1;
u16 remaining_downloads;
u16 error_count;
u16 dl_frequency;
u16 dl_frequency_when_err;
s32 error_code;
u8 subtask_id;
u8 subtask_type;
u8 subtask_flags;
u8 padding2;
u32 subtask_bitmask;
s32 unknown2;
u32 dl_timestamp; // Last DL time
u32 subtask_timestamps[32];
char dl_url[236];
char filename[64];
u8 unk6[29];
u8 should_use_rootca;
u16 unknown3;
};

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 c0476fd

Please sign in to comment.