mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-04 14:01:17 +12:00
* Update OpenSSL hash functions to OpenSSL 3.0 * Fix invalid sscanf format in DownloadManager * Fix unset return value warning * Fix erroneous check on otpMem in iosu_crypto
178 lines
No EOL
5.5 KiB
C++
178 lines
No EOL
5.5 KiB
C++
#include "Cafe/OS/common/OSCommon.h"
|
|
#include "Cafe/OS/libs/nn_acp/nn_acp.h"
|
|
#include "Cafe/OS/libs/coreinit/coreinit_Thread.h"
|
|
#include "Cafe/OS/libs/nn_common.h"
|
|
#include "util/crypto/aes128.h"
|
|
#include "openssl/sha.h"
|
|
#include "Cemu/napi/napi.h"
|
|
|
|
namespace nn
|
|
{
|
|
namespace idbe
|
|
{
|
|
struct nnIdbeIconDataV0_t
|
|
{
|
|
// raw icon data as byte array
|
|
// check NAPI::IDBEIconDataV0 for exact data layout
|
|
uint8 rawData[0x12060];
|
|
uint8* GetTGAData()
|
|
{
|
|
return rawData + 0x2030;
|
|
}
|
|
};
|
|
|
|
static_assert(sizeof(nnIdbeIconDataV0_t) == 0x12060, "");
|
|
|
|
struct nnIdbeHeader_t
|
|
{
|
|
uint8 formatVersion;
|
|
uint8 keyIndex;
|
|
};
|
|
|
|
struct nnIdbeEncryptedIcon_t
|
|
{
|
|
nnIdbeHeader_t header;
|
|
uint8 hashSHA256[32];
|
|
nnIdbeIconDataV0_t iconData;
|
|
};
|
|
|
|
static_assert(offsetof(nnIdbeEncryptedIcon_t, hashSHA256) == 2, "");
|
|
static_assert(offsetof(nnIdbeEncryptedIcon_t, iconData) == 0x22, "");
|
|
static_assert(sizeof(nnIdbeEncryptedIcon_t) == 0x12082);
|
|
|
|
void asyncDownloadIconFile(uint64 titleId, nnIdbeEncryptedIcon_t* iconOut, OSThread_t* thread)
|
|
{
|
|
std::vector<uint8> idbeData = NAPI::IDBE_RequestRawEncrypted(titleId);
|
|
if (idbeData.size() != sizeof(nnIdbeEncryptedIcon_t))
|
|
{
|
|
// icon does not exist or has the wrong size
|
|
cemuLog_force("IDBE: Failed to retrieve icon for title {:016x}", titleId);
|
|
memset(iconOut, 0, sizeof(nnIdbeEncryptedIcon_t));
|
|
coreinit_resumeThread(thread);
|
|
return;
|
|
}
|
|
memcpy(iconOut, idbeData.data(), sizeof(nnIdbeEncryptedIcon_t));
|
|
coreinit_resumeThread(thread);
|
|
}
|
|
|
|
void export_DownloadIconFile(PPCInterpreter_t* hCPU)
|
|
{
|
|
ppcDefineParamTypePtr(encryptedIconData, nnIdbeEncryptedIcon_t, 0);
|
|
ppcDefineParamU64(titleId, 2);
|
|
ppcDefineParamU32(uknR7, 4);
|
|
ppcDefineParamU32(uknR8, 5);
|
|
|
|
auto asyncTask = std::async(std::launch::async, asyncDownloadIconFile, titleId, encryptedIconData, coreinit::OSGetCurrentThread());
|
|
coreinit::OSSuspendThread(coreinit::OSGetCurrentThread());
|
|
PPCCore_switchToScheduler();
|
|
osLib_returnFromFunction(hCPU, 1);
|
|
}
|
|
|
|
static_assert(sizeof(nnIdbeHeader_t) == 0x2, "");
|
|
|
|
static uint8 idbeAesKeys[4 * 16] =
|
|
{
|
|
0x4A,0xB9,0xA4,0x0E,0x14,0x69,0x75,0xA8,0x4B,0xB1,0xB4,0xF3,0xEC,0xEF,0xC4,0x7B,
|
|
0x90,0xA0,0xBB,0x1E,0x0E,0x86,0x4A,0xE8,0x7D,0x13,0xA6,0xA0,0x3D,0x28,0xC9,0xB8,
|
|
0xFF,0xBB,0x57,0xC1,0x4E,0x98,0xEC,0x69,0x75,0xB3,0x84,0xFC,0xF4,0x07,0x86,0xB5,
|
|
0x80,0x92,0x37,0x99,0xB4,0x1F,0x36,0xA6,0xA7,0x5F,0xB8,0xB4,0x8C,0x95,0xF6,0x6F
|
|
};
|
|
|
|
static uint8 idbeAesIv[16] =
|
|
{
|
|
0xA4,0x69,0x87,0xAE,0x47,0xD8,0x2B,0xB4,0xFA,0x8A,0xBC,0x04,0x50,0x28,0x5F,0xA4
|
|
};
|
|
|
|
bool decryptIcon(nnIdbeEncryptedIcon_t* iconInput, nnIdbeIconDataV0_t* iconOutput)
|
|
{
|
|
// check header
|
|
nnIdbeHeader_t* idbeHeader = (nnIdbeHeader_t*)iconInput;
|
|
if (idbeHeader->formatVersion != 0)
|
|
{
|
|
forceLog_printf("idbe header version unknown (%d)", (sint32)idbeHeader->formatVersion);
|
|
return false;
|
|
}
|
|
if (idbeHeader->keyIndex >= 4)
|
|
{
|
|
forceLog_printf("idbe header key count invalid (%d)", (sint32)idbeHeader->keyIndex);
|
|
return false;
|
|
}
|
|
// decrypt data
|
|
uint8 iv[16];
|
|
memcpy(iv, idbeAesIv, sizeof(iv));
|
|
uint8 decryptedSHA256[SHA256_DIGEST_LENGTH];
|
|
AES128_CBC_decrypt_updateIV(decryptedSHA256, iconInput->hashSHA256, sizeof(decryptedSHA256), idbeAesKeys + 16 * idbeHeader->keyIndex, iv);
|
|
AES128_CBC_decrypt((uint8*)iconOutput, (uint8*)&iconInput->iconData, sizeof(iconInput->iconData), idbeAesKeys + 16 * idbeHeader->keyIndex, iv);
|
|
// calculate and compare sha256
|
|
uint8 calculatedSHA256[SHA256_DIGEST_LENGTH];
|
|
SHA256((const unsigned char*)iconOutput, sizeof(nnIdbeIconDataV0_t), calculatedSHA256);
|
|
if (memcmp(calculatedSHA256, decryptedSHA256, SHA256_DIGEST_LENGTH) != 0)
|
|
{
|
|
forceLogDebug_printf("Idbe icon has incorrect sha256 hash");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
struct TGAHeader
|
|
{
|
|
/* +0x00 */ uint8 idLength;
|
|
/* +0x01 */ uint8 colorMap;
|
|
/* +0x02 */ uint8 imageType;
|
|
/* +0x03 */ uint8 colorMap_firstIndex_low;
|
|
/* +0x04 */ uint8 colorMap_firstIndex_high;
|
|
/* +0x05 */ uint8 colorMap_len_low;
|
|
/* +0x06 */ uint8 colorMap_len_high;
|
|
/* +0x07 */ uint8 colorMap_bpp;
|
|
/* +0x08 */ uint16 image_xOrigin;
|
|
/* +0x0A */ uint16 image_yOrigin;
|
|
/* +0x0C */ uint16 image_width;
|
|
/* +0x0E */ uint16 image_height;
|
|
/* +0x10 */ uint8 image_bpp;
|
|
/* +0x11 */ uint8 image_desc;
|
|
};
|
|
|
|
static_assert(offsetof(TGAHeader, colorMap_firstIndex_low) == 0x03);
|
|
static_assert(sizeof(TGAHeader) == 0x12);
|
|
|
|
void export_DecryptIconFile(PPCInterpreter_t* hCPU)
|
|
{
|
|
ppcDefineParamTypePtr(output, nnIdbeIconDataV0_t, 0);
|
|
ppcDefineParamTypePtr(input, nnIdbeEncryptedIcon_t, 1);
|
|
ppcDefineParamU32(platformMode, 2);
|
|
|
|
forceLogDebug_printf("nn_idbe.DecryptIconFile(...)");
|
|
|
|
if (decryptIcon(input, output))
|
|
{
|
|
osLib_returnFromFunction(hCPU, 1);
|
|
return;
|
|
}
|
|
forceLogDebug_printf("Unable to decrypt idbe icon file, using default icon");
|
|
|
|
// return default icon
|
|
TGAHeader* tgaHeader = (TGAHeader*)(output->GetTGAData());
|
|
memset(tgaHeader, 0, sizeof(TGAHeader));
|
|
tgaHeader->imageType = 2;
|
|
|
|
tgaHeader->image_width = 256;
|
|
tgaHeader->image_height = 256;
|
|
tgaHeader->image_bpp = 32;
|
|
tgaHeader->image_desc = (1 << 3);
|
|
|
|
osLib_returnFromFunction(hCPU, 1);
|
|
}
|
|
|
|
void load()
|
|
{
|
|
// this module is used by:
|
|
// Daily Log app
|
|
// Download Manager app
|
|
// and possibly other system titles?
|
|
|
|
osLib_addFunction("nn_idbe", "DownloadIconFile__Q2_2nn4idbeFPvULUsb", export_DownloadIconFile);
|
|
osLib_addFunction("nn_idbe", "DecryptIconFile__Q2_2nn4idbeFPvPCv", export_DecryptIconFile);
|
|
}
|
|
|
|
}
|
|
} |