From 09bd2e4792bd0346991d37da13f7a3e667a8e3c0 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Tue, 4 Apr 2023 02:02:06 +0100 Subject: [PATCH] Lots of work on keychip communication --- src/micetools/dll/devices/smb_ds28cn01.c | 2 + src/micetools/dll/devices/smb_n2.c | 122 +++-- src/micetools/dll/hooks/system.h | 6 +- src/micetools/dll/meson.build | 2 + src/micetools/launcher/main.c | 42 +- src/micetools/lib/ami/amiCrc.c | 13 +- src/micetools/lib/ami/amiCrc.h | 13 +- src/micetools/lib/mice/exe.h | 3 +- src/micetools/lib/mxk/mxk.c | 62 ++- src/micetools/lib/mxk/mxkCrypt.c | 8 +- src/micetools/lib/mxk/mxkCrypt.h | 21 +- src/micetools/lib/mxk/mxkDs.c | 2 +- src/micetools/lib/mxk/mxkN2.c | 556 ++++++++++++++++++----- src/micetools/lib/mxk/mxkN2.h | 63 ++- src/micetools/lib/mxk/mxkSmbus.c | 6 +- src/micetools/lib/mxk/mxkSmbus.h | 4 +- src/micetools/util/micedump/kc_pic.c | 2 +- 17 files changed, 710 insertions(+), 217 deletions(-) diff --git a/src/micetools/dll/devices/smb_ds28cn01.c b/src/micetools/dll/devices/smb_ds28cn01.c index c1449fe..10abda5 100644 --- a/src/micetools/dll/devices/smb_ds28cn01.c +++ b/src/micetools/dll/devices/smb_ds28cn01.c @@ -115,6 +115,8 @@ BOOL smbus_ds28cn01_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) { memcpy(&MAC_INPUT_BUFFER[4], USER_EEPROM[page], DS28CN01_EEPROM_PAGE_SIZE); memcpy(&MAC_INPUT_BUFFER[36], &data[0], 4); MAC_INPUT_BUFFER[40] = 0x40 | page; + // TODO: Where did I get that the unique number is factored in? + // This seems like it would cause sums to calculate wrong! memcpy(&MAC_INPUT_BUFFER[41], UNIQUE_NUMBER, 7); memcpy(&MAC_INPUT_BUFFER[48], &SECRET[4], 4); memcpy(&MAC_INPUT_BUFFER[52], &data[4], 3); diff --git a/src/micetools/dll/devices/smb_n2.c b/src/micetools/dll/devices/smb_n2.c index 8e63a04..0eaf483 100644 --- a/src/micetools/dll/devices/smb_n2.c +++ b/src/micetools/dll/devices/smb_n2.c @@ -13,8 +13,9 @@ LOG_FACILITY _lf = { }; PLOG_FACILITY plf = &_lf; -#define N2_IO_BUFFER 0x1000 +#define N2_IO_BUFFER 512 +BYTE n2_auth_level = 1; BYTE n2_in_buffer[N2_IO_BUFFER]; WORD n2_in_pointer = 0; BYTE n2_out_buffer[N2_IO_BUFFER]; @@ -25,7 +26,7 @@ WORD n2_error_code = 0; BYTE n2_auth_key[20] = { 0x96, 0xed, 0x31, 0xb2, 0x28, 0x71, 0x05, 0xa5, 0xa3, 0x30, 0x54, 0x0f, 0x25, 0xbe, 0xd8, 0x51, 0xa5, 0xc8, 0x36, 0x21 }; -BYTE n2_session_nonce[20]; +BYTE n2_session_salt[20]; struct { BYTE key[16]; BYTE iv[16]; @@ -67,24 +68,26 @@ typedef struct { } N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO; #pragma pack(pop) -N2_KEYCHIP_INFO n2_keychip_info = { .m_KeyId = KEY_ID, - .m_Appboot = { - .m_Format = 1, - .m_GameId = GAME_ID, - .m_Region = 0xff, - .m_ModelType = 2, - .m_SystemFlag = 0x24, - .m_PlatformId = HW_ID, - .m_DvdFlag = 1, - .m_NetworkAddr = - (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), - } }; +N2_KEYCHIP_INFO n2_keychip_info = { + .m_KeyId = KEY_ID, + .m_Appboot = { + .m_Format = 1, + .m_GameId = GAME_ID, + .m_Region = 0xff, + .m_ModelType = 2, + .m_SystemFlag = 0x24, + .m_PlatformId = HW_ID, + .m_DvdFlag = 1, + .m_NetworkAddr = + (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), + }, +}; WORD n2_enable_session(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { *nOut = 20; - RAND_bytes(n2_session_nonce, sizeof n2_session_nonce); - memcpy(dataOut, n2_session_nonce, sizeof n2_session_nonce); + RAND_bytes(n2_session_salt, sizeof n2_session_salt); + memcpy(dataOut, n2_session_salt, sizeof n2_session_salt); log_misc(plf, "Session open"); return N2_SUCCESS; @@ -97,6 +100,8 @@ WORD n2_set_auth_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn, pt, sizeof pt); memcpy(n2_auth_key, pt, sizeof n2_auth_key); + n2_auth_level = 2; + return N2_SUCCESS; } WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { @@ -108,11 +113,13 @@ WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) memcpy(n2_enc_key.key, pt, sizeof n2_enc_key.key); memcpy(n2_enc_key.iv, pt + sizeof n2_enc_key.key, sizeof n2_enc_key.iv); + n2_auth_level = 3; + return N2_SUCCESS; } WORD n2_get_auth_level(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) { *nOut = 1; - dataOut[0] = 3; // TODO: ? + dataOut[0] = n2_auth_level; log_misc(plf, "Auth level get"); return N2_SUCCESS; } @@ -241,6 +248,9 @@ void n2_install_commands() { } void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { + EVP_MD_CTX* ctx; + unsigned int outlen; + n2_install_commands(); log_info(plf, "Processing command: %04x/%04x (%d bytes)", tag, command, paramSize); @@ -257,16 +267,50 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { WORD expectedExtraData = N2_CHECKSUM_SIZE + N2_HEADER_SIZE; if (tag == N2_TAG_RQU_AUTH_COMMAND) expectedExtraData += N2_AUTH_SIZE; - n2_command handler = N2_COMMANDS[command & 0xff]; - if (handler.handler == NULL) { - result = N2_BAD_ORDINAL; - } else if (handler.tag != tag) { - result = N2_BAD_TAG; - } else if (handler.paramSize + expectedExtraData != paramSize) { - result = N2_BAD_DATASIZE; + unsigned char sha1sum[20]; + ctx = EVP_MD_CTX_create(); + EVP_DigestInit(ctx, EVP_sha1()); + EVP_DigestUpdate(ctx, n2_in_buffer, N2_HEADER_SIZE + paramSize - expectedExtraData); + EVP_DigestFinal_ex(ctx, sha1sum, &outlen); + EVP_MD_CTX_destroy(ctx); + + HMAC_CTX hmac_ctx; + if (tag == N2_TAG_RQU_COMMAND) { + if (memcmp(sha1sum, n2_in_buffer + paramSize - N2_CHECKSUM_SIZE, N2_CHECKSUM_SIZE) != 0) { + log_error(plf, "SHA1Sum chek failed!"); + result = N2_SUMFAIL; + } } else { - result = (*handler.handler)(paramSize, n2_in_buffer + N2_HEADER_SIZE, - n2_out_buffer + N2_HEADER_SIZE, &bodyLength); + unsigned char nonce[20]; + memcpy_s(nonce, 20, n2_in_buffer + paramSize - N2_CHECKSUM_SIZE - N2_AUTH_SIZE, 20); + unsigned char hmac[20]; + + HMAC_CTX_init(&hmac_ctx); + HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL); + HMAC_Update(&hmac_ctx, sha1sum, N2_CHECKSUM_SIZE); + HMAC_Update(&hmac_ctx, n2_session_salt, N2_CHECKSUM_SIZE); + HMAC_Update(&hmac_ctx, nonce, N2_CHECKSUM_SIZE); + HMAC_Final(&hmac_ctx, hmac, &outlen); + HMAC_CTX_cleanup(&hmac_ctx); + + if (memcmp(hmac, n2_in_buffer + paramSize - N2_AUTH_SIZE, N2_AUTH_SIZE) != 0) { + log_error(plf, "HMAC check failed!"); + result = N2_AUTHFAIL; + } + } + + if (result == N2_SUCCESS) { + n2_command handler = N2_COMMANDS[command & 0xff]; + if (handler.handler == NULL) { + result = N2_BAD_ORDINAL; + } else if (handler.tag != tag) { + result = N2_BAD_TAG; + } else if (handler.paramSize + expectedExtraData != paramSize) { + result = N2_BAD_DATASIZE; + } else { + result = (*handler.handler)(paramSize, n2_in_buffer + N2_HEADER_SIZE, + n2_out_buffer + N2_HEADER_SIZE, &bodyLength); + } } WORD paramSizeOut = bodyLength + expectedExtraData; @@ -274,9 +318,6 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { ((PWORD)n2_out_buffer)[1] = fix_endian(paramSizeOut); ((PWORD)n2_out_buffer)[2] = fix_endian(result); - EVP_MD_CTX* ctx; - unsigned int outlen; - WORD fixed_command = fix_endian(command); // Calculate a SHA1 of the packet, and append it @@ -291,26 +332,16 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { // At this point: packet = header | data | SHA(header | command | data) if (tag == N2_TAG_RQU_AUTH_COMMAND) { - BYTE crypto_buffer[N2_CHECKSUM_SIZE]; - - // Calculate a new SHA1 of the packet, including the SHA1 we just appeneded - // crypto_buffer = SHA1(header | command | data) - ctx = EVP_MD_CTX_create(); - EVP_DigestInit(ctx, EVP_sha1()); - EVP_DigestUpdate(ctx, n2_out_buffer, N2_HEADER_SIZE); - EVP_DigestUpdate(ctx, &fixed_command, 2); - EVP_DigestUpdate(ctx, n2_out_buffer + N2_HEADER_SIZE, bodyLength); - EVP_DigestFinal_ex(ctx, crypto_buffer, &outlen); - EVP_MD_CTX_destroy(ctx); + // TODO: Further investigation might be needed here. + // The following code checks out against mxkeychip, but repeating the + // packet sum twice feels wrong. // Calculate an HMAC, and append it - HMAC_CTX hmac_ctx; HMAC_CTX_init(&hmac_ctx); HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL); // SHA1(header | command | data) - HMAC_Update(&hmac_ctx, crypto_buffer, sizeof crypto_buffer); - // SHA1(header | auth | data) + HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE); HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE); // Request nonce HMAC_Update(&hmac_ctx, n2_in_buffer + paramSize - N2_AUTH_SIZE - N2_CHECKSUM_SIZE, @@ -319,6 +350,10 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) { HMAC_Final(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength + N2_CHECKSUM_SIZE, &outlen); HMAC_CTX_cleanup(&hmac_ctx); + + // Update session salt + memcpy_s(n2_session_salt, sizeof n2_session_salt, + n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE); } } @@ -376,6 +411,7 @@ BOOL smbus_N2_write(ich9_cmd_t cmd, WORD code, BYTE nbytes, LPBYTE data) { } BOOL smbus_N2_read(ich9_cmd_t cmd, WORD code, BYTE nbytes, BYTE* data) { + // TODO: Unaligned mxk reads poke into this for the final byte! log_error(plf, "Unsupported read mode: %01x (%02x)", cmd, code); return FALSE; } diff --git a/src/micetools/dll/hooks/system.h b/src/micetools/dll/hooks/system.h index 930088d..0e0989e 100644 --- a/src/micetools/dll/hooks/system.h +++ b/src/micetools/dll/hooks/system.h @@ -2,7 +2,9 @@ #include "../common.h" -FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName); -HMODULE (*TrueGetModuleHandleA)(LPCSTR lpModuleName); +FARPROC(WINAPI* TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName); +HMODULE(WINAPI* TrueGetModuleHandleA)(LPCSTR lpModuleName); +HMODULE(WINAPI* TrueLoadLibraryA)(LPCSTR lpLibFileName); +HMODULE(WINAPI* TrueLoadLibraryW)(LPCWSTR lpLibFileName); void hook_system(); diff --git a/src/micetools/dll/meson.build b/src/micetools/dll/meson.build index a22c57c..c651727 100644 --- a/src/micetools/dll/meson.build +++ b/src/micetools/dll/meson.build @@ -8,6 +8,8 @@ shared_library( name_prefix: '', vs_module_defs: 'mice.def', sources: [ + 'amvStub/amv.c', + 'util/misc.c', 'util/hook.c', 'util/path.c', diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index 4509154..e161e19 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -9,7 +9,9 @@ bool debug_wait = false; int boot_delay = 0; char exe_name[MAX_PATH + 1] = ""; -char commandline[MAX_PATH + 1] = ""; + +size_t nCommandLine = 256; +char* commandLine = NULL; static void print_help(char* exe) { log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe); @@ -69,10 +71,13 @@ static bool parse_cmdline(int argc, char* argv[]) { return false; } } else { - if (commandline[0] == 0) - snprintf(commandline, sizeof commandline, "%s", argv[i]); - else - snprintf(commandline, sizeof commandline, "%s %s", commandline, argv[i]); + size_t newLength = nCommandLine + 1 + strlen(argv[i]) + 1; + if (newLength > nCommandLine) { + nCommandLine = newLength; + commandLine = realloc(commandLine, nCommandLine); + } + strcat_s(commandLine, nCommandLine, " "); + strcat_s(commandLine, nCommandLine, argv[i]); } } return true; @@ -176,6 +181,13 @@ int main(int argc, char* argv[]) { log_info(plfBoot, "Micetools version: %s", MICE_VERSION); + commandLine = malloc(nCommandLine); + if (commandLine == NULL) { + log_error(plfBoot, "Fatal: Failed to malloc(commandLine)"); + return terminate(-1); + } + commandLine[0] = '\0'; + CHAR workDir[MAX_PATH + 1]; GetCurrentDirectory(MAX_PATH, workDir); log_info(plfBoot, "Current directory: %s", workDir); @@ -203,7 +215,7 @@ int main(int argc, char* argv[]) { spawn_pcp_processes(); - log_info(plfBoot, "exec: %s %s", exe_name, commandline); + log_info(plfBoot, "exec: %s %s", exe_name, commandLine); char micepath[MAX_PATH + 1]; if (!locate_library(micepath, MAX_PATH + 1)) { @@ -216,18 +228,30 @@ int main(int argc, char* argv[]) { info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info); + size_t nFullCommandLine = nCommandLine + strlen(exe_name) + 1; + char* fullCommandLine = malloc(nFullCommandLine); + snprintf(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine); + free(commandLine); + char* extra_injections = MiceConfig.launcher.inject; PROCESS_INFORMATION pi; - if (!start_and_inject(hJob, exe_name, commandline, micepath, debug_wait, boot_delay, - extra_injections, 0, &pi)) + if (!start_and_inject(hJob, exe_name, fullCommandLine, micepath, debug_wait, boot_delay, + extra_injections, 0, &pi)) { + free(fullCommandLine); return terminate(-1); + } + free(fullCommandLine); SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE); if (FAILED(WaitForSingleObject(pi.hProcess, INFINITE))) { log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError()); } else { - log_info(plfBoot, "Shutting down"); + DWORD exitCode; + if (GetExitCodeProcess(pi.hProcess, &exitCode)) + log_info(plfBoot, "Shutting down (ret:%d)", exitCode); + else + log_info(plfBoot, "Shutting down (failed to get exit code)"); CloseHandle(pi.hProcess); } return terminate(0); diff --git a/src/micetools/lib/ami/amiCrc.c b/src/micetools/lib/ami/amiCrc.c index bdc2516..475bb80 100644 --- a/src/micetools/lib/ami/amiCrc.c +++ b/src/micetools/lib/ami/amiCrc.c @@ -4,9 +4,9 @@ AM_LIB_C_HEADER(amiCrc, AMI_CRC) -void amiCrc32RCreateTable(unsigned int *table) { +void amiCrc32RCreateTable(uint32_t *table) { for (int i = 0; i < 256; i++) { - unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL; + uint32_t value = (~i & 1) - 1 & CRC32_POLYNOMIAL; value = ((i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; value = ((i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; value = ((i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; @@ -18,13 +18,12 @@ void amiCrc32RCreateTable(unsigned int *table) { } } -unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data, - unsigned int initial) { - unsigned int value = ~initial; +uint32_t amiCrc32RGet(uint32_t *table, int length, void *data, uint32_t initial) { + uint32_t value = ~initial; while (length > 0) { - value = value >> 8 ^ table[(data[0] ^ value) & 0xff]; + value = value >> 8 ^ table[(((unsigned char *)data)[0] ^ value) & 0xff]; length += -1; - data++; + ((unsigned char *)data)++; } return ~value; } diff --git a/src/micetools/lib/ami/amiCrc.h b/src/micetools/lib/ami/amiCrc.h index 5922ffc..b48d98d 100644 --- a/src/micetools/lib/ami/amiCrc.h +++ b/src/micetools/lib/ami/amiCrc.h @@ -1,19 +1,20 @@ #pragma once +#include + #include "../_am.h" AM_LIB_H_HEADER(amiCrc, AMI_CRC) typedef struct _AMI_CRC { - unsigned int m_init; - unsigned int m_table[256]; + uint32_t m_init; + uint32_t m_table[256]; } AMI_CRC; -void amiCrc32RCreateTable(unsigned int *table); -unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data, - unsigned int initial); +void amiCrc32RCreateTable(uint32_t *table); +uint32_t amiCrc32RGet(uint32_t *table, int length, void *data, uint32_t initial); -#define amiCrc32RInit() \ +#define amiCrc32RInit() \ do { \ if (!amiCrc.m_init) { \ amiCrc32RCreateTable(amiCrc.m_table); \ diff --git a/src/micetools/lib/mice/exe.h b/src/micetools/lib/mice/exe.h index 7e9b407..ebc4938 100644 --- a/src/micetools/lib/mice/exe.h +++ b/src/micetools/lib/mice/exe.h @@ -3,6 +3,7 @@ #include BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, - DWORD delay, LPCSTR extra_injections, DWORD flags, LPPROCESS_INFORMATION lpProcessInformation); + DWORD delay, LPCSTR extra_injections, DWORD flags, + LPPROCESS_INFORMATION lpProcessInformation); #define MICELIB "mice.dll" diff --git a/src/micetools/lib/mxk/mxk.c b/src/micetools/lib/mxk/mxk.c index c654e10..e75dd00 100644 --- a/src/micetools/lib/mxk/mxk.c +++ b/src/micetools/lib/mxk/mxk.c @@ -177,7 +177,7 @@ BOOL mxkNvramRead(unsigned short addr, unsigned char blocks, unsigned char* data } bool mxkValidString(const char* string, unsigned int length) { - for (int i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) { char c = string[i]; if (isalnum(c)) continue; if (c != '.' && c != '_' && c != '-' && c != ':' && c != '@' && c != '%' && c != '/' && @@ -187,7 +187,52 @@ bool mxkValidString(const char* string, unsigned int length) { return true; } -MXK_STATUS mxkInit() { +MXK_STATUS mxkGetKeychipIdFromN2(void) { + N2KeychipId_t kcId; + + memset(&kcId, 0, sizeof kcId); + int err = mxkN2CmdReadKeychipID(&kcId); + if (err != 0) { + amiDebugLog("Error: mxkN2CmdReadKeychipID().ErrorCode %d", err); + return MXK_STATUS_ERROR; + } + + amiCrc32RInit(); + uint32_t crcCalc = amiCrc32RCalc((sizeof kcId.m_AppBoot) - 4, (LPBYTE)&kcId.m_AppBoot + 4, 0); + if (crcCalc != kcId.m_AppBoot.m_Crc) { + amiDebugLog("Error AppBootInfo CRC!!!"); + return MXK_STATUS_ERROR; + } + + crcCalc = amiCrc32RCalc(sizeof kcId - 4, (LPBYTE)&kcId + 4, 0); + if (crcCalc != kcId.m_Crc) { + amiDebugLog("Error KeychipID CRC!!!"); + return MXK_STATUS_ERROR; + } + + // N2 keychip ID is a smaller, more compact, format than normal appboot. Restructure it to match + // before committing it to memory! + unsigned char keyId[16]; + appboot_t appboot; + + memcpy_s(keyId, sizeof keyId, kcId.m_KeyId, sizeof kcId.m_KeyId); + memcpy_s(&appboot, sizeof appboot, &kcId.m_AppBoot, + sizeof kcId.m_AppBoot - sizeof kcId.m_AppBoot.m_Seed); + memcpy_s(appboot.seed, sizeof appboot.seed, kcId.m_AppBoot.m_Seed, + sizeof kcId.m_AppBoot.m_Seed); + + printf("Got N2 key ID: %.16s\n", keyId); + printf("Got N2 game ID: %.4s\n", kcId.m_AppBoot.m_GameId); + + // ...but we're not actually committing it to memory at the moment! + // memcpy_s(&APPBOOT, 256, &appboot, sizeof appboot); + // memcpy_s(N2_KEYID, 16, keyId, 16); + // DAT_004adc95 = 0; + // DAT_004adda4 = 0; + return MXK_STATUS_OK; +} + +MXK_STATUS mxkInit(void) { mxkVersionDirty = true; AppBoot.m_cacheDirty = true; @@ -203,7 +248,6 @@ MXK_STATUS mxkInit() { amiDebugLog("Error mxkExchengeAesKey!!"); return MXK_STATUS_ERROR; } - // TODO: N2 if (mxkSmbusInit() != MXK_STATUS_OK) { amiDebugLog("Error mxkSmbusInit!!"); return MXK_STATUS_ERROR; @@ -226,9 +270,15 @@ MXK_STATUS mxkInit() { // eeprom_playcount(); } - // TODO: - mxkN2CmdSetDeviceInfo(); - mxkN2Authentication(); + if (mxkN2Init() != 0) { + amiDebugLog("Error mxkN2Init!!"); + return MXK_STATUS_ERROR; + } + + if (mxkGetKeychipIdFromN2() != 0) { + amiDebugLog("Error mxkGetKeychipIdFromN2!!"); + return MXK_STATUS_ERROR; + } return MXK_STATUS_OK; } diff --git a/src/micetools/lib/mxk/mxkCrypt.c b/src/micetools/lib/mxk/mxkCrypt.c index 38a8bca..5b4e678 100644 --- a/src/micetools/lib/mxk/mxkCrypt.c +++ b/src/micetools/lib/mxk/mxkCrypt.c @@ -1,8 +1,8 @@ #include "mxkCrypt.h" #include -#include #include +#include // These three should be initialised to null, and populated by mxkCryptInit, but we already know // their values and aren't trying to hide them from anyone! mxkCryptInit is still fully implemented, @@ -153,8 +153,8 @@ void mxkSwapKeys() { memcpy(KEY_S, temp, 16); } -MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, - unsigned char* ct, const unsigned char* pt, size_t nbytes) { +MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, void* ct, + const void* pt, size_t nbytes) { if (key == NULL || iv == NULL || ct == NULL || pt == NULL) { amiDebugLog("Error: Invalid param."); return MXK_STATUS_INVALID_PARAM; @@ -173,7 +173,7 @@ MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned cha } MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv, - const unsigned char* ct, unsigned char* pt, size_t nbytes) { + const void* ct, void* pt, size_t nbytes) { if (key == NULL || iv == NULL || ct == NULL || pt == NULL) { amiDebugLog("Error: Invalid param."); return MXK_STATUS_INVALID_PARAM; diff --git a/src/micetools/lib/mxk/mxkCrypt.h b/src/micetools/lib/mxk/mxkCrypt.h index cffc1b0..2105a18 100644 --- a/src/micetools/lib/mxk/mxkCrypt.h +++ b/src/micetools/lib/mxk/mxkCrypt.h @@ -4,23 +4,34 @@ #include "../ami/ami.h" #include "mxkDefs.h" +#define SHA1_SUM_SIZE 20 +#define HMAC_SUM_SIZE 20 +#define HMAC_KEY_SIZE 20 + +typedef char Sha1Sum_t[SHA1_SUM_SIZE]; +typedef char (*PSha1Sum_t)[SHA1_SUM_SIZE]; +typedef char HmacSum_t[HMAC_SUM_SIZE]; +typedef char (*PHmacSum_t)[HMAC_SUM_SIZE]; +typedef char HmacKey_t[HMAC_SUM_SIZE]; +typedef char (*PHmacKey_t)[HMAC_SUM_SIZE]; + void mxkSetKeyS(unsigned char* key_s); void mxkSetKeyR(unsigned char* key_r); void mxkSwapKeys(); MXK_STATUS mxkCryptInit(void); -int mxkCryptCalcHashWithHmacSha1(void* key, unsigned char* md, size_t* nbuffer, +int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer, unsigned char* buffer, size_t nin); -void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, unsigned char* sum); +void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, PSha1Sum_t sum); void mxkCryptCreateDigest(void); void mxkCryptRsaSignVerify(void); MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv, - const unsigned char* ct, unsigned char* pt, size_t nbytes); -MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, - unsigned char* pt, const unsigned char* ct, size_t nbytes); + const void* ct, void* pt, size_t nbytes); +MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, void* ct, + const void* pt, size_t nbytes); MXK_STATUS mxkCryptDecryptData(const unsigned char* ct, unsigned char* pt); MXK_STATUS mxkCryptEncryptData(unsigned char* ct, const unsigned char* pt); diff --git a/src/micetools/lib/mxk/mxkDs.c b/src/micetools/lib/mxk/mxkDs.c index ab10592..9141200 100644 --- a/src/micetools/lib/mxk/mxkDs.c +++ b/src/micetools/lib/mxk/mxkDs.c @@ -57,7 +57,7 @@ int mxkDsKeychipComputeMac(unsigned char page, void *challenge, unsigned char *m Sleep(16); status = mxkDsWaitNotBusy(&INT_004ab34c); if (status == 0) { - if (!mxkSmbusI2CReadBlock(KC_DS_ADDRESS, DS28CN01_REG_MAC, mac, 20)) { + if (mxkSmbusI2CReadBlock(KC_DS_ADDRESS, DS28CN01_REG_MAC, mac, 20) != 0) { amiDebugLog("Error mxkSmbusI2CReadBlock()!!!"); error = -8; } diff --git a/src/micetools/lib/mxk/mxkN2.c b/src/micetools/lib/mxk/mxkN2.c index 5fc2958..cf9fa47 100644 --- a/src/micetools/lib/mxk/mxkN2.c +++ b/src/micetools/lib/mxk/mxkN2.c @@ -1,3 +1,5 @@ +#include "mxkN2.h" + #include #include #include @@ -7,30 +9,47 @@ #include "mxkCrypt.h" #include "mxkSmbus.h" -#define N2_ADDR 0x30 - typedef struct { unsigned char m_Key[16]; unsigned char m_IV[16]; } AESKey_t; +#pragma pack(push, 1) typedef struct { unsigned short m_Tag; unsigned short m_ParamSize; unsigned short m_Command; - unsigned char m_Body[506]; + unsigned char m_Body[N2_DATA_MAX]; } N2Packet_t; +typedef struct { + union { + struct { + Sha1Sum_t m_ShaSum; + } rqu; + struct { + N2Nonce_t m_Nonce; + HmacSum_t m_Hmac; + } sign; + }; +} N2PacketFooter_t; +#pragma pack(pop) BOOL MXK_HAS_INIT = FALSE; BOOL MXK_N2_INIT = FALSE; +#define CheckN2Init \ + do { \ + if (!MXK_N2_INIT) { \ + amiDebugLog("Error: Uninitialized."); \ + return -3; \ + } \ + } while (0); typedef struct { unsigned char m_Addr; - unsigned char m_HmacKey[20]; + HmacKey_t m_HmacKey; AESKey_t m_AESKey; - unsigned char m_AuthKey[20]; - unsigned char m_EncKey[16]; - unsigned char Unk[16]; - unsigned char m_HmacOut[20]; + N2AuthKey_t m_AuthKey; + AESKey_t m_EncKey; + HmacSum_t m_HmacSalt; } N2DeviceInfo_t; N2DeviceInfo_t N2DeviceInfo; @@ -41,14 +60,16 @@ unsigned char N2_KEY_HMAC[2][20] = { 0x1d, 0x1e, 0x1f, 0x11, 0xee, 0xb0, 0xf4, 0xd4, 0x20, 0x24 } }; -AESKey_t N2_KEY_AES[2] = { { { 0xd7, 0xf6, 0x86, 0xfb, 0x63, 0x44, 0xff, 0xa5, 0x60, 0x9d, 0x4e, - 0xf0, 0x18, 0xe9, 0x45, 0xb4 }, - { 0x12, 0x6c, 0xb1, 0xdb, 0x9e, 0x00, 0x8c, 0xc6, 0xae, 0xa1, 0x73, - 0xec, 0xe7, 0x2f, 0x5a, 0xc4 } }, - { { 0xa1, 0x1a, 0xc4, 0x4d, 0xcd, 0x48, 0x4f, 0xed, 0x70, 0xcc, 0x3f, - 0x5d, 0x94, 0x5b, 0xbe, 0xb3 }, - { 0x9c, 0x5c, 0xba, 0x7f, 0xb0, 0x15, 0xc7, 0x69, 0xcb, 0xb4, 0x41, - 0x19, 0x97, 0x2b, 0x45, 0x9f } } }; +AESKey_t N2_KEY_AES[2] = { + { { 0xd7, 0xf6, 0x86, 0xfb, 0x63, 0x44, 0xff, 0xa5, 0x60, 0x9d, 0x4e, 0xf0, 0x18, 0xe9, 0x45, + 0xb4 }, + { 0x12, 0x6c, 0xb1, 0xdb, 0x9e, 0x00, 0x8c, 0xc6, 0xae, 0xa1, 0x73, 0xec, 0xe7, 0x2f, 0x5a, + 0xc4 } }, + { { 0xa1, 0x1a, 0xc4, 0x4d, 0xcd, 0x48, 0x4f, 0xed, 0x70, 0xcc, 0x3f, 0x5d, 0x94, 0x5b, 0xbe, + 0xb3 }, + { 0x9c, 0x5c, 0xba, 0x7f, 0xb0, 0x15, 0xc7, 0x69, 0xcb, 0xb4, 0x41, 0x19, 0x97, 0x2b, 0x45, + 0x9f } }, +}; int mxkN2CmdInit(void) { if (MXK_N2_INIT) { @@ -65,7 +86,7 @@ int mxkN2CmdSetDeviceInfo(void) { if (mxkN2CmdInit() != 0) return -5; - unsigned char hmacKey[20]; + HmacKey_t hmacKey; AESKey_t aesKey; for (int i = 0; i < sizeof hmacKey; i++) hmacKey[i] = N2_KEY_HMAC[0][i] ^ N2_KEY_HMAC[1][i]; for (int i = 0; i < sizeof aesKey.m_Key; i++) @@ -88,17 +109,18 @@ int mxkN2CmdSetDeviceInfo(void) { } // TODO: Better name -void _randomBytes(unsigned char *buf, int nbytes) { +void _randomBytes(void *buf, int nbytes) { FILETIME fileTime; amtime_t amTime; for (int i = 0; i < nbytes; i++) { amiTimerGet(&amTime); GetSystemTimeAsFileTime(&fileTime); - buf[i] = (amTime.microseconds ^ fileTime.dwLowDateTime ^ fileTime.dwHighDateTime) & 0xff; + ((unsigned char *)buf)[i] = + (amTime.microseconds ^ fileTime.dwLowDateTime ^ fileTime.dwHighDateTime) & 0xff; } } -void mxkN2GetPacketNonce(unsigned char *nonce) { _randomBytes(nonce, 20); } +void mxkN2GetPacketNonce(PN2Nonce_t nonce) { _randomBytes(nonce, 20); } int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams, va_list args) { @@ -110,10 +132,11 @@ int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numSt size_t offset = 0; size_t max = *count; for (size_t i = 0; i < numStreams && i < max; i++) { - size_t n = va_arg(args, size_t); unsigned char *b = va_arg(args, unsigned char *); - if (i + n > max) n = max - i; - memcpy(out + offset, b, i); + size_t n = va_arg(args, size_t); + if (offset + n > max) n = max - offset; + memcpy(out + offset, b, n); + offset += n; } *count = offset; @@ -129,46 +152,49 @@ void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned va_end(args); } -void mxkN2UtilSha1Many(unsigned char *sum, int numStreams, ...) { +void mxkN2UtilSha1Many(PSha1Sum_t sum, int numStreams, ...) { va_list args; va_start(args, numStreams); - unsigned char sumout[20]; + Sha1Sum_t sumout; unsigned char concatinated[0x200]; size_t size = sizeof concatinated; mxkN2UtilVCatenateData(concatinated, &size, numStreams, args); - mxkCryptCalcHashWithSha1(concatinated, size, sumout); - memcpy_s(sum, 20, sumout, 20); + mxkCryptCalcHashWithSha1(concatinated, size, &sumout); + memcpy_s(sum, sizeof *sum, sumout, sizeof sumout); va_end(args); } -int mxkN2UtilHmacPacket(void *val1, unsigned char *sha1, void *nonce, void *key, - unsigned char *hash_out) { - unsigned char hash[20]; - unsigned char data_in[60]; +int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t nonce, PHmacKey_t key, + PHmacSum_t computedHash) { + HmacSum_t hash; + unsigned char data_in[sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce]; - size_t count = 60; - size_t nout = 20; - mxkN2UtilCatenateData(data_in, &count, 3, val1, 20, sha1, 20, nonce, 20); + size_t count = sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce; + size_t nout = HMAC_SUM_SIZE; + mxkN2UtilCatenateData(data_in, &count, 3, packetSha, sizeof *packetSha, hmacSalt, + sizeof *hmacSalt, nonce, sizeof *nonce); - int iVar1 = mxkCryptCalcHashWithHmacSha1(key, hash, &nout, data_in, count); - if (iVar1 != -2 && nout == 20) { - memcpy(hash_out, hash, 20); - return 0; - } - return -2; + int err = mxkCryptCalcHashWithHmacSha1(key, &hash, &nout, data_in, count); + if (err == -2 || nout != HMAC_SUM_SIZE) return -2; + + memcpy_s(computedHash, sizeof *computedHash, hash, HMAC_SUM_SIZE); + return 0; } -int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nbytes, +int mxkN2CmdWriteData(unsigned char addr, void *data, unsigned short nbytes, unsigned short *nbytesOut) { unsigned int ptr_; unsigned char nstep; int status; unsigned short position; - if (mxkSmbusRequestMutex() != 0) return -6; + if (mxkSmbusRequestMutex() != 0) { + amiDebugLog("Error: mxkSmbusRequestMutex"); + return -6; + } status = 0; position = 0; @@ -178,14 +204,14 @@ int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nb if ((int)(nbytes - ptr_) < 5) { nstep = (byte)(nbytes - ptr_); if (nstep != 1) goto LAB_0040ae51; - status = mxkSmbusWriteByte(addr, 0xcc, data[ptr_]); + status = mxkSmbusWriteByte(addr, 0xcc, ((unsigned char *)data)[ptr_]); } else { nstep = 4; LAB_0040ae51: - status = mxkSmbusI2CWriteBlock(addr, 0xcc, data + ptr_, nstep); + status = mxkSmbusI2CWriteBlock(addr, 0xcc, &((unsigned char *)data)[ptr_], nstep); } if (status != 0) { - amiDebugLog("Error: Data write failed. Position %d. ErrorCode %d.\n", position, + amiDebugLog("Error: Data write failed. Position %d. ErrorCode %d.", position, status); break; @@ -196,118 +222,410 @@ int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nb } *nbytesOut = position; - if (!mxkSmbusReleaseMutex()) return -6; + if (mxkSmbusReleaseMutex() != 0) { + amiDebugLog("Error: mxkSmbusReleaseMutex"); + return -6; + } return 0; } -int mxkN2CmdWriteCommand(unsigned char *param_1, unsigned char *packet, unsigned short tag, - unsigned short command, unsigned char *auth_key, unsigned char addr, - void *data, size_t nbytes) { - int iVar1; - unsigned short real_tag; - unsigned short paramsize; - - N2Packet_t cmd; +int mxkN2CmdWriteCommand(PN2Nonce_t requestNonce, PHmacSum_t hmacSalt, N2Tag_t tag, + N2Command_t command, PHmacKey_t hmacKey, unsigned char addr, + N2Byte_t *data, unsigned short nbytes) { + Sha1Sum_t sha1sum; + N2Packet_t packet; + int ret; if (data == NULL && nbytes != 0) return -2; - memset(&cmd, 0, 0x200); - paramsize = (tag == N2_TAG_RQU_COMMAND ? 20 : 0) + 0x14 + (nbytes & 0xffff) + 6; - real_tag = (tag != N2_TAG_RQU_COMMAND) + 0xc1; - cmd.m_Tag = real_tag * 0x100 | real_tag >> 8; - cmd.m_ParamSize = (unsigned short)paramsize << 8 | (unsigned short)paramsize >> 8; - cmd.m_Command = command << 8 | command >> 8; - if (data != NULL) memcpy_s(cmd.m_Body, sizeof cmd.m_Body, data, nbytes); + N2PacketFooter_t *footer = (N2PacketFooter_t *)(packet.m_Body + nbytes); - // SHA1(header | data) - unsigned char packet_sha[20]; - mxkN2UtilSha1Many(packet_sha, 1, &cmd, nbytes + 6); + ZeroMemory(&packet, sizeof packet); + unsigned short paramsize = + N2_HEADER_SIZE + nbytes + + (tag == N2_TAG_RQU_COMMAND ? N2_FOOTER_RQU_SIZE : N2_FOOTER_SIGN_SIZE); + + N2Tag_t realTag = tag == N2_TAG_RQU_COMMAND ? N2_TAG_RQU_COMMAND : N2_TAG_RQU_AUTH_COMMAND; + packet.m_Tag = _byteswap_ushort(realTag); + packet.m_ParamSize = _byteswap_ushort(paramsize); + packet.m_Command = _byteswap_ushort(command); + + if (data != NULL) memcpy_s(packet.m_Body, sizeof packet.m_Body, data, nbytes); + + mxkN2UtilSha1Many(&sha1sum, 1, &packet, nbytes + N2_HEADER_SIZE); if (tag == N2_TAG_RQU_COMMAND) { - memcpy(cmd.m_Body, packet_sha, 20); + memcpy_s(footer->rqu.m_ShaSum, sizeof footer->rqu.m_ShaSum, sha1sum, sizeof sha1sum); } else { - unsigned char nonce[20]; - mxkN2GetPacketNonce(nonce); - memcpy(cmd.m_Body + nbytes, nonce, 20); - mxkN2UtilHmacPacket(packet_sha, param_1, nonce, auth_key, cmd.m_Body + nbytes + 20); + if (requestNonce == NULL || hmacKey == NULL) return -2; - puts("Dodgy HMAC"); - exit(1); + mxkN2GetPacketNonce(requestNonce); + memcpy_s(footer->sign.m_Nonce, sizeof footer->sign.m_Nonce, requestNonce, + sizeof *requestNonce); + + mxkN2UtilHmacPacket(&sha1sum, hmacSalt, &footer->sign.m_Nonce, hmacKey, + &footer->sign.m_Hmac); } - unsigned short nWrote; - iVar1 = mxkN2CmdWriteData(addr, (unsigned char *)&cmd, paramsize, &nWrote); - if (iVar1 == 0) { - iVar1 = 0; - } else { - amiDebugLog("Error: Data write failed. ErrorCode %d.", iVar1); - iVar1 = -8; + unsigned short nBytesOut; + ret = mxkN2CmdWriteData(addr, &packet, paramsize, &nBytesOut); + if (ret != 0) { + amiDebugLog("Error: Data write failed. ErrorCode %d.", ret); + return -8; } - return iVar1; + return 0; +} + +int mxkN2CmdReadData(unsigned char addr, N2Packet_t *lpPacket, unsigned short nReadSize, + unsigned short *lpBytesRead) { + int err; + *lpBytesRead = 0; + + if (nReadSize < 4 || lpPacket == NULL) { + amiDebugLog("Error: Invalid param."); + return -2; + } + if (mxkSmbusRequestMutex() != 0) return -6; + + unsigned char *buffer = (unsigned char *)lpPacket; + + // Read until m_ParamSize + err = mxkSmbusI2CReadBlock(addr, 0xc3, buffer, 4); + + unsigned short readPosition = 4; + if (err == 0) { + unsigned short paramSize = _byteswap_ushort(lpPacket->m_ParamSize); + if (nReadSize < paramSize - 4) { + amiDebugLog("mxkSmbusI2CReadBlock data : %04X %04X", lpPacket->m_Tag, + lpPacket->m_ParamSize); + amiDebugLog("Error: Data size is too small.(readSize:%04X, m_paramSize:%04X)", + nReadSize, (lpPacket->m_ParamSize << 8 | lpPacket->m_ParamSize >> 8) - 4); + return -11; + } + + if (4 < paramSize) { + while (readPosition < paramSize) { + unsigned short blockSize = paramSize - readPosition; + if (blockSize > 4) blockSize = 4; + + if (blockSize == 1) + err = mxkSmbusReadByte(addr, buffer + readPosition, 0xc3); + else + err = mxkSmbusI2CReadBlock(addr, 0xc3, buffer + readPosition, blockSize & 0xff); + + if (err != 0) { + amiDebugLog("Error: Data read failed. Position %d. ErrorCode %d.", readPosition, + err); + break; + } + + readPosition += blockSize; + } + } + } + + *lpBytesRead = readPosition; + if (mxkSmbusReleaseMutex() != 0) { + amiDebugLog("Error: ReleaseMutex(). ErrorCode %d.", GetLastError()); + return -6; + } + if (err) return -1; + return 0; +} + +bool mxkN2CmdIsValidOutParam(N2Packet_t *packet, unsigned tag, unsigned short paramSize) { + unsigned short tagPacket = _byteswap_ushort(packet->m_Tag); + unsigned short paramSizePacket = _byteswap_ushort(packet->m_ParamSize); + unsigned short returnCode = _byteswap_ushort(packet->m_Command); + if (tagPacket == tag && paramSizePacket == paramSize && returnCode == 0) return true; + + amiDebugLog("tag: %04x, paramSize: %d, returnCode: %04x", tagPacket, paramSizePacket, + returnCode); + return false; +} + +int mxkN2CmdReadResponce(PN2Nonce_t requestNonce, PHmacSum_t hmacSalt, N2Tag_t tag, + N2Command_t command, PHmacKey_t hmacKey, unsigned char addr, void *bufOut, + unsigned short nOut) { + int ret; + unsigned short nBytesRead; + Sha1Sum_t sha1sum; + N2Packet_t packet; + + ZeroMemory(&packet, sizeof packet); + unsigned short footerSize = + tag == N2_TAG_RQU_COMMAND ? N2_FOOTER_RQU_SIZE : N2_FOOTER_SIGN_SIZE; + ret = mxkN2CmdReadData(addr, &packet, nOut + N2_HEADER_SIZE + footerSize, &nBytesRead); + if (ret != 0) { + amiDebugLog("Error: Data read failed. ErrorCode %d.", ret); + return -7; + } + + if (!mxkN2CmdIsValidOutParam( + &packet, tag == N2_TAG_RQU_COMMAND ? N2_TAG_RSP_COMMAND : N2_TAG_RSP_AUTH_COMMAND, + nBytesRead)) { + amiDebugLog("Error: Invalid output parameter."); + return -9; + } + + unsigned short fixedCommand = _byteswap_ushort(command); + + mxkN2UtilSha1Many(&sha1sum, 3, &packet, N2_HEADER_SIZE, &fixedCommand, sizeof fixedCommand, + packet.m_Body, nOut); + + N2PacketFooter_t *footer = (N2PacketFooter_t *)(packet.m_Body + nOut); + + if (tag == N2_TAG_RQU_COMMAND) { + if (memcmp(footer->rqu.m_ShaSum, sha1sum, sizeof sha1sum) != 0) { + amiDebugLog("Error: Invalid hash value."); + return -10; + } + } else { + if (requestNonce == NULL || hmacKey == NULL) return -2; + + HmacSum_t computedHash; + mxkN2UtilHmacPacket(&sha1sum, &footer->sign.m_Nonce, requestNonce, hmacKey, &computedHash); + if (memcmp(footer->sign.m_Hmac, computedHash, sizeof computedHash) != 0) { + amiDebugLog("Error: Invalid hash value."); + return -10; + } + memcpy_s(requestNonce, sizeof *requestNonce, packet.m_Body + nOut, 20); + + if (hmacSalt != NULL) + memcpy_s(hmacSalt, sizeof *hmacSalt, &footer->sign.m_Nonce, + sizeof footer->sign.m_Nonce); + } + + if (bufOut != NULL && nOut != 0) { + memcpy_s(bufOut, nOut, packet.m_Body, + ((nBytesRead - footerSize) - N2_HEADER_SIZE) & 0xffff); + } + return 0; } int mxkN2CmdEnableSession(void) { - int ret; - unsigned char local_18[20]; + N2Nonce_t nonce; - if (!MXK_N2_INIT) { - amiDebugLog("Error: Uninitialized."); - return -3; - } + CheckN2Init; - ret = mxkN2CmdWriteCommand(NULL, local_18, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL, + int err; + err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL, N2DeviceInfo.m_Addr, NULL, 0); - if (ret != 0) return ret; + if (err != 0) return err; Sleep(32); - // TODO: ASAP - // ret = mxkN2CmdReadResponce(local_18, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL, - // N2DeviceInfo.m_Addr, N2DeviceInfo.m_HmacOut, 20); - if (ret != 0) return ret; + err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL, + N2DeviceInfo.m_Addr, &N2DeviceInfo.m_HmacSalt, 20); + if (err != 0) return err; Sleep(16); return 0; } +int mxkN2CmdGetErrorCode(unsigned short *errorCode) { + N2Nonce_t nonce; + + CheckN2Init; + + int err; + err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_ERROR_CODE, NULL, + N2DeviceInfo.m_Addr, NULL, 0); + if (err != 0) return err; + + Sleep(32); + unsigned short rawErrorCode; + err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_ERROR_CODE, NULL, + N2DeviceInfo.m_Addr, &rawErrorCode, 2); + if (err != 0) return err; + + Sleep(16); + *errorCode = _byteswap_ushort(rawErrorCode); + return 0; +} + +int mxkN2CmdSetAuthKey(PN2AuthKey_t authKey) { + CheckN2Init; + + unsigned char authKeyPt[32]; + ZeroMemory(authKeyPt, sizeof authKeyPt); + unsigned char authKeyCt[32]; + memcpy_s(authKeyPt, sizeof authKeyPt, authKey, sizeof *authKey); + mxkCryptEncryptAes128CBC(N2DeviceInfo.m_AESKey.m_Key, N2DeviceInfo.m_AESKey.m_IV, authKeyCt, + authKeyPt, sizeof authKeyPt); + + N2Nonce_t nonce; + int err; + err = mxkN2CmdWriteCommand(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_SET_AUTH_KEY, &N2DeviceInfo.m_HmacKey, N2DeviceInfo.m_Addr, + authKeyCt, sizeof authKeyCt); + if (err != 0) return err; + + Sleep(96); + err = mxkN2CmdReadResponce(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_SET_AUTH_KEY, &N2DeviceInfo.m_HmacKey, N2DeviceInfo.m_Addr, + NULL, 0); + if (err != 0) return err; + Sleep(16); + memcpy_s(N2DeviceInfo.m_AuthKey, sizeof N2DeviceInfo.m_AuthKey, authKey, sizeof *authKey); + return 0; +} + +int mxkN2CmdSetEncKey(AESKey_t *encKey) { + CheckN2Init; + + unsigned char encKeyCt[sizeof *encKey]; + mxkCryptEncryptAes128CBC(N2DeviceInfo.m_AESKey.m_Key, N2DeviceInfo.m_AESKey.m_IV, encKeyCt, + encKey, sizeof encKeyCt); + + N2Nonce_t requestNonce; + int err; + err = mxkN2CmdWriteCommand(&requestNonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_SET_ENC_KEY, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr, + encKeyCt, sizeof encKeyCt); + if (err != 0) return err; + + Sleep(96); + err = mxkN2CmdReadResponce(&requestNonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_SET_ENC_KEY, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr, + NULL, 0); + if (err != 0) return err; + + Sleep(16); + memcpy_s(&N2DeviceInfo.m_EncKey, sizeof N2DeviceInfo.m_EncKey, encKey, sizeof *encKey); + return 0; +} + +int mxkN2CmdGetAuthLevel(unsigned char *authLevel) { + CheckN2Init; + + unsigned char rawAuthlevel; + N2Nonce_t nonce; + + int err; + err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_AUTH_LEVEL, NULL, + N2DeviceInfo.m_Addr, NULL, 0); + if (err != 0) return err; + Sleep(32); + err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_AUTH_LEVEL, NULL, + N2DeviceInfo.m_Addr, &rawAuthlevel, 1); + if (err != 0) return err; + Sleep(16); + err = 0; + *authLevel = rawAuthlevel; + return 0; +} + +int mxkN2GetErrorCode(void) { + unsigned short errorCode; + + int err = mxkN2CmdGetErrorCode(&errorCode); + if (err != 0) { + amiDebugLog("Error: mxkN2CmdGetErrorCode(). ErrorCode %d", err); + return -5; + } + + amiDebugLog("N2 ErrorCode 0x%04X", errorCode); + return 0; +} +int mxkN2CmdReadKeychipID(N2KeychipId_t *lpKeychipId) { + CheckN2Init; + + N2Nonce_t nonce; + + unsigned char readData[sizeof *lpKeychipId + 2]; + + N2Byte_t request[4]; + request[0] = 0; + request[1] = 0; + request[2] = 0; + request[3] = sizeof *lpKeychipId; + + int err; + err = mxkN2CmdWriteCommand(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_READ_KEYCHIP_ID, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr, + request, sizeof request); + if (err != 0) return err; + Sleep(128); + err = mxkN2CmdReadResponce(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND, + N2_ORD_READ_KEYCHIP_ID, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr, + readData, sizeof readData); + + if (err != 0) return err; + Sleep(16); + + mxkCryptDecryptAes128CBC(N2DeviceInfo.m_EncKey.m_Key, N2DeviceInfo.m_EncKey.m_IV, readData + 2, + (unsigned char *)lpKeychipId, sizeof *lpKeychipId); + return 0; +} + int mxkN2Authentication(void) { - // TODO: ASAP - // unsigned char auth_key[20]; - // unsigned char enc_key[32]; + N2AuthKey_t authKey; + AESKey_t enc_key; if (!MXK_HAS_INIT) { amiDebugLog("No Init Error!!"); return -3; } - int ErrorCode; - - ErrorCode = mxkN2CmdEnableSession(); - if (ErrorCode != 0) { - // mxkN2GetErrorCode(); - amiDebugLog("Error: mxkN2CmdEnableSession(). ErrorCode %d", ErrorCode); + int err; + err = mxkN2CmdEnableSession(); + if (err != 0) { + mxkN2GetErrorCode(); + amiDebugLog("Error: mxkN2CmdEnableSession(). ErrorCode %d", err); return -5; } - // _randomBytes(auth_key, sizeof auth_key); - // ErrorCode = mxkN2CmdSetAuthKey(auth_key); - // if (ErrorCode != 0) { - // mxkN2GetErrorCode(); - // amiDebugLog("Error: mxkN2CmdSetAuthKey(). ErrorCode %d", ErrorCode); - // return -5; - // } + unsigned char authLevel; + mxkN2CmdGetAuthLevel(&authLevel); + printf("Achieved auth level: %d\n", authLevel); - // _randomBytes(enc_key, sizeof enc_key); - // ErrorCode = mxkN2CmdSetEncKey(enc_key); - // if (ErrorCode != 0) { - // mxkN2GetErrorCode(); - // amiDebugLog("Error: mxkN2CmdSetEncKey().ErrorCode %d", ErrorCode); - // return -5; - // } + _randomBytes(authKey, sizeof authKey); + err = mxkN2CmdSetAuthKey(&authKey); + if (err != 0) { + mxkN2GetErrorCode(); + amiDebugLog("Error: mxkN2CmdSetAuthKey(). ErrorCode %d", err); + return -5; + } - // unsigned char auth_level; - // ErrorCode = mxkN2CmdGetAuthLevel(&auth_level); - // if (ErrorCode == 0 && auth_level == 3) return 0; + mxkN2CmdGetAuthLevel(&authLevel); + printf("Achieved auth level: %d\n", authLevel); - // mxkN2GetErrorCode(); - // amiDebugLog("Error: mxkN2CmdGetAuthLevel().ErrorCode %d", ErrorCode); + _randomBytes(&enc_key, sizeof enc_key); + err = mxkN2CmdSetEncKey(&enc_key); + if (err != 0) { + mxkN2GetErrorCode(); + amiDebugLog("Error: mxkN2CmdSetEncKey().ErrorCode %d", err); + return -5; + } + + mxkN2CmdGetAuthLevel(&authLevel); + printf("Achieved auth level: %d\n", authLevel); + + // unsigned char authLevel; + err = mxkN2CmdGetAuthLevel(&authLevel); + if (err == 0 && authLevel == 3) return 0; + + mxkN2GetErrorCode(); + amiDebugLog("Error: mxkN2CmdGetAuthLevel().ErrorCode %d", err); return -5; } + +void mxkN2Exit(void) { MXK_N2_INIT = FALSE; } + +int mxkN2Init(void) { + int err; + err = mxkN2CmdSetDeviceInfo(); + if (err != 0) return err; + + err = mxkN2Authentication(); + if (err != 0) { + unsigned short errorCode; + err = mxkN2CmdGetErrorCode(&errorCode); + if (err != 0) { + amiDebugLog("Error: mxkN2CmdGetErrorCode(). ErrorCode %d", err); + } else { + amiDebugLog("N2 ErrorCode 0x%04X", errorCode); + } + return -1; + } + return 0; +} diff --git a/src/micetools/lib/mxk/mxkN2.h b/src/micetools/lib/mxk/mxkN2.h index cdc2a23..ce39026 100644 --- a/src/micetools/lib/mxk/mxkN2.h +++ b/src/micetools/lib/mxk/mxkN2.h @@ -1,25 +1,72 @@ #pragma once +#include #include -void _randomBytes(unsigned char *buf, int nbytes); +#include "mxkCrypt.h" + +#pragma pack(push, 1) +typedef struct { + uint32_t m_Crc; + uint8_t m_Unk04[12]; + uint8_t m_KeyId[16]; + struct { + uint32_t m_Crc; + uint32_t m_FormatType; + uint8_t m_GameId[4]; + uint8_t m_Region; + uint8_t m_ModelType; + uint8_t m_SystemFlags; + uint8_t Rsv0f; + uint8_t m_PlatformId[3]; + uint8_t m_DvdFlag; + uint8_t m_NetworkAddr[4]; + uint8_t Unk10[88]; + uint8_t m_Seed[16]; + } m_AppBoot; +} N2KeychipId_t; +#pragma pack(pop) + +#define N2_ADDR 0x30 + +#define N2_AUTH_KEY_SIZE 20 +#define N2_NONCE_SIZE 20 +#define N2_DATA_MAX 506 + +#define N2_FOOTER_RQU_SIZE SHA1_SUM_SIZE +#define N2_FOOTER_SIGN_SIZE (N2_NONCE_SIZE + HMAC_SUM_SIZE) + +typedef char N2Nonce_t[N2_NONCE_SIZE]; +typedef char N2AuthKey_t[N2_AUTH_KEY_SIZE]; +typedef char (*PN2Nonce_t)[N2_NONCE_SIZE]; +typedef char (*PN2AuthKey_t)[N2_AUTH_KEY_SIZE]; + +typedef unsigned short N2Tag_t; +typedef unsigned short N2Command_t; +typedef unsigned char N2Byte_t; + +void _randomBytes(void *buf, int nbytes); int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams, va_list args); void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned int numStreams, ...); -void mxkN2UtilSha1Many(unsigned char *sum, int numStreams, ...); -int mxkN2UtilHmacPacket(void *val1, unsigned char *sha1, void *nonce, void *key, - unsigned char *hash_out); +void mxkN2UtilSha1Many(PSha1Sum_t sum, int numStreams, ...); +int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t nonce, PHmacKey_t key, + PHmacSum_t computedHash); -int mxkN2CmdWriteCommand(unsigned char *param_1, unsigned char *packet, unsigned short tag, - unsigned short command, unsigned char *auth_key, unsigned char addr, - void *data, size_t nbytes); +int mxkN2CmdWriteCommand(PN2Nonce_t nonce, PHmacSum_t hmacSalt, N2Tag_t tag, N2Command_t command, + PHmacKey_t hmacKey, unsigned char addr, N2Byte_t *data, + unsigned short nbytes); int mxkN2CmdEnableSession(void); -int mxkN2CmdSetAuthKey(unsigned char* authKey); +int mxkN2CmdSetAuthKey(PN2AuthKey_t authKey); int mxkN2CmdInit(void); int mxkN2CmdSetDeviceInfo(void); int mxkN2Authentication(void); +int mxkN2CmdReadKeychipID(N2KeychipId_t *lpKeychipId); + +int mxkN2Init(void); +void mxkN2Exit(void); diff --git a/src/micetools/lib/mxk/mxkSmbus.c b/src/micetools/lib/mxk/mxkSmbus.c index 1225ffe..f58dd95 100644 --- a/src/micetools/lib/mxk/mxkSmbus.c +++ b/src/micetools/lib/mxk/mxkSmbus.c @@ -228,7 +228,7 @@ int mxkSmbusI2CWriteCommand(unsigned char command_code, unsigned char *buffer, s return tries == 5 ? -9 : 0; } -bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer, +int mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer, unsigned char nbytes) { DWORD nBytesReturned; smb_packet packet; @@ -244,10 +244,10 @@ bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigne if (!succ || nBytesReturned != sizeof packet) return false; if (packet.status == 0) { memcpy(buffer, packet.data, nbytes); - return true; + return 0; } if (packet.status != 24) return false; Sleep(16); } - return false; + return -8; } diff --git a/src/micetools/lib/mxk/mxkSmbus.h b/src/micetools/lib/mxk/mxkSmbus.h index b1ff73e..1979819 100644 --- a/src/micetools/lib/mxk/mxkSmbus.h +++ b/src/micetools/lib/mxk/mxkSmbus.h @@ -10,9 +10,9 @@ int mxkSmbusI2CWriteCommand(unsigned char command_code, unsigned char *buffer, size_t nbytes); int mxkSmbusI2CWriteBlock(unsigned char addr, unsigned char command, unsigned char *buffer, - unsigned char nbytes); -bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer, unsigned char nbytes); +int mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer, + unsigned char nbytes); int mxkSmbusWriteByte(unsigned char v_addr, unsigned char command_code, unsigned char data); int mxkSmbusReadByte(unsigned char addr, unsigned char *readByte, unsigned char cmd_code); diff --git a/src/micetools/util/micedump/kc_pic.c b/src/micetools/util/micedump/kc_pic.c index 683a85e..6145555 100644 --- a/src/micetools/util/micedump/kc_pic.c +++ b/src/micetools/util/micedump/kc_pic.c @@ -16,7 +16,7 @@ void miceDumpKCPIC() { } /** - * The following sequence is required to avoid SBTR! + * The following sequence is required, within 30 seconds, to avoid SBTR! * * amDongleSetupKeychip: * keychip.appboot.systemflag=?&cache=0