looping for smart card, inverted the silent to verbose, updated cardhelper stuff

This commit is contained in:
iceman1001 2021-04-04 17:01:43 +02:00
commit d19da982f0
9 changed files with 316 additions and 107 deletions

View file

@ -32,7 +32,7 @@
#define I2C_ERROR "I2C_WaitAck Error" #define I2C_ERROR "I2C_WaitAck Error"
static volatile uint32_t c; //static
// Direct use the loop to delay. 6 instructions loop, Masterclock 48MHz, // Direct use the loop to delay. 6 instructions loop, Masterclock 48MHz,
// delay=1 is about 200kbps // delay=1 is about 200kbps
@ -40,6 +40,7 @@ static volatile uint32_t c;
// I2CSpinDelayClk(4) = 12.31us // I2CSpinDelayClk(4) = 12.31us
// I2CSpinDelayClk(1) = 3.07us // I2CSpinDelayClk(1) = 3.07us
static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
volatile uint32_t c;
for (c = delay * 2; c; c--) {}; for (c = delay * 2; c; c--) {};
} }
@ -160,7 +161,7 @@ static bool WaitSCL_H_delay(uint32_t delay) {
// 5000 * 3.07us = 15350us. 15.35ms // 5000 * 3.07us = 15350us. 15.35ms
// 15000 * 3.07us = 46050us. 46.05ms // 15000 * 3.07us = 46050us. 46.05ms
static bool WaitSCL_H(void) { static bool WaitSCL_H(void) {
return WaitSCL_H_delay(15000); return WaitSCL_H_delay(10000);
} }
static bool WaitSCL_L_delay(uint32_t delay) { static bool WaitSCL_L_delay(uint32_t delay) {
@ -174,7 +175,7 @@ static bool WaitSCL_L_delay(uint32_t delay) {
} }
// 5000 * 3.07us = 15350us. 15.35ms // 5000 * 3.07us = 15350us. 15.35ms
static bool WaitSCL_L(void) { static bool WaitSCL_L(void) {
return WaitSCL_L_delay(15000); return WaitSCL_L_delay(10000);
} }
// Wait max 1800ms or until SCL goes LOW. // Wait max 1800ms or until SCL goes LOW.
@ -219,10 +220,7 @@ static bool I2C_WaitForSim(void) {
// 8051 speaks with smart card. // 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms // 1000*50*3.07 = 153.5ms
// 1byte transfer == 1ms with max frame being 256bytes // 1byte transfer == 1ms with max frame being 256bytes
if (!WaitSCL_H_delay(10 * 1000 * 30)) return WaitSCL_H_delay(10 * 1000 * 50);
return false;
return true;
} }
// send i2c STOP // send i2c STOP
@ -713,6 +711,9 @@ void SmartCardAtr(void) {
I2C_Reset_EnterMainProgram(); I2C_Reset_EnterMainProgram();
smart_card_atr_t card; smart_card_atr_t card;
int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT; int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT;
if (res == PM3_ETIMEOUT) {
I2C_Reset_EnterMainProgram();
}
reply_ng(CMD_SMART_ATR, res, (uint8_t *)&card, sizeof(smart_card_atr_t)); reply_ng(CMD_SMART_ATR, res, (uint8_t *)&card, sizeof(smart_card_atr_t));
set_tracing(false); set_tracing(false);
LEDsoff(); LEDsoff();

View file

@ -41,45 +41,6 @@ static int CmdHelp(const char *Cmd);
"DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
// Sample private RSA Key
// Following example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c)
// private key - Exponent D
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
"66CA472BC44D253102F8B4A9D3BFA750" \
"91386C0077937FE33FA3252D28855837" \
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
"DF79C5CE07EE72C7F123142198164234" \
"CABB724CF78B8173B9F880FC86322407" \
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
"071513A1E85B5DFA031F21ECAE91A34D"
// prime P
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
"2C01CAD19EA484A87EA4377637E75500" \
"FCB2005C5C7DD6EC4AC023CDA285D796" \
"C3D9E75E1EFC42488BB4F1D13AC30A57"
// prime Q
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
"910E4168387E3C30AA1E00C339A79508" \
"8452DD96A9A5EA5D9DCA68DA636032AF"
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
"3C94D22288ACD763FD8E5600ED4A702D" \
"F84198A5F06C2E72236AE490C93F07F8" \
"3CC559CD27BC2D1CA488811730BB5725"
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
"D8AAEA56749EA28623272E4F7D0592AF" \
"7C1F1313CAC9471B5C523BFE592F517B" \
"407A1BD76C164B93DA2D32A383E58357"
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
"F38D18D2B2F0E2DD275AA977E2BF4411" \
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
"A74206CEC169D74BF5A8C50D6F48EA08"
int rdv4_get_signature(rdv40_validation_t *out) { int rdv4_get_signature(rdv40_validation_t *out) {
if (out == NULL) { if (out == NULL) {
@ -107,7 +68,6 @@ int rdv4_get_signature(rdv40_validation_t *out) {
// validate signature // validate signature
int rdv4_validate(rdv40_validation_t *mem) { int rdv4_validate(rdv40_validation_t *mem) {
// Flash ID hash (sha1) // Flash ID hash (sha1)
uint8_t sha_hash[20] = {0}; uint8_t sha_hash[20] = {0};
mbedtls_sha1(mem->flashid, sizeof(mem->flashid), sha_hash); mbedtls_sha1(mem->flashid, sizeof(mem->flashid), sha_hash);
@ -129,7 +89,6 @@ int rdv4_validate(rdv40_validation_t *mem) {
return PM3_EFAILED; return PM3_EFAILED;
} }
static int rdv4_sign_write(uint8_t *signature, uint8_t slen){ static int rdv4_sign_write(uint8_t *signature, uint8_t slen){
// save to mem // save to mem
clearCommandBuffer(); clearCommandBuffer();
@ -485,7 +444,6 @@ static int CmdFlashMemInfo(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
// set up PK key context now. // set up PK key context now.
mbedtls_pk_context pkctx; mbedtls_pk_context pkctx;
mbedtls_pk_init( &pkctx ); mbedtls_pk_init( &pkctx );
@ -536,6 +494,7 @@ static int CmdFlashMemInfo(const char *Cmd) {
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
return res; return res;
} }
res = rdv4_validate(&mem); res = rdv4_validate(&mem);
// Flash ID hash (sha1) // Flash ID hash (sha1)

View file

@ -35,6 +35,7 @@
#define ICLASS_KEYS_MAX 8 #define ICLASS_KEYS_MAX 8
#define ICLASS_AUTH_RETRY 10 #define ICLASS_AUTH_RETRY 10
#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" #define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -127,6 +128,89 @@ uint8_t card_app2_limit[] = {
0xff, 0xff,
}; };
iclass_config_card_item_t iclass_config_types[14]= {
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
{"", "", ""},
// must be the last entry
{"no config card info available", "", ""}
};
static bool check_config_card(const iclass_config_card_item_t *o) {
if (o == NULL || strlen(o->desc) == 0) {
PrintAndLogEx(INFO, "No data available");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass config -l") "` to download from cardhelper");
return false;
}
return true;
}
static int load_config_cards(void) {
PrintAndLogEx(INFO, "Detecting cardhelper...");
if (IsCardHelperPresent(false) == false)
return PM3_ENODATA;
for (int i = 0; i < ARRAYLEN(iclass_config_types); ++i) {
PrintAndLogEx(INPLACE, "loading idx %i", i);
iclass_config_card_item_t *ret = &iclass_config_types[i];
uint8_t desc[70] = {0};
if (GetConfigCardStrByIdx(i, desc) == PM3_SUCCESS) {
memcpy(ret->desc, desc, sizeof(desc));
}
uint8_t blocks[16] = {0};
if (GetConfigCardByIdx(i, blocks) == PM3_SUCCESS) {
memcpy(ret->blk6, blocks, sizeof(ret->blk6));
memcpy(ret->blk7, blocks + sizeof(ret->blk6), sizeof(ret->blk7));
}
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass configcard -p") "` to list all");
return PM3_SUCCESS;
}
static const iclass_config_card_item_t *get_config_card_item(uint8_t idx) {
iclass_config_card_item_t *ret = &iclass_config_types[idx];
return ret;
}
static void print_config_cards(void) {
if (check_config_card(&iclass_config_types[0])) {
PrintAndLogEx(INFO, "---- " _CYAN_("Config cards available") " ------------");
for (int i = 0; i < ARRAYLEN(iclass_config_types); ++i) {
PrintAndLogEx(INFO, "%2d, %s", i, iclass_config_types[i].desc);
}
PrintAndLogEx(NORMAL, "");
}
}
static void print_config_card(const iclass_config_card_item_t *o) {
if (check_config_card(o)) {
PrintAndLogEx(INFO, "description... %s", o->desc);
PrintAndLogEx(INFO, "block 6....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk6, sizeof(o->blk6)));
PrintAndLogEx(INFO, "block 7....... " _YELLOW_("%s"), sprint_hex_inrow(o->blk7, sizeof(o->blk7)));
}
}
static void generate_config_card(const iclass_config_card_item_t *o) {
if (check_config_card(o)) {
}
}
static uint8_t isset(uint8_t val, uint8_t mask) { static uint8_t isset(uint8_t val, uint8_t mask) {
return (val & mask); return (val & mask);
} }
@ -937,7 +1021,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
uint8_t dec_data[8] = {0}; uint8_t dec_data[8] = {0};
bool use_sc = false; bool use_sc = false;
if (have_key == false) { if (have_key == false) {
use_sc = IsCryptoHelperPresent(verbose); use_sc = IsCardHelperPresent(verbose);
if (use_sc == false) { if (use_sc == false) {
size_t keylen = 0; size_t keylen = 0;
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
@ -1047,7 +1131,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
PrintAndLogEx(INFO, "Block 7 decoder"); PrintAndLogEx(INFO, "Block 7 decoder");
char hexstr[8 + 1] = {0}; char hexstr[16 + 1] = {0};
hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true); hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true);
char binstr[8 * 8 + 1] = {0}; char binstr[8 * 8 + 1] = {0};
@ -1157,7 +1241,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
bool use_sc = false; bool use_sc = false;
if (have_key == false) { if (have_key == false) {
use_sc = IsCryptoHelperPresent(verbose); use_sc = IsCardHelperPresent(verbose);
if (use_sc == false) { if (use_sc == false) {
size_t keylen = 0; size_t keylen = 0;
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
@ -2008,7 +2092,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
if (memcmp(data, empty, 8) == 0) if (memcmp(data, empty, 8) == 0)
return PM3_SUCCESS; return PM3_SUCCESS;
bool use_sc = IsCryptoHelperPresent(verbose); bool use_sc = IsCardHelperPresent(verbose);
if (use_sc == false) if (use_sc == false)
return PM3_SUCCESS; return PM3_SUCCESS;
@ -3391,7 +3475,7 @@ static int CmdHFiClassEncode(const char *Cmd) {
} }
if (have_enc_key == false) { if (have_enc_key == false) {
use_sc = IsCryptoHelperPresent(false); use_sc = IsCardHelperPresent(false);
if (use_sc == false) { if (use_sc == false) {
size_t keylen = 0; size_t keylen = 0;
int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen); int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen);
@ -3489,6 +3573,55 @@ static int CmdHFiClassAutopwn(const char *Cmd) {
} }
*/ */
static int CmdHFiClassConfigCard(const char * Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass configcard",
"Manage reader configuration card via Cardhelper",
"hf iclass configcard -l --> download config cards "
"hf iclass configcard -p --> print config card"
"hf iclass configcard -g --ki 1 --> generate config dump file based on idx 1"
);
void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "ki", "<dec>", "select index in list"),
arg_lit0("g", NULL, "generate card dump file"),
arg_lit0("l", NULL, "load available cards"),
arg_lit0("p", NULL, "print available cards"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int idx = arg_get_int_def(ctx, 1, -1);
bool generate = arg_get_lit(ctx, 2);
bool load = arg_get_lit(ctx, 3);
bool print = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (load) {
if (load_config_cards() != PM3_SUCCESS) {
PrintAndLogEx(INFO, "failed to load, check your cardhelper");
}
}
if (print) {
print_config_cards();
}
if (idx >= 0) {
const iclass_config_card_item_t *item = get_config_card_item(idx);
print_config_card(item);
}
if (generate) {
const iclass_config_card_item_t *item = get_config_card_item(idx);
generate_config_card(item);
}
return PM3_SUCCESS;
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
@ -3514,6 +3647,7 @@ static command_t CommandTable[] = {
{"eview", CmdHFiClassEView, IfPm3Iclass, "View emulator memory"}, {"eview", CmdHFiClassEView, IfPm3Iclass, "View emulator memory"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
{"configcard", CmdHFiClassConfigCard, AlwaysAvailable, "Reader configuration card"},
{"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "Calc diversified keys (blocks 3 & 4) to write new keys"}, {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "Calc diversified keys (blocks 3 & 4) to write new keys"},
{"encode", CmdHFiClassEncode, AlwaysAvailable, "Encode binary wiegand to block 7"}, {"encode", CmdHFiClassEncode, AlwaysAvailable, "Encode binary wiegand to block 7"},
{"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "Encrypt given block data"}, {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "Encrypt given block data"},

View file

@ -28,6 +28,12 @@ typedef struct iclass_prekey {
uint8_t key[8]; uint8_t key[8];
} iclass_prekey_t; } iclass_prekey_t;
typedef struct {
char desc[70];
uint8_t blk6[8];
uint8_t blk7[8];
} iclass_config_card_item_t;
int CmdHFiClass(const char *Cmd); int CmdHFiClass(const char *Cmd);
int info_iclass(void); int info_iclass(void);

View file

@ -255,31 +255,43 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
} }
} }
static int smart_wait(uint8_t *data, bool silent) { static int smart_wait(uint8_t *data, bool verbose) {
int i = 5;
uint32_t len = 0;
do {
clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
if (!silent) PrintAndLogEx(WARNING, "smart card response timeout");
len = resp.oldarg[0];
if (len == 0) {
if (verbose) PrintAndLogEx(WARNING, "smart card response failed");
return -2;
}
memcpy(data, resp.data.asBytes, len);
if (len >= 2) {
if (verbose) {
PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
}
} else {
if (verbose) {
PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8));
}
}
return len;
}
} while (i--);
if (verbose) {
PrintAndLogEx(WARNING, "smart card response timeout");
}
return -1; return -1;
} }
uint32_t len = resp.oldarg[0]; static int smart_responseEx(uint8_t *data, bool verbose) {
if (!len) {
if (!silent) PrintAndLogEx(WARNING, "smart card response failed");
return -2;
}
memcpy(data, resp.data.asBytes, len);
if (len >= 2) {
if (!silent) PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1]));
} else {
if (!silent) PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8));
}
return len; int datalen = smart_wait(data, verbose);
}
static int smart_responseEx(uint8_t *data, bool silent) {
int datalen = smart_wait(data, silent);
bool needGetData = false; bool needGetData = false;
if (datalen < 2) { if (datalen < 2) {
@ -293,13 +305,13 @@ static int smart_responseEx(uint8_t *data, bool silent) {
if (needGetData) { if (needGetData) {
int len = data[datalen - 1]; int len = data[datalen - 1];
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); if (verbose) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus)); SendCommandMIX(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus));
datalen = smart_wait(data, silent); datalen = smart_wait(data, verbose);
if (datalen < 2) { if (datalen < 2) {
goto out; goto out;
@ -310,7 +322,7 @@ static int smart_responseEx(uint8_t *data, bool silent) {
// data with ACK // data with ACK
if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK
if (data[0] != ISO7816_GET_RESPONSE) { if (data[0] != ISO7816_GET_RESPONSE) {
if (!silent) { if (verbose) {
PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]); PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]);
} }
datalen = 0; datalen = 0;
@ -321,7 +333,7 @@ static int smart_responseEx(uint8_t *data, bool silent) {
memmove(data, &data[1], datalen); memmove(data, &data[1], datalen);
} else { } else {
// wrong length // wrong length
if (!silent) { if (verbose) {
PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3); PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3);
} }
} }
@ -333,7 +345,7 @@ out:
} }
static int smart_response(uint8_t *data) { static int smart_response(uint8_t *data) {
return smart_responseEx(data, false); return smart_responseEx(data, true);
} }
static int CmdSmartRaw(const char *Cmd) { static int CmdSmartRaw(const char *Cmd) {
@ -358,7 +370,7 @@ static int CmdSmartRaw(const char *Cmd) {
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool reply = arg_get_lit(ctx, 1); bool reply = (arg_get_lit(ctx, 1) == false);
bool active = arg_get_lit(ctx, 2); bool active = arg_get_lit(ctx, 2);
bool active_select = arg_get_lit(ctx, 3); bool active_select = arg_get_lit(ctx, 3);
bool decode_tlv = arg_get_lit(ctx, 4); bool decode_tlv = arg_get_lit(ctx, 4);
@ -807,7 +819,7 @@ static void smart_brute_prim(void) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, 5, 0, get_card_data + i, 5); SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, 5, 0, get_card_data + i, 5);
int len = smart_responseEx(buf, true); int len = smart_responseEx(buf, false);
if (len > 2) { if (len > 2) {
// if ( decodeTLV ) { // if ( decodeTLV ) {
@ -849,14 +861,14 @@ static int smart_brute_sfi(bool decodeTLV) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD)); SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD));
len = smart_responseEx(buf, true); len = smart_responseEx(buf, false);
if (buf[0] == 0x6C) { if (buf[0] == 0x6C) {
READ_RECORD[4] = buf[1]; READ_RECORD[4] = buf[1];
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD)); SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(READ_RECORD), 0, READ_RECORD, sizeof(READ_RECORD));
len = smart_responseEx(buf, true); len = smart_responseEx(buf, false);
READ_RECORD[4] = 0; READ_RECORD[4] = 0;
} }
@ -892,7 +904,7 @@ static void smart_brute_options(bool decodeTLV) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS)); SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, sizeof(GET_PROCESSING_OPTIONS), 0, GET_PROCESSING_OPTIONS, sizeof(GET_PROCESSING_OPTIONS));
int len = smart_responseEx(buf, true); int len = smart_responseEx(buf, false);
if (len > 4) { if (len > 4) {
PrintAndLogEx(SUCCESS, "Got processing options"); PrintAndLogEx(SUCCESS, "Got processing options");
if (decodeTLV) { if (decodeTLV) {
@ -988,7 +1000,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, hexlen, 0, cmddata, hexlen); SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, hexlen, 0, cmddata, hexlen);
int len = smart_responseEx(buf, true); int len = smart_responseEx(buf, false);
if (len < 3) if (len < 3)
continue; continue;
@ -1056,12 +1068,16 @@ int CmdSmartcard(const char *Cmd) {
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0; *dataoutlen = 0;
if (activateCard) if (activateCard) {
smart_select(true, NULL); if (smart_select(false, NULL) == false) {
PrintAndLogEx(DEBUG, "APDU SC - select card failed");
return 1;
}
}
PrintAndLogEx(DEBUG, "APDU SC"); PrintAndLogEx(DEBUG, "APDU SC");
@ -1073,7 +1089,7 @@ int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCar
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen); SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
int len = smart_responseEx(dataout, silent); int len = smart_responseEx(dataout, verbose);
if (len < 0) { if (len < 0) {
return 1; return 1;
} }
@ -1090,14 +1106,14 @@ int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCar
// something fishy: we have only 5 bytes but we put datainlen in arg1? // something fishy: we have only 5 bytes but we put datainlen in arg1?
SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data)); SendCommandMIX(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
len = smart_responseEx(dataout, silent); len = smart_responseEx(dataout, verbose);
} }
*dataoutlen = len; *dataoutlen = len;
return 0; return 0;
} }
bool smart_select(bool silent, smart_card_atr_t *atr) { bool smart_select(bool verbose, smart_card_atr_t *atr) {
if (atr) if (atr)
memset(atr, 0, sizeof(smart_card_atr_t)); memset(atr, 0, sizeof(smart_card_atr_t));
@ -1106,12 +1122,12 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) { if (!WaitForResponseTimeout(CMD_SMART_ATR, &resp, 2500)) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); if (verbose) PrintAndLogEx(WARNING, "smart card select failed");
return false; return false;
} }
if (resp.status != PM3_SUCCESS) { if (resp.status != PM3_SUCCESS) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); if (verbose) PrintAndLogEx(WARNING, "smart card select failed");
return false; return false;
} }
@ -1121,7 +1137,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
if (atr) if (atr)
memcpy(atr, &card, sizeof(smart_card_atr_t)); memcpy(atr, &card, sizeof(smart_card_atr_t));
if (!silent) if (verbose)
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
return true; return true;

View file

@ -16,7 +16,7 @@
int CmdSmartcard(const char *Cmd); int CmdSmartcard(const char *Cmd);
bool smart_select(bool silent, smart_card_atr_t *atr); bool smart_select(bool verbose, smart_card_atr_t *atr);
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif #endif

View file

@ -307,7 +307,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea
case ECC_CONTACT: case ECC_CONTACT:
res = 1; res = 1;
if (IfPm3Smartcard()) if (IfPm3Smartcard())
res = ExchangeAPDUSC(true, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); res = ExchangeAPDUSC(false, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
if (res) { if (res) {
return res; return res;

View file

@ -17,19 +17,26 @@
#define CARD_INS_DECRYPT 0x01 #define CARD_INS_DECRYPT 0x01
#define CARD_INS_ENCRYPT 0x02 #define CARD_INS_ENCRYPT 0x02
#define CARD_INS_VEIRFY_RRG 0x05
#define CARD_INS_DECODE 0x06 #define CARD_INS_DECODE 0x06
#define CARD_INS_NUMBLOCKS 0x07 #define CARD_INS_NUMBLOCKS 0x07
#define CARD_INS_PINSIZE 0x08 #define CARD_INS_PINSIZE 0x08
#define CARD_INS_CC 0x81
#define CARD_INS_CC_DESC 0x82
static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// look for CryptoHelper // look for CardHelper
bool IsCryptoHelperPresent(bool verbose) { bool IsCardHelperPresent(bool verbose) {
if (IfPm3Smartcard()) { if (IfPm3Smartcard()) {
int resp_len = 0; int resp_len = 0;
uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00};
uint8_t resp[20] = {0}; uint8_t resp[20] = {0};
ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len);
if (resp_len < 8) {
return false;
}
if (strstr("CryptoHelper", (char *)resp) == 0) { if (strstr("CryptoHelper", (char *)resp) == 0) {
if (verbose) { if (verbose) {
@ -48,7 +55,7 @@ static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
cmd[1] = ins; cmd[1] = ins;
memcpy(cmd + 5, src, 8); memcpy(cmd + 5, src, 8);
ExchangeAPDUSC(true, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len); ExchangeAPDUSC(false, cmd, sizeof(cmd), false, false, dec, sizeof(dec), &resp_len);
if (resp_len == 10) { if (resp_len == 10) {
memcpy(dest, dec, 8); memcpy(dest, dec, 8);
@ -74,12 +81,23 @@ void DecodeBlock6(uint8_t *src) {
memcpy(c + 6, src, 8); memcpy(c + 6, src, 8);
// first part // first part
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
if (resp_len < 11) {
return;
}
PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9);
// second part // second part
c[5] = 0x02; c[5] = 0x02;
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len);
if (resp_len < 11) {
return;
}
PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9);
} }
@ -89,7 +107,13 @@ uint8_t GetNumberBlocksForUserId(uint8_t *src) {
uint8_t resp[254] = {0}; uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_NUMBLOCKS, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t c[] = {0x96, CARD_INS_NUMBLOCKS, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(c + 5, src, 8); memcpy(c + 5, src, 8);
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len);
if (resp_len < 8) {
return 0;
}
return resp[8]; return resp[8];
} }
@ -99,10 +123,75 @@ uint8_t GetPinSize(uint8_t *src) {
uint8_t resp[254] = {0}; uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(c + 5, src, 8); memcpy(c + 5, src, 8);
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len);
if (resp_len < 2) {
return 0;
}
if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) { if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) {
return resp[8]; return resp[8];
} }
return 0; return 0;
} }
int GetConfigCardByIdx(uint8_t typ, uint8_t *blocks) {
if (blocks == NULL)
return PM3_EINVARG;
int resp_len = 0;
uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_CC, 0x00, 0x00, 17, typ, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
if (resp_len < 2) {
return PM3_ESOFT;
}
if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) {
memcpy(blocks, resp + 1, 16);
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
int GetConfigCardStrByIdx(uint8_t typ, uint8_t *out) {
if (out == NULL)
return PM3_EINVARG;
int resp_len = 0;
uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_CC_DESC, 0x00, 0x00, 1, typ};
ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
if (resp_len < 2) {
return PM3_ESOFT;
}
if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) {
memcpy(out, resp + 1, resp_len - 2 - 1);
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
int VerifyRdv4Signature(uint8_t *memid, uint8_t *signature) {
if (memid == NULL || signature == NULL)
return PM3_EINVARG;
int resp_len = 0;
uint8_t resp[254] = {0};
uint8_t c[5 + 8 + 128] = {0x96, CARD_INS_VEIRFY_RRG, 0x00, 0x00, 8 + 128};
memcpy(c + 5, memid, 8);
memcpy(c + 5 + 8, signature, 128);
ExchangeAPDUSC(false, c, sizeof(c), true, false, resp, sizeof(resp), &resp_len);
if (resp_len < 2) {
return PM3_ESOFT;
}
if (memcmp(resp + resp_len - 4, "\x6f\x6b\x90\x00", 4) == 0) {
return PM3_SUCCESS;
}
return PM3_ESOFT;
}

View file

@ -14,10 +14,14 @@
#include <ctype.h> #include <ctype.h>
#include "common.h" #include "common.h"
bool IsCryptoHelperPresent(bool verbose); bool IsCardHelperPresent(bool verbose);
bool Encrypt(uint8_t *src, uint8_t *dest); bool Encrypt(uint8_t *src, uint8_t *dest);
bool Decrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest);
void DecodeBlock6(uint8_t *src); void DecodeBlock6(uint8_t *src);
uint8_t GetNumberBlocksForUserId(uint8_t *src); uint8_t GetNumberBlocksForUserId(uint8_t *src);
uint8_t GetPinSize(uint8_t *src); uint8_t GetPinSize(uint8_t *src);
int GetConfigCardByIdx(uint8_t typ, uint8_t *blocks);
int GetConfigCardStrByIdx(uint8_t typ, uint8_t *out);
int VerifyRdv4Signature(uint8_t *memid, uint8_t *signature);
#endif #endif