Skip to content

Commit

Permalink
appears to work - using normal mifare sim init
Browse files Browse the repository at this point in the history
working demo

works

seems to work so far

more cleanup and works

working copy

working, clean one more pass

cleanup continues

back in buisness babyyy

final cleanup before PR I hope
  • Loading branch information
orange-tangerine committed Jan 21, 2025
1 parent 32f06db commit 3eb0238
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 609 deletions.
749 changes: 323 additions & 426 deletions armsrc/emvsim.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions armsrc/emvsim.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
#define AUTHKEYNONE 0xff

void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak);
void annotate(uint8_t *cmd, uint8_t cmdsize);

#endif
178 changes: 6 additions & 172 deletions armsrc/i2c_direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@
#include "i2c.h"
#include "i2c_direct.h"

static uint8_t fci_template[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15};

static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59 };
static uint8_t pay2_response[] = { 0x03, 0x6f, 0x3e, 0x84, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0xa5, 0x2c, 0xbf, 0x0c, 0x29, 0x61, 0x27, 0x4f, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x63, 0x04, 0xdf, 0x20, 0x01, 0x80, 0x90, 0x00, 0x07, 0x9d};

static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint8_t *output, uint16_t *olen) {
LED_D_ON();

Expand All @@ -50,9 +45,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
// check if alloacted...
smartcard_command_t flags = p->flags;

//if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
//clear_trace();

if ((flags & SC_LOG) == SC_LOG)
set_tracing(true);
else
Expand All @@ -65,10 +57,9 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
if ((flags & SC_SELECT) == SC_SELECT) {
smart_card_atr_t card;
bool gotATR = GetATR(&card, true);
//reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));

if (gotATR == false) {
Dbprintf("No ATR received...\n");
//reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
goto OUT;
}
}
Expand All @@ -92,8 +83,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
);

if (res == false && g_dbglevel > 3) {
//DbpString(I2C_ERROR);
//reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
Dbprintf("SmartCardDirectSend: I2C_BufferWrite failed\n");
goto OUT;
}
Expand All @@ -109,11 +98,8 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
}

if (len == 2 && resp[1] == 0x61) {
//Dbprintf("Data to be read: len = %d\n", len);
//Dbprintf("\n");

uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, resp[2]};
//smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp));

smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
payload->flags = SC_RAW | SC_LOG;
payload->len = sizeof(cmd_getresp);
Expand All @@ -129,8 +115,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
resp[2] = 0x82;
AddCrc14A(resp, 3);

//Dbhexdump(5, &resp[0], false); // special print
//EmSendCmd(&resp[0], 5);
memcpy(output, resp, 5);
*olen = 5;
}
Expand All @@ -142,9 +126,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
resp[2] = 0x82;
AddCrc14A(resp, 3);

//Dbhexdump(5, &resp[0], false); // special print
//EmSendCmd14443aRaw(&resp[0], 5);
//EmSendCmd(&resp[0], 5);
memcpy(output, resp, 5);
*olen = 5;
FpgaDisableTracing();
Expand All @@ -154,108 +135,23 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
Dbprintf("***** sending it over the wire... len: %d =>\n", len);
resp[1] = prepend;

// if we have a generate AC request, lets extract the data and populate the template
if (resp[1] != 0xff && resp[2] == 0x77) {
Dbprintf("we have detected a generate ac response, lets repackage it!");
Dbhexdump(len, &resp[1], false); // special print
// 11 and 12 are trans counter.
// 16 to 24 are the cryptogram
// 27 to 34 is issuer application data
Dbprintf("atc: %d %d, cryptogram: %d ", resp[11], resp[12], resp[13]);

// then, on the template:
// 61 and 62 for counter
// 46 to 54 for cryptogram
// 36 to 43 for issuer application data

uint8_t template[] = { 0x00, 0x00, 0x77, 0x47, 0x82, 0x02, 0x39, 0x00, 0x57, 0x13, 0x47, 0x62, 0x28, 0x00, 0x05, 0x93, 0x38, 0x64, 0xd2, 0x70, 0x92, 0x01, 0x00, 0x00, 0x01, 0x42, 0x00, 0x00, 0x0f, 0x5f, 0x34, 0x01, 0x00, 0x9f, 0x10, 0x07, 0x06, 0x01, 0x12, 0x03, 0xa0, 0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4, 0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02, 0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04, 0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff};

// do the replacement
template[1] = resp[1]; // class bit

template[61] = resp[11];
template[62] = resp[12];

template[46] = resp[16];
template[47] = resp[17];
template[48] = resp[18];
template[49] = resp[19];
template[50] = resp[20];
template[51] = resp[21];
template[52] = resp[22];
template[53] = resp[23];
template[54] = resp[24];

template[36] = resp[27];
template[37] = resp[28];
template[38] = resp[29];
template[39] = resp[30];
template[40] = resp[31];
template[41] = resp[32];
template[42] = resp[33];

Dbprintf("\nrearranged is: ");
len = sizeof(template);
Dbhexdump(len, &template[0], false); // special print

AddCrc14A(&template[1], len - 3);
Dbprintf("\nafter crc rearranged is: ");
Dbhexdump(len, &template[0], false); // special print
Dbprintf("\n");

//EmSendCmd(&template[1], len-1);
memcpy(output, &template[1], len - 1);
*olen = len - 1;

BigBuf_free();
return;
}

//Dbhexdump(len, &resp[1], false); // special print
AddCrc14A(&resp[1], len);
Dbhexdump(len + 2, &resp[1], false); // special print

// Check we don't want to modify the response (application profile response)
//uint8_t modifyme[] = {0x03, 0x77, 0x0e, 0x82, 0x02};
Dbhexdump(len + 2, &resp[1], false);

BigBuf_free();

if (prepend == 0xff) {
Dbprintf("pdol request, we can can the response...");
Dbprintf("pdol request, we can ignore the response...");
return;
}

if (memcmp(&resp[2], &pay1_response[0], sizeof(pay1_response)) == 0 && true) {
Dbprintf("Switching out the pay1 response for a pay2 response...");
//EmSendCmd(&pay2_response[0], sizeof(pay2_response));
memcpy(output, &pay2_response[0], sizeof(pay2_response));
*olen = sizeof(pay2_response);
} else if (memcmp(&resp[1], &fci_template[0], 2) == 0 && true) {
Dbprintf("***** modifying response to have full fci template...!");
//EmSendCmd(&fci_template[0], sizeof(fci_template));
memcpy(output, &fci_template[0], sizeof(fci_template));
*olen = sizeof(fci_template);
} else {
//Dbprintf("***** not modifying response...");
//EmSendCmd(&resp[1], len + 2);
memcpy(output, &resp[1], len + 2);
*olen = len + 2;
}
memcpy(output, &resp[1], len + 2);
*olen = len + 2;

BigBuf_free();

//memcpy(saved_command, &resp[1], len+2);
//saved_command_len = len+2;
//EmSendCmd14443aRaw(&resp[1], len+2);
//FpgaDisableTracing();
//EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
}

//reply_ng(CMD_SMART_RAW, PM3_SUCCESS, resp, len);

OUT:
//BigBuf_free();
//set_tracing(false);
LEDsoff();
}

Expand All @@ -269,7 +165,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
dlen = data[4] + 5;
}

//smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + dlen);
smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + dlen);
if (payload == NULL) {
Dbprintf("failed to allocate memory");
Expand All @@ -285,7 +180,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
bool use_t0 = true;

if (active || active_select) {

payload->flags |= (SC_CONNECT | SC_CLEARLOG);
if (active_select)
payload->flags |= SC_SELECT;
Expand All @@ -296,7 +190,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
payload->flags |= SC_WAIT;
payload->wait_delay = timeout;
}
//Dbprintf("SIM Card timeout... %u ms", payload->wait_delay);

if (dlen > 0) {
if (use_t0)
Expand All @@ -305,66 +198,7 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
payload->flags |= SC_RAW;
}

////uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
//uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
//if (buf == NULL) {
// Dbprintf("failed to allocate memory");
// free(payload);
// return PM3_EMALLOC;
//}


//clearCommandBuffer();
//SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen);

//for (int i = 0; i < dlen; i++) {
// Dbprintf("%02x ", data[i]);
//}

SmartCardDirectSend(prepend, payload, output, olen);

//if (reply == false) {
// Dbprintf("failed to talk to smart card!!!");
// goto out;
//}

//// reading response from smart card
//int len = smart_response(buf, PM3_CMD_DATA_SIZE);
//if (len < 0) {
// free(payload);
// free(buf);
// return PM3_ESOFT;
//}

//if (buf[0] == 0x6C) {

// // request more bytes to download
// data[4] = buf[1];
// memcpy(payload->data, data, dlen);
// clearCommandBuffer();
// SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen);

// len = smart_response(buf, PM3_CMD_DATA_SIZE);

// data[4] = 0;
//}

//if (decode_tlv && len > 4) {
// TLVPrintFromBuffer(buf, len - 2);
//} else {
// if (len > 2) {
// Dbprintf("Response data:");
// Dbprintf(" # | bytes | ascii");
// Dbprintf("---+-------------------------------------------------+-----------------");
// print_hex_break(buf, len, 16);
// }
//}

//memcpy(buffer, buf, len);

//out:
//free(payload);
//free(buf);
return PM3_SUCCESS;
}

4 changes: 3 additions & 1 deletion armsrc/mifaresim.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ static uint8_t MifareMaxSector(uint16_t flags) {
}
}

static bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
bool MifareSimInit (uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
//static bool MifareSimInitX(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {

uint8_t uid_tmp[10] = {0};
// SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf
Expand Down Expand Up @@ -293,6 +294,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t s
rSAK[0] = rSAK_1k;
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK");
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_2K_MAX_BYTES)) {
Dbprintf("We got this to happen!!!\n");
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
rSAK[0] = rSAK_2k;
*rats = rRATS;
Expand Down
2 changes: 2 additions & 0 deletions armsrc/mifaresim.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define __MIFARESIM_H

#include "common.h"
#include "mifare.h"

#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
Expand All @@ -42,5 +43,6 @@
#define AUTHKEYNONE 0xff

void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t atqa, uint8_t sak);
bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len);

#endif
39 changes: 29 additions & 10 deletions client/src/emv/cmdemv.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,21 +643,21 @@ static int CmdEMVSmartToNFC(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

int uid_len = 0;
int uidlen = 0;
uint8_t uid[7] = {0};
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
CLIGetHexWithReturn(ctx, 2, uid, &uidlen);

if (uid_len == 0) {
if (uidlen == 0) {
PrintAndLogEx(SUCCESS, "No UID provided, using default.");
uint8_t default_uid[7] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
memcpy(uid, default_uid, sizeof(default_uid));
uid_len = sizeof(default_uid);
} else if (uid_len != 7) {
uidlen = sizeof(default_uid);
} else if (uidlen != 7) {
PrintAndLogEx(FAILED, "UID must be 7 bytes long.");
return PM3_EINVARG;
}

PrintAndLogEx(SUCCESS, "UID length is %d", uid_len);
PrintAndLogEx(SUCCESS, "UID length is %d", uidlen);

bool testMode = arg_get_lit(ctx, 1);
bool show_apdu = true;
Expand All @@ -670,7 +670,7 @@ static int CmdEMVSmartToNFC(const char *Cmd) {

CLIParserFree(ctx);

// todo: check this is relevant for us.
// todo for PR: check this is relevant for us.
SetAPDULogging(show_apdu);

struct {
Expand All @@ -681,14 +681,33 @@ static int CmdEMVSmartToNFC(const char *Cmd) {
uint8_t sak;
} PACKED payload;

memcpy(payload.uid, uid, uid_len);
payload.flags = 0x1204;
memcpy(payload.uid, uid, uidlen);

// Set up the flags for 2K mifare sim with RATS
uint16_t flags = 0;

FLAG_SET_UID_IN_DATA(flags, uidlen);
if (IS_FLAG_UID_IN_EMUL(flags)) {
PrintAndLogEx(WARNING, "Invalid parameter for UID");
CLIParserFree(ctx);
return PM3_EINVARG;
}

FLAG_SET_MF_SIZE(flags, MIFARE_2K_MAX_BYTES);
//snprintf(csize, sizeof(csize), "2K with RATS");
//k_sectors_cnt = MIFARE_2K_MAXSECTOR; // todo: delete

flags |= FLAG_ATQA_IN_DATA;
flags |= FLAG_SAK_IN_DATA;

payload.flags = flags;
//payload.flags = 0x1204;
payload.exitAfter = 0x1;
payload.atqa = 0x0;
payload.sak = 0x20;

clearCommandBuffer();
SendCommandNG(0x0386, (uint8_t *)&payload, sizeof(payload));
SendCommandNG(CMD_HF_ISO14443A_EMV_SIMULATE, (uint8_t *)&payload, sizeof(payload));

PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");

Expand Down
Loading

0 comments on commit 3eb0238

Please sign in to comment.