654 lines
21 KiB
C
654 lines
21 KiB
C
#include "mxkN2.h"
|
|
|
|
#include <Windows.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/hmac.h>
|
|
|
|
#include "../../dll/devices/smb_n2.h"
|
|
#include "../ami/ami.h"
|
|
#include "mxkCrypt.h"
|
|
#include "mxkSmbus.h"
|
|
|
|
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[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;
|
|
HmacKey_t m_HmacKey;
|
|
AESKey_t m_AESKey;
|
|
N2AuthKey_t m_AuthKey;
|
|
AESKey_t m_EncKey;
|
|
HmacSum_t m_HmacSalt;
|
|
} N2DeviceInfo_t;
|
|
N2DeviceInfo_t N2DeviceInfo;
|
|
|
|
/**
|
|
* Device keys for:
|
|
*
|
|
* RingEdge:
|
|
* Key: 76ec42b6ae0cb048105171ad8cb2fb07
|
|
* IV: 8e300ba42e154baf651532f570041f5b
|
|
* Auth: 96ed31b2287105a5a330540f25bed851a5c83621
|
|
*
|
|
* ELEFUN:
|
|
* Key: 519aaa25b5ed20b53d28bb56731d7c8d
|
|
* IV: 40a1bfc5341340d3dfdbd1a12b855700
|
|
* Auth: 998e952b6a4899ba42d1d0e8a4fdc87775e19c26
|
|
*
|
|
* Nu:
|
|
* Key: c21c966cbd8b00b9cf4c51bab2c3dfa5
|
|
* IV: 0b137aab20acc7eea0bbec594957dc6d
|
|
* Auth: 74935ef7e0181c0661f7bb7118c5512a130a5d19
|
|
*/
|
|
|
|
// Auth = 96ed31b2287105a5a330540f25bed851a5c83621
|
|
unsigned char N2_KEY_HMAC[2][20] = {
|
|
{ 0x2c, 0xf8, 0x3e, 0x5e, 0x51, 0xf0, 0x60, 0x1b, 0xf6, 0xb1,
|
|
0x49, 0x11, 0x3a, 0xaf, 0x36, 0xe1, 0x51, 0x1c, 0x16, 0x05 },
|
|
{ 0xba, 0x15, 0x0f, 0xec, 0x79, 0x81, 0x65, 0xbe, 0x55, 0x81,
|
|
0x1d, 0x1e, 0x1f, 0x11, 0xee, 0xb0, 0xf4, 0xd4, 0x20, 0x24 }
|
|
};
|
|
|
|
// Key = 76ec42b6ae0cb048105171ad8cb2fb07
|
|
// IV = 8e300ba42e154baf651532f570041f5b
|
|
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) {
|
|
amiDebugLog("Error: Already initialized.");
|
|
return -4;
|
|
}
|
|
ZeroMemory(&N2DeviceInfo, sizeof N2DeviceInfo);
|
|
MXK_N2_INIT = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
int mxkN2CmdSetDeviceInfo(void) {
|
|
if (MXK_HAS_INIT) return -4;
|
|
|
|
if (mxkN2CmdInit() != 0) return -5;
|
|
|
|
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++)
|
|
aesKey.m_Key[i] = N2_KEY_AES[0].m_Key[i] ^ N2_KEY_AES[1].m_Key[i];
|
|
for (int i = 0; i < sizeof aesKey.m_IV; i++)
|
|
aesKey.m_IV[i] = N2_KEY_AES[0].m_IV[i] ^ N2_KEY_AES[1].m_IV[i];
|
|
|
|
N2DeviceInfo_t deviceInfo = { 0 };
|
|
deviceInfo.m_Addr = N2_ADDR;
|
|
|
|
memcpy(&deviceInfo.m_HmacKey, hmacKey, sizeof hmacKey);
|
|
memcpy(&deviceInfo.m_AESKey, &aesKey, sizeof aesKey);
|
|
if (!MXK_N2_INIT)
|
|
amiDebugLog("Error: Uninitialized.");
|
|
else
|
|
memcpy(&N2DeviceInfo, &deviceInfo, sizeof deviceInfo);
|
|
|
|
MXK_HAS_INIT = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
// TODO: Better name
|
|
void _randomBytes(void *buf, int nbytes) {
|
|
FILETIME fileTime;
|
|
amtime_t amTime;
|
|
|
|
for (int i = 0; i < nbytes; i++) {
|
|
amiTimerGet(&amTime);
|
|
GetSystemTimeAsFileTime(&fileTime);
|
|
((unsigned char *)buf)[i] =
|
|
(amTime.microseconds ^ fileTime.dwLowDateTime ^ fileTime.dwHighDateTime) & 0xff;
|
|
}
|
|
}
|
|
void mxkN2GetPacketNonce(PN2Nonce_t nonce) { _randomBytes(nonce, 20); }
|
|
|
|
int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams,
|
|
va_list args) {
|
|
if (out == NULL || count == NULL) {
|
|
amiDebugLog("Error: Invalid param.");
|
|
return -2;
|
|
}
|
|
|
|
size_t offset = 0;
|
|
size_t max = *count;
|
|
for (size_t i = 0; i < numStreams && i < max; i++) {
|
|
unsigned char *b = va_arg(args, unsigned char *);
|
|
size_t n = va_arg(args, size_t);
|
|
if (offset + n > max) n = max - offset;
|
|
memcpy(out + offset, b, n);
|
|
offset += n;
|
|
}
|
|
|
|
*count = offset;
|
|
return 0;
|
|
}
|
|
void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned int numStreams,
|
|
...) {
|
|
va_list args;
|
|
va_start(args, numStreams);
|
|
|
|
mxkN2UtilVCatenateData(concatinated, count, numStreams, args);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
void mxkN2UtilSha1Many(PSha1Sum_t sum, int numStreams, ...) {
|
|
va_list args;
|
|
va_start(args, numStreams);
|
|
|
|
Sha1Sum_t sumout;
|
|
unsigned char concatinated[0x200];
|
|
size_t size = sizeof concatinated;
|
|
|
|
mxkN2UtilVCatenateData(concatinated, &size, numStreams, args);
|
|
mxkCryptCalcHashWithSha1(concatinated, size, &sumout);
|
|
memcpy_s(sum, sizeof *sum, sumout, sizeof sumout);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
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 = sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce;
|
|
unsigned int nout = HMAC_SUM_SIZE;
|
|
mxkN2UtilCatenateData(data_in, &count, 3, packetSha, sizeof *packetSha, hmacSalt,
|
|
sizeof *hmacSalt, nonce, sizeof *nonce);
|
|
|
|
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, void *data, unsigned short nbytes,
|
|
unsigned short *nbytesOut) {
|
|
unsigned int ptr_;
|
|
unsigned char nstep;
|
|
int status;
|
|
unsigned short position;
|
|
|
|
if (mxkSmbusRequestMutex() != 0) {
|
|
amiDebugLog("Error: mxkSmbusRequestMutex");
|
|
return -6;
|
|
}
|
|
|
|
status = 0;
|
|
position = 0;
|
|
if (nbytes != 0) {
|
|
do {
|
|
ptr_ = position;
|
|
if ((int)(nbytes - ptr_) < 5) {
|
|
nstep = (byte)(nbytes - ptr_);
|
|
if (nstep != 1) goto LAB_0040ae51;
|
|
status = mxkSmbusWriteByte(addr, 0xcc, ((unsigned char *)data)[ptr_]);
|
|
} else {
|
|
nstep = 4;
|
|
LAB_0040ae51:
|
|
status = mxkSmbusI2CWriteBlock(addr, 0xcc, &((unsigned char *)data)[ptr_], nstep);
|
|
}
|
|
if (status != 0) {
|
|
amiDebugLog("Error: Data write failed. Position %d. ErrorCode %d.", position,
|
|
status);
|
|
|
|
break;
|
|
}
|
|
position += nstep;
|
|
Sleep(0);
|
|
} while (position < nbytes);
|
|
}
|
|
*nbytesOut = position;
|
|
|
|
if (mxkSmbusReleaseMutex() != 0) {
|
|
amiDebugLog("Error: mxkSmbusReleaseMutex");
|
|
return -6;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
|
|
N2PacketFooter_t *footer = (N2PacketFooter_t *)(packet.m_Body + nbytes);
|
|
|
|
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_s(footer->rqu.m_ShaSum, sizeof footer->rqu.m_ShaSum, sha1sum, sizeof sha1sum);
|
|
} else {
|
|
if (requestNonce == NULL || hmacKey == NULL) return -2;
|
|
|
|
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 nBytesOut;
|
|
ret = mxkN2CmdWriteData(addr, &packet, paramsize, &nBytesOut);
|
|
if (ret != 0) {
|
|
amiDebugLog("Error: Data write failed. ErrorCode %d.", ret);
|
|
return -8;
|
|
}
|
|
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) {
|
|
N2Nonce_t nonce;
|
|
|
|
CheckN2Init;
|
|
|
|
int err;
|
|
err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL,
|
|
N2DeviceInfo.m_Addr, NULL, 0);
|
|
if (err != 0) return err;
|
|
|
|
Sleep(32);
|
|
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) {
|
|
N2AuthKey_t authKey;
|
|
AESKey_t enc_key;
|
|
|
|
if (!MXK_HAS_INIT) {
|
|
amiDebugLog("No Init Error!!");
|
|
return -3;
|
|
}
|
|
|
|
int err;
|
|
err = mxkN2CmdEnableSession();
|
|
if (err != 0) {
|
|
mxkN2GetErrorCode();
|
|
amiDebugLog("Error: mxkN2CmdEnableSession(). ErrorCode %d", err);
|
|
return -5;
|
|
}
|
|
|
|
unsigned char authLevel;
|
|
mxkN2CmdGetAuthLevel(&authLevel);
|
|
printf("Achieved auth level: %d\n", authLevel);
|
|
|
|
_randomBytes(authKey, sizeof authKey);
|
|
err = mxkN2CmdSetAuthKey(&authKey);
|
|
if (err != 0) {
|
|
mxkN2GetErrorCode();
|
|
amiDebugLog("Error: mxkN2CmdSetAuthKey(). ErrorCode %d", err);
|
|
return -5;
|
|
}
|
|
|
|
mxkN2CmdGetAuthLevel(&authLevel);
|
|
printf("Achieved auth level: %d\n", authLevel);
|
|
|
|
_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;
|
|
}
|