Lots of work on keychip communication

This commit is contained in:
Bottersnike 2023-04-04 02:02:06 +01:00
parent b88e279b32
commit 09bd2e4792
Signed by: Bottersnike
SSH Key Fingerprint: SHA256:3g0ghwd4dNX1k1RX8qazbiT+3RIYn/daeBevHZVCiU0
17 changed files with 710 additions and 217 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,20 @@
#pragma once
#include <stdint.h>
#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); \

View File

@ -3,6 +3,7 @@
#include <stdio.h>
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"

View File

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

View File

@ -1,8 +1,8 @@
#include "mxkCrypt.h"
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
// 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;

View File

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

View File

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

View File

@ -1,3 +1,5 @@
#include "mxkN2.h"
#include <Windows.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
@ -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;
}

View File

@ -1,25 +1,72 @@
#pragma once
#include <stdint.h>
#include <varargs.h>
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);

View File

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

View File

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

View File

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