mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
remake style and output
This commit is contained in:
parent
2a2f9275cd
commit
ff1d66da61
4 changed files with 201 additions and 215 deletions
|
@ -1,4 +1,3 @@
|
||||||
// -*- mode: c; indent-tabs-mode: nil; tab-width: 3 -*-
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2019 micolous+git@gmail.com
|
// Copyright (C) 2019 micolous+git@gmail.com
|
||||||
//
|
//
|
||||||
|
@ -42,66 +41,65 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static void getAndPrintBalance(void) {
|
static int get_and_print_balance(void) {
|
||||||
uint32_t balance;
|
uint32_t balance = 0;
|
||||||
bool ret = KSX6924GetBalance(&balance);
|
if (KSX6924GetBalance(&balance) == false) {
|
||||||
if (!ret) {
|
|
||||||
PrintAndLogEx(ERR, "Error getting balance");
|
PrintAndLogEx(ERR, "Error getting balance");
|
||||||
return;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Current balance: %ld won/cents", balance);
|
PrintAndLogEx(SUCCESS, "Current balance: " _YELLOW_("%ld") " won/cents", balance);
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFKSX6924Balance(const char *Cmd) {
|
static int CmdHFKSX6924Balance(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf ksx6924 balance",
|
CLIParserInit(&ctx, "hf ksx6924 balance",
|
||||||
"Gets the current purse balance.\n",
|
"Gets the current purse balance",
|
||||||
"Usage:\n\thf ksx6924 balance\n");
|
"hf ksx6924 balance\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
arg_lit0("k", "keep", "keep field ON for next command"),
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
bool keep = arg_get_lit(ctx, 1);
|
||||||
bool APDULogging = arg_get_lit(ctx, 2);
|
bool APDULogging = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
bool ret = KSX6924TrySelect();
|
if ( KSX6924TrySelect()) {
|
||||||
if (!ret) {
|
get_and_print_balance();
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAndPrintBalance();
|
if (keep == false) {
|
||||||
|
|
||||||
end:
|
|
||||||
if (!leaveSignalON) {
|
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFKSX6924Info(const char *Cmd) {
|
static int CmdHFKSX6924Info(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf ksx6924 info",
|
CLIParserInit(&ctx, "hf ksx6924 info",
|
||||||
"Get info about a KS X 6924 transit card.\nThis application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).\n",
|
"Get info about a KS X 6924 transit card.\n"
|
||||||
"Usage:\n\thf ksx6924 info\n");
|
"This application is used by T-Money (South Korea) and\n"
|
||||||
|
"Snapper+ (Wellington, New Zealand).",
|
||||||
|
"hf ksx6924 info\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
arg_lit0("k", "keep", "keep field ON for next command"),
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
bool keep = arg_get_lit(ctx, 1);
|
||||||
bool APDULogging = arg_get_lit(ctx, 2);
|
bool APDULogging = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
@ -114,7 +112,7 @@ static int CmdHFKSX6924Info(const char *Cmd) {
|
||||||
int res = KSX6924Select(true, true, buf, sizeof(buf), &len, &sw);
|
int res = KSX6924Select(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
if (!leaveSignalON) {
|
if (keep == false) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -200,24 +198,24 @@ static int CmdHFKSX6924Info(const char *Cmd) {
|
||||||
|
|
||||||
KSX6924PrintPurseInfo(&purseInfo);
|
KSX6924PrintPurseInfo(&purseInfo);
|
||||||
|
|
||||||
getAndPrintBalance();
|
get_and_print_balance();
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (!leaveSignalON) {
|
if (keep == false) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFKSX6924Select(const char *Cmd) {
|
static int CmdHFKSX6924Select(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf ksx6924 select",
|
CLIParserInit(&ctx, "hf ksx6924 select",
|
||||||
"Selects KS X 6924 application, and leaves field up.\n",
|
"Selects KS X 6924 application, and leaves field up",
|
||||||
"Usage:\n\thf ksx6924 select\n");
|
"hf ksx6924 select\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -226,133 +224,139 @@ static int CmdHFKSX6924Select(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
bool ret = KSX6924TrySelect();
|
if (KSX6924TrySelect()) {
|
||||||
if (ret) {
|
PrintAndLogEx(SUCCESS, "Card is selected and field is up");
|
||||||
PrintAndLogEx(SUCCESS, "OK");
|
|
||||||
} else {
|
} else {
|
||||||
// Wrong app, drop field.
|
// Wrong app, drop field.
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFKSX6924InitializeCard(const char *Cmd) {
|
static int CmdHFKSX6924Initialize(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf ksx6924 initializecard",
|
CLIParserInit(&ctx, "hf ksx6924 initialize",
|
||||||
"Perform transaction initialization. (Mpda)\n",
|
"Perform transaction initialization (mpda)",
|
||||||
"Usage:\n\thf ksx6924 initializecard 000003e8 -> Mpda\n");
|
"hf ksx6924 initialize 000003e8 -> mpda\n");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
arg_lit0("k", "keep", "keep field ON for next command"),
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_strx1(NULL, NULL, "<Mpda 4byte hex>", NULL),
|
arg_strx1(NULL, NULL, "<mpda 4byte hex>", NULL),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
bool keep = arg_get_lit(ctx, 1);
|
||||||
bool APDULogging = arg_get_lit(ctx, 2);
|
bool APDULogging = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
uint8_t data[APDU_RES_LEN] = {0};
|
uint8_t data[APDU_RES_LEN] = {0};
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
CLIGetHexWithReturn(ctx, 3, data, &datalen);
|
CLIGetHexWithReturn(ctx, 3, data, &datalen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
if (datalen != 4) {
|
if (datalen != 4) {
|
||||||
PrintAndLogEx(WARNING, "Mpda parameter must be 4 byte long (eg: 000003e8)");
|
PrintAndLogEx(WARNING, "Mpda parameter must be 4 byte long (eg: 000003e8)");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try selecting card
|
||||||
|
if (KSX6924TrySelect() == false) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = KSX6924TrySelect();
|
PrintAndLogEx(SUCCESS, "Initialize Card : Mpda -> %02X %02X %02X %02X", data[0], data[1], data[2], data[3]);
|
||||||
if (!ret) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Initialize Card : Mpda -> %02X %02X %02X %02X", data[0], data[1], data[2], data[3]);
|
uint8_t response[25] = {0};
|
||||||
uint8_t response[25];
|
if (KSX6924InitializeCard(data[0], data[1], data[2], data[3], response) ) {
|
||||||
if (!KSX6924InitializeCard(data[0], data[1], data[2], data[3], response)) {
|
PrintAndLogEx(SUCCESS, "Response : %s", sprint_hex(response, sizeof(response)));
|
||||||
|
} else {
|
||||||
PrintAndLogEx(FAILED, "Initialize Card Error");
|
PrintAndLogEx(FAILED, "Initialize Card Error");
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Response : %s", sprint_hex(response, sizeof(response)));
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (!leaveSignalON) {
|
if (keep == false) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFKSX6924PRec(const char *Cmd) {
|
static int CmdHFKSX6924PRec(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf ksx6924 prec",
|
CLIParserInit(&ctx, "hf ksx6924 prec",
|
||||||
"Executes proprietary read record command.\nData format is unknown. Other records are available with 'emv getrec'.\n",
|
"Executes proprietary read record command.\n"
|
||||||
"Usage:\n\thf ksx6924 prec 0b -> read proprietary record 0x0b\n");
|
"Data format is unknown. Other records are available with 'emv getrec'.\n",
|
||||||
|
"hf ksx6924 prec 0b -> read proprietary record 0x0b");
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
arg_lit0("k", "keep", "keep field ON for next command"),
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
arg_lit0("a", "apdu", "show APDU reqests and responses"),
|
||||||
arg_strx1(NULL, NULL, "<record 1byte HEX>", NULL),
|
arg_strx1(NULL, NULL, "<record 1byte HEX>", NULL),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
bool keep = arg_get_lit(ctx, 1);
|
||||||
bool APDULogging = arg_get_lit(ctx, 2);
|
bool APDULogging = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
uint8_t data[APDU_RES_LEN] = {0};
|
uint8_t data[APDU_RES_LEN] = {0};
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
CLIGetHexWithReturn(ctx, 3, data, &datalen);
|
CLIGetHexWithReturn(ctx, 3, data, &datalen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
if (datalen != 1) {
|
if (datalen != 1) {
|
||||||
PrintAndLogEx(WARNING, "Record parameter must be 1 byte long (eg: 0f)");
|
PrintAndLogEx(WARNING, "Record parameter must be 1 byte long (eg: 0f)");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KSX6924TrySelect() == false) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = KSX6924TrySelect();
|
PrintAndLogEx(SUCCESS, "Getting record %02x ...", data[0]);
|
||||||
if (!ret) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "Getting record %02x...", data[0]);
|
uint8_t recordData[0x10] = {0};
|
||||||
uint8_t recordData[0x10];
|
if (KSX6924ProprietaryGetRecord(data[0], recordData, sizeof(recordData))) {
|
||||||
if (!KSX6924ProprietaryGetRecord(data[0], recordData, sizeof(recordData))) {
|
PrintAndLogEx(SUCCESS, " %s", sprint_hex(recordData, sizeof(recordData)));
|
||||||
|
} else {
|
||||||
PrintAndLogEx(FAILED, "Error getting record");
|
PrintAndLogEx(FAILED, "Error getting record");
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " %s", sprint_hex(recordData, sizeof(recordData)));
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (!leaveSignalON) {
|
if (keep == false) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"info", CmdHFKSX6924Info, AlwaysAvailable, "Get info about a KS X 6924 (T-Money, Snapper+) transit card"},
|
{"balance", CmdHFKSX6924Balance, IfPm3Iso14443a, "Get current purse balance"},
|
||||||
{"select", CmdHFKSX6924Select, AlwaysAvailable, "Select application, and leave field up"},
|
{"info", CmdHFKSX6924Info, IfPm3Iso14443a, "Get info about a KS X 6924 (T-Money, Snapper+) transit card"},
|
||||||
{"balance", CmdHFKSX6924Balance, AlwaysAvailable, "Get current purse balance"},
|
{"initialize", CmdHFKSX6924Initialize, IfPm3Iso14443a, "Perform transaction initialization (Mpda)"},
|
||||||
{"initializecard", CmdHFKSX6924InitializeCard, AlwaysAvailable, "Perform transaction initialization (Mpda)"},
|
{"prec", CmdHFKSX6924PRec, IfPm3Iso14443a, "Send proprietary get record command (CLA=90, INS=4C)"},
|
||||||
{"prec", CmdHFKSX6924PRec, AlwaysAvailable, "Send proprietary get record command (CLA=90, INS=4C)"},
|
{"select", CmdHFKSX6924Select, IfPm3Iso14443a, "Select application, and leave field up"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
int CmdHFKSX6924(const char *Cmd) {
|
|
||||||
(void)WaitForResponseTimeout(CMD_ACK, NULL, 100);
|
|
||||||
CmdsParse(CommandTable, Cmd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd) {
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
CmdsHelp(CommandTable);
|
CmdsHelp(CommandTable);
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CmdHFKSX6924(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// -*- mode: c; indent-tabs-mode: nil; tab-width: 3 -*-
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2019 micolous+git@gmail.com
|
// Copyright (C) 2019 micolous+git@gmail.com
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// -*- mode: c; indent-tabs-mode: nil; tab-width: 3 -*-
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2019 micolous+git@gmail.com
|
// Copyright (C) 2019 micolous+git@gmail.com
|
||||||
//
|
//
|
||||||
|
@ -21,11 +20,13 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "ksx6924core.h"
|
#include "ksx6924core.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <winsock2.h> // ntohl
|
# include <winsock2.h> // ntohl
|
||||||
#else
|
#else
|
||||||
# include <arpa/inet.h> // ntohl
|
# include <arpa/inet.h> // ntohl
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "emv/emvcore.h"
|
#include "emv/emvcore.h"
|
||||||
#include "iso7816/apduinfo.h"
|
#include "iso7816/apduinfo.h"
|
||||||
|
@ -230,43 +231,39 @@ static int64_t bcdToLong(const uint8_t *buf, size_t len) {
|
||||||
/**
|
/**
|
||||||
* Converts a date from on-card format to ksx6924_date format.
|
* Converts a date from on-card format to ksx6924_date format.
|
||||||
*/
|
*/
|
||||||
static bool convertInternalDate(
|
static bool convert_internal_date( const _ksx6924_internal_date_t i, struct ksx6924_date *ret) {
|
||||||
const _ksx6924_internal_date_t i, struct ksx6924_date *ret) {
|
|
||||||
int64_t year = bcdToLong(i.year, 2);
|
int64_t year = bcdToLong(i.year, 2);
|
||||||
int16_t month = bcdToInteger(i.month[0]);
|
int16_t month = bcdToInteger(i.month[0]);
|
||||||
int16_t day = bcdToInteger(i.day[0]);
|
int16_t day = bcdToInteger(i.day[0]);
|
||||||
|
|
||||||
if (year < 0 || year > 0xffff || month < 0 || day < 0) {
|
if (year < 0 || year > 0xFFFF || month < 0 || day < 0) {
|
||||||
goto fail;
|
memset(ret, 0, sizeof(struct ksx6924_date));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret->year = year & 0xffff;
|
ret->year = year & 0xFFFF;
|
||||||
ret->month = month;
|
ret->month = month;
|
||||||
ret->day = day;
|
ret->day = day;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
|
||||||
memset(ret, 0, sizeof(struct ksx6924_date));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses purse info in FCI tag b0
|
* Parses purse info in FCI tag b0
|
||||||
*/
|
*/
|
||||||
bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen,
|
bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen, struct ksx6924_purse_info *ret) {
|
||||||
struct ksx6924_purse_info *ret) {
|
|
||||||
|
memset(ret, 0, sizeof(struct ksx6924_purse_info));
|
||||||
|
|
||||||
if (purseLen != sizeof(_ksx6924_internal_purse_info_t)) {
|
if (purseLen != sizeof(_ksx6924_internal_purse_info_t)) {
|
||||||
// Invalid size!
|
// Invalid size!
|
||||||
PrintAndLogEx(NORMAL, "Expected %ld bytes, got %ld\n",
|
PrintAndLogEx(FAILED, "Expected %ld bytes, got %ld\n", sizeof(_ksx6924_internal_purse_info_t), purseLen);
|
||||||
sizeof(_ksx6924_internal_purse_info_t), purseLen);
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _ksx6924_internal_purse_info_t *internalPurseInfo = (const _ksx6924_internal_purse_info_t *)purseInfo;
|
const _ksx6924_internal_purse_info_t *internalPurseInfo = (const _ksx6924_internal_purse_info_t *)purseInfo;
|
||||||
|
|
||||||
memset(ret, 0, sizeof(struct ksx6924_purse_info));
|
|
||||||
|
|
||||||
// Simple copies
|
// Simple copies
|
||||||
ret->cardType = internalPurseInfo->cardType;
|
ret->cardType = internalPurseInfo->cardType;
|
||||||
ret->alg = internalPurseInfo->alg;
|
ret->alg = internalPurseInfo->alg;
|
||||||
|
@ -279,9 +276,12 @@ bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen,
|
||||||
|
|
||||||
// Fields that need rewriting
|
// Fields that need rewriting
|
||||||
hex_to_buffer(ret->csn, internalPurseInfo->csn,
|
hex_to_buffer(ret->csn, internalPurseInfo->csn,
|
||||||
sizeof(internalPurseInfo->csn), sizeof(ret->csn) - 1,
|
sizeof(internalPurseInfo->csn),
|
||||||
/* min_str_len */ 0, /* spaces_between */ 0,
|
sizeof(ret->csn) - 1,
|
||||||
/* uppercase */ false);
|
0, // min_str_len
|
||||||
|
0, // spaces_between
|
||||||
|
false // uppercase
|
||||||
|
);
|
||||||
|
|
||||||
int64_t idtr = bcdToLong(internalPurseInfo->idtr, 5);
|
int64_t idtr = bcdToLong(internalPurseInfo->idtr, 5);
|
||||||
if (idtr < 0) {
|
if (idtr < 0) {
|
||||||
|
@ -293,95 +293,88 @@ bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen,
|
||||||
if (bra < 0) {
|
if (bra < 0) {
|
||||||
bra = 0; // fail
|
bra = 0; // fail
|
||||||
}
|
}
|
||||||
ret->bra = bra & 0xffff;
|
|
||||||
|
|
||||||
convertInternalDate(internalPurseInfo->issueDate, &(ret->issueDate));
|
ret->bra = bra & 0xFFFF;
|
||||||
convertInternalDate(internalPurseInfo->expiryDate, &(ret->expiryDate));
|
|
||||||
|
convert_internal_date(internalPurseInfo->issueDate, &(ret->issueDate));
|
||||||
|
convert_internal_date(internalPurseInfo->expiryDate, &(ret->expiryDate));
|
||||||
|
|
||||||
ret->balMax = ntohl(*(uint32_t *)(internalPurseInfo->balMax));
|
ret->balMax = ntohl(*(uint32_t *)(internalPurseInfo->balMax));
|
||||||
ret->mmax = ntohl(*(uint32_t *)(internalPurseInfo->mmax));
|
ret->mmax = ntohl(*(uint32_t *)(internalPurseInfo->mmax));
|
||||||
|
|
||||||
memcpy(&ret->rfu, &internalPurseInfo->rfu, 8);
|
memcpy(&ret->rfu, &internalPurseInfo->rfu, 8);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
|
||||||
memset(ret, 0, sizeof(struct ksx6924_purse_info));
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints out a ksx6924_purse_info
|
* Prints out a ksx6924_purse_info
|
||||||
*/
|
*/
|
||||||
void KSX6924PrintPurseInfo(const struct ksx6924_purse_info *purseInfo) {
|
void KSX6924PrintPurseInfo(const struct ksx6924_purse_info *purseInfo) {
|
||||||
|
|
||||||
if (purseInfo == NULL) {
|
if (purseInfo == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "## KS X 6924 Purse Info:");
|
PrintAndLogEx(INFO, "--- " _CYAN_("KS X 6924 Purse Info") " ---------------------------");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(NORMAL, "cardType .............................. %02x (%s)",
|
PrintAndLogEx(INFO, " cardType .............................. %02x ( %s )", purseInfo->cardType,
|
||||||
purseInfo->cardType,
|
|
||||||
KSX6924LookupCardType(purseInfo->cardType, KSX6924_UNKNOWN));
|
KSX6924LookupCardType(purseInfo->cardType, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "alg (encryption algorithm) ............ %02x (%s)",
|
PrintAndLogEx(INFO, " alg (encryption algorithm) ............ %02x ( %s )", purseInfo->alg,
|
||||||
purseInfo->alg,
|
|
||||||
KSX6924LookupAlg(purseInfo->alg, KSX6924_UNKNOWN));
|
KSX6924LookupAlg(purseInfo->alg, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "vk (keyset version) ................... %02x",
|
PrintAndLogEx(INFO, " vk (keyset version) ................... %02x", purseInfo->vk);
|
||||||
purseInfo->vk);
|
PrintAndLogEx(INFO, " idCenter (issuer ID) .................. %02x ( %s )", purseInfo->idCenter,
|
||||||
PrintAndLogEx(NORMAL, "idCenter (issuer ID) .................. %02x (%s)",
|
|
||||||
purseInfo->idCenter,
|
|
||||||
KSX6924LookupTMoneyIDCenter(purseInfo->idCenter, KSX6924_UNKNOWN));
|
KSX6924LookupTMoneyIDCenter(purseInfo->idCenter, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "csn (card number) ..................... %s",
|
PrintAndLogEx(INFO, " CSN (card number) ..................... %s", purseInfo->csn);
|
||||||
purseInfo->csn);
|
PrintAndLogEx(INFO, " idtr (card usage authentication ID) ... %i", purseInfo->idtr);
|
||||||
PrintAndLogEx(NORMAL, "idtr (card usage authentication ID) ... %i",
|
PrintAndLogEx(INFO, " issue date ............................ %04i-%02i-%02i",
|
||||||
purseInfo->idtr);
|
purseInfo->issueDate.year,
|
||||||
PrintAndLogEx(NORMAL, "issueDate ............................. %04i-%02i-%02i",
|
purseInfo->issueDate.month,
|
||||||
purseInfo->issueDate.year, purseInfo->issueDate.month, purseInfo->issueDate.day);
|
purseInfo->issueDate.day);
|
||||||
PrintAndLogEx(NORMAL, "expiryDate ............................ %04i-%02i-%02i",
|
PrintAndLogEx(INFO, " expiry date ........................... %04i-%02i-%02i",
|
||||||
purseInfo->expiryDate.year, purseInfo->expiryDate.month, purseInfo->expiryDate.day);
|
purseInfo->expiryDate.year,
|
||||||
PrintAndLogEx(NORMAL, "userCode (ticket type) ................ %02x (%s)",
|
purseInfo->expiryDate.month,
|
||||||
purseInfo->userCode,
|
purseInfo->expiryDate.day);
|
||||||
|
PrintAndLogEx(INFO, " user code (ticket type) ............... %02x ( %s )", purseInfo->userCode,
|
||||||
KSX6924LookupTMoneyUserCode(purseInfo->userCode, KSX6924_UNKNOWN));
|
KSX6924LookupTMoneyUserCode(purseInfo->userCode, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "disRate (discount type) ............... %02x (%s)",
|
PrintAndLogEx(INFO, " disRate (discount type) ............... %02x ( %s )", purseInfo->disRate,
|
||||||
purseInfo->disRate,
|
|
||||||
KSX6924LookupTMoneyDisRate(purseInfo->disRate, KSX6924_UNKNOWN));
|
KSX6924LookupTMoneyDisRate(purseInfo->disRate, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "balMax (in won/cents) ................. %ld",
|
PrintAndLogEx(INFO, " balMax (in won/cents) ................. %ld", purseInfo->balMax);
|
||||||
purseInfo->balMax);
|
PrintAndLogEx(INFO, " bra (branch code) ..................... %04x", purseInfo->bra);
|
||||||
PrintAndLogEx(NORMAL, "bra (branch code) ..................... %04x",
|
PrintAndLogEx(INFO, " mmax (one-time transaction limit) ..... %ld", purseInfo->mmax);
|
||||||
purseInfo->bra);
|
PrintAndLogEx(INFO, " tcode (telecom carrier ID) ............ %02x ( %s )", purseInfo->tcode,
|
||||||
PrintAndLogEx(NORMAL, "mmax (one-time transaction limit) ..... %ld",
|
|
||||||
purseInfo->mmax);
|
|
||||||
PrintAndLogEx(NORMAL, "tcode (telecom carrier ID) ............ %02x (%s)",
|
|
||||||
purseInfo->tcode,
|
|
||||||
KSX6924LookupTMoneyTCode(purseInfo->tcode, KSX6924_UNKNOWN));
|
KSX6924LookupTMoneyTCode(purseInfo->tcode, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "ccode (credit card company ID) ........ %02x (%s)",
|
PrintAndLogEx(INFO, " ccode (credit card company ID) ........ %02x ( %s )", purseInfo->ccode,
|
||||||
purseInfo->ccode,
|
|
||||||
KSX6924LookupTMoneyCCode(purseInfo->ccode, KSX6924_UNKNOWN));
|
KSX6924LookupTMoneyCCode(purseInfo->ccode, KSX6924_UNKNOWN));
|
||||||
PrintAndLogEx(NORMAL, "rfu (reserved) ........................ %s",
|
PrintAndLogEx(INFO, " rfu (reserved) ........................ %s", sprint_hex(purseInfo->rfu, sizeof(purseInfo->rfu)));
|
||||||
sprint_hex(purseInfo->rfu, sizeof(purseInfo->rfu)));
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the KS X 6924 Application, D4100000030001, and returns the response
|
* Selects the KS X 6924 Application, D4100000030001, and returns the response
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
int KSX6924Select(
|
int KSX6924Select(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||||
bool ActivateField, bool LeaveFieldON,
|
|
||||||
uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
|
||||||
// T-Money + Snapper
|
// T-Money + Snapper
|
||||||
uint8_t aid[] = {0xD4, 0x10, 0x00, 0x00, 0x03, 0x00, 0x01};
|
uint8_t aid[] = {0xD4, 0x10, 0x00, 0x00, 0x03, 0x00, 0x01};
|
||||||
|
|
||||||
// Cashbee
|
// Cashbee
|
||||||
//uint8_t aid[] = {0xD4, 0x10, 0x00, 0x00, 0x14, 0x00, 0x01};
|
//uint8_t aid[] = {0xD4, 0x10, 0x00, 0x00, 0x14, 0x00, 0x01};
|
||||||
|
return EMVSelect(CC_CONTACTLESS,
|
||||||
|
ActivateField,
|
||||||
return EMVSelect(CC_CONTACTLESS, ActivateField, LeaveFieldON, aid,
|
LeaveFieldON,
|
||||||
sizeof(aid), Result, MaxResultLen, ResultLen, sw, NULL);
|
aid,
|
||||||
|
sizeof(aid),
|
||||||
|
Result,
|
||||||
|
MaxResultLen,
|
||||||
|
ResultLen,
|
||||||
|
sw,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the KS X 6924 Application. Returns true if selected successfully.
|
* Selects the KS X 6924 Application. Returns true if selected successfully.
|
||||||
*/
|
*/
|
||||||
|
@ -398,8 +391,11 @@ bool KSX6924TrySelect(void) {
|
||||||
|
|
||||||
if (sw != 0x9000) {
|
if (sw != 0x9000) {
|
||||||
if (sw) {
|
if (sw) {
|
||||||
PrintAndLogEx(FAILED, "Not a KS X 6924 card! APDU response: %04x - %s",
|
PrintAndLogEx(FAILED,
|
||||||
sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
"Not a KS X 6924 card! APDU response: %04x - %s",
|
||||||
|
sw,
|
||||||
|
GetAPDUCodeDescription(sw >> 8, sw & 0xff)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(FAILED, "APDU exchange error. Card returns 0x0000.");
|
PrintAndLogEx(FAILED, "APDU exchange error. Card returns 0x0000.");
|
||||||
}
|
}
|
||||||
|
@ -418,30 +414,29 @@ bool KSX6924GetBalance(uint32_t *result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t sw;
|
*result = 0;
|
||||||
size_t result_len;
|
|
||||||
uint8_t rawResult[4 /* message */ + 2 /* sw */];
|
uint8_t arr[4 + 2]; // message , sw
|
||||||
//uint8_t apdu[] = {0x90, 0x4c, 0x00, 0x00, 4, rawResult};
|
//uint8_t apdu[] = {0x90, 0x4c, 0x00, 0x00, 4, arr};
|
||||||
memset(rawResult, 0, sizeof(rawResult));
|
memset(arr, 0, sizeof(arr));
|
||||||
|
|
||||||
uint8_t data[] = {0x00, 0x00, 0x00, 0x00};
|
uint8_t data[] = {0x00, 0x00, 0x00, 0x00};
|
||||||
int res = FIDOExchange((sAPDU_t) {0x90, 0x4c, 0x00, 0x00, 4, data}, rawResult, sizeof(rawResult),
|
|
||||||
&result_len, &sw);
|
uint16_t sw = 0;
|
||||||
|
size_t rlen = 0;
|
||||||
|
|
||||||
|
int res = FIDOExchange((sAPDU_t) {0x90, 0x4c, 0x00, 0x00, 4, data}, arr, sizeof(arr), &rlen, &sw);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
// error communicating
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sw != 0x9000) {
|
if (sw != 0x9000) {
|
||||||
// card returned error
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = ntohl(*(uint32_t *)(rawResult));
|
*result = ntohl(*(uint32_t *)(arr));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
|
||||||
*result = 0;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,34 +444,32 @@ fail:
|
||||||
* Perform transaction initialization.
|
* Perform transaction initialization.
|
||||||
*/
|
*/
|
||||||
bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t mpda4, uint8_t *result) {
|
bool KSX6924InitializeCard(uint8_t mpda1, uint8_t mpda2, uint8_t mpda3, uint8_t mpda4, uint8_t *result) {
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t sw;
|
*result = 0;
|
||||||
size_t result_len;
|
uint16_t sw = 0;
|
||||||
uint8_t rawResult[1 /* ALGep */ + 1 /* VKep */ + 4 /* BALep */ + 1 /* IDcenter */ + 8 /* IDep */ + 4 /* NTep */ + 4 /* Sign1 */ + 2 /* sw */];
|
size_t rlen = 0;
|
||||||
memset(rawResult, 0, sizeof(rawResult));
|
|
||||||
|
// ALGep + VKep + BALep + IDcenter + IDep + NTep + Sign1 + sw
|
||||||
|
uint8_t arr[1 + 1 + 4 + 1 + 8 + 4 + 4 + 2];
|
||||||
|
memset(arr, 0, sizeof(arr));
|
||||||
|
|
||||||
uint8_t data[] = {mpda1, mpda2, mpda3, mpda4};
|
uint8_t data[] = {mpda1, mpda2, mpda3, mpda4};
|
||||||
int res = FIDOExchange((sAPDU_t) {0x90, 0x02, 0x00, 0x00, 0x04, data}, rawResult, sizeof(rawResult),
|
int res = FIDOExchange((sAPDU_t) {0x90, 0x02, 0x00, 0x00, 0x04, data}, arr, sizeof(arr), &rlen, &sw);
|
||||||
&result_len, &sw);
|
|
||||||
if (res) {
|
if (res) {
|
||||||
// error communicating
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sw != 0x9000) {
|
if (sw != 0x9000) {
|
||||||
// card returned error
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//*result = ntohl(*(uint32_t*)(rawResult));
|
//*result = ntohl(*(uint32_t*)(arr));
|
||||||
memcpy(result, rawResult, result_len + 2 /* sw */);
|
memcpy(result, arr, rlen + 2); // skip 2 sw bytes
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
|
||||||
*result = 0;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -491,38 +484,29 @@ fail:
|
||||||
*
|
*
|
||||||
* Returns false on error.
|
* Returns false on error.
|
||||||
*/
|
*/
|
||||||
bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result,
|
bool KSX6924ProprietaryGetRecord(uint8_t id, uint8_t *result, size_t result_len) {
|
||||||
size_t resultLen) {
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(result, 0, resultLen);
|
memset(result, 0, result_len);
|
||||||
|
|
||||||
uint16_t sw;
|
uint8_t arr[result_len + 2]; // message + sw
|
||||||
size_t result_len;
|
memset(arr, 0, sizeof(arr));
|
||||||
|
|
||||||
uint8_t rawResult[resultLen /* message */ + 2 /* sw */];
|
uint16_t sw = 0;
|
||||||
memset(rawResult, 0, sizeof(rawResult));
|
size_t rlen = 0;
|
||||||
|
|
||||||
//uint8_t apdu[] = {0x90, 0x78, id, 0x00, resultLen, rawResult};
|
//uint8_t apdu[] = {0x90, 0x78, id, 0x00, resultLen, arr};
|
||||||
int res = FIDOExchange((sAPDU_t) {0x90, 0x78, id, 0x00, resultLen, rawResult}, rawResult, sizeof(rawResult),
|
int res = FIDOExchange((sAPDU_t) {0x90, 0x78, id, 0x00, result_len, arr}, arr, sizeof(arr), &rlen, &sw);
|
||||||
&result_len, &sw);
|
|
||||||
if (res) {
|
if (res) {
|
||||||
// error communicating
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sw != 0x9000) {
|
if (sw != 0x9000) {
|
||||||
// card returned error
|
return false;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy into the actual result buffer
|
memcpy(result, arr, result_len);
|
||||||
memcpy(result, rawResult, resultLen);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
|
||||||
memset(result, 0, resultLen);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// -*- mode: c; indent-tabs-mode: nil; tab-width: 3 -*-
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2019 micolous+git@gmail.com
|
// Copyright (C) 2019 micolous+git@gmail.com
|
||||||
//
|
//
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue