ADD: 'hf 14a apdu' @merlokk

This commit is contained in:
iceman1001 2017-11-10 20:47:31 +01:00
parent a3e923c529
commit 8b83db2c1b
6 changed files with 242 additions and 17 deletions

View file

@ -8,6 +8,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (Merlok)
- Added to proxmark ability to execute commands from stdin (pipe) (Merlok)
- Added new standalone mode "HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN" (@cjbrigato)
- Added to `hf 14a apdu` - exchange apdu via iso1443-4 (Merlok)
- Added to `hf 14a apdu` - apdu and tlv results parser (Merlok)
### Fixed
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)

View file

@ -114,6 +114,11 @@ CMDSRCS = crapto1/crapto1.c \
graph.c \
cmddata.c \
lfdemod.c \
emv/apduinfo.c\
emv/dump.c\
emv/tlv.c\
emv/emv_tags.c\
emv/emvcore.c\
cmdanalyse.c \
cmdhf.c \
cmdhf14a.c \
@ -328,3 +333,4 @@ $(DEPENDENCY_FILES): ;
.PRECIOUS: $(DEPENDENCY_FILES)
-include $(DEPENDENCY_FILES)

View file

@ -12,13 +12,7 @@
#include "cmdhf14a.h"
static int CmdHelp(const char *Cmd);
static void waitCmd(uint8_t iLen);
// structure and database for uid -> tagtype lookups
typedef struct {
uint8_t uid;
char* desc;
} manufactureName;
static int waitCmd(uint8_t iLen);
const manufactureName manufactureMapping[] = {
// ID, "Vendor Country"
@ -94,7 +88,6 @@ const manufactureName manufactureMapping[] = {
{ 0x00, "no tag-info available" } // must be the last entry
};
// get a product description based on the UID
// uid[8] tag uid
// returns description of the best match
@ -593,6 +586,160 @@ int CmdHF14ASniff(const char *Cmd) {
return 0;
}
void DropField() {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
clearCommandBuffer();
SendCommand(&c);
}
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen) {
uint16_t cmdc = 0;
if (activateField) {
cmdc |= ISO14A_CONNECT;
}
if (leaveSignalON)
cmdc |= ISO14A_NO_DISCONNECT;
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
// here length USB_CMD_DATA_SIZE=512
// timeout timeout14a * 1.06 / 100, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_SET_TIMEOUT | cmdc, (datainlen & 0xFFFF), 1000 * 1000 * 1.06 / 100}};
memcpy(c.d.asBytes, datain, datainlen);
SendCommand(&c);
uint8_t *recv;
UsbCommand resp;
if (activateField) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("APDU ERROR: Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] != 1) {
PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]);
return 1;
}
}
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
*dataoutlen = iLen - 2;
if (*dataoutlen < 0)
*dataoutlen = 0;
memcpy(dataout, recv, *dataoutlen);
if(!iLen) {
PrintAndLog("APDU ERROR: No APDU response.");
return 1;
}
// check block TODO
if (iLen == -2) {
PrintAndLog("APDU ERROR: Block type mismatch.");
return 2;
}
// CRC Check
if (iLen == -1) {
PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
return 3;
}
// check apdu length
if (iLen < 4) {
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
return 2;
}
} else {
PrintAndLog("APDU ERROR: Reply timeout.");
return 4;
}
return 0;
}
int CmdHF14AAPDU(const char *cmd) {
uint8_t data[USB_CMD_DATA_SIZE];
int datalen = 0;
bool activateField = false;
bool leaveSignalON = false;
bool decodeTLV = false;
if (strlen(cmd) < 2) {
PrintAndLog("Usage: hf 14a apdu [-s] [-k] [-t] <APDU (hex)>");
PrintAndLog(" -s activate field and select card");
PrintAndLog(" -k leave the signal field ON after receive response");
PrintAndLog(" -t executes TLV decoder if it possible. TODO!!!!");
return 0;
}
int cmdp = 0;
while(param_getchar(cmd, cmdp) != 0x00) {
char c = param_getchar(cmd, cmdp);
if ((c == '-') && (param_getlength(cmd, cmdp) == 2))
switch (param_getchar_indx(cmd, 1, cmdp)) {
case 's':
case 'S':
activateField = true;
break;
case 'k':
case 'K':
leaveSignalON = true;
break;
case 't':
case 'T':
decodeTLV = true;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
return 1;
}
if (isxdigit(c)) {
// len = data + PCB(1b) + CRC(2b)
switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data) - 1 - 2, &datalen)) {
case 1:
PrintAndLog("Invalid HEX value.");
return 1;
case 2:
PrintAndLog("APDU too large.");
return 1;
case 3:
PrintAndLog("Hex must have even number of digits.");
return 1;
}
// we get all the hex to end of line with spaces
break;
}
cmdp++;
}
PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, &datalen);
if (res)
return res;
PrintAndLog("<<<< %s", sprint_hex(data, datalen));
PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
// TLV decoder
if (decodeTLV && datalen > 4) {
TLVPrintFromBuffer(data, datalen - 2);
}
return 0;
}
int CmdHF14ACmdRaw(const char *cmd) {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
bool reply = 1;
@ -600,11 +747,11 @@ int CmdHF14ACmdRaw(const char *cmd) {
bool power = false;
bool active = false;
bool active_select = false;
bool no_rats = false;
uint16_t numbits = 0;
bool bTimeout = false;
uint32_t timeout = 0;
bool topazmode = false;
bool no_rats = false;
char buf[5]="";
int i = 0;
uint8_t data[USB_CMD_DATA_SIZE];
@ -740,15 +887,16 @@ int CmdHF14ACmdRaw(const char *cmd) {
SendCommand(&c);
if (reply) {
int res = 0;
if (active_select)
waitCmd(1);
if (datalen > 0)
res = waitCmd(1);
if (!res && datalen > 0)
waitCmd(0);
}
return 0;
}
static void waitCmd(uint8_t iSelect) {
static int waitCmd(uint8_t iSelect) {
UsbCommand resp;
uint16_t len = 0;
@ -766,12 +914,14 @@ static void waitCmd(uint8_t iSelect) {
}
if (!len)
return;
return 1;
PrintAndLog("%s", sprint_hex(resp.d.asBytes, len) );
} else {
PrintAndLog("timeout while waiting for reply.");
return 3;
}
return 0;
}
static command_t CommandTable[] = {
@ -782,6 +932,7 @@ static command_t CommandTable[] = {
{"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443-a UIDs in one go"},
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"},
{"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"},
{"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"},
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
{NULL, NULL, 0, NULL}
};

View file

@ -30,6 +30,14 @@
#include "cmdhfmfu.h"
#include "cmdhf.h" // list cmd
#include "mifarehost.h"
#include "emv/apduinfo.h"
#include "emv/emvcore.h"
// structure and database for uid -> tagtype lookups
typedef struct {
uint8_t uid;
char* desc;
} manufactureName;
extern int CmdHF14A(const char *Cmd);
extern int CmdHF14AList(const char *Cmd);
@ -41,6 +49,9 @@ extern int CmdHF14ACmdRaw(const char *Cmd);
extern int CmdHF14ACUIDs(const char *Cmd);
extern char* getTagInfo(uint8_t uid);
extern void DropField();
extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen);
extern int usage_hf_14a_sim(void);
extern int usage_hf_14a_sniff(void);

View file

@ -379,11 +379,19 @@ int param_getlength(const char *line, int paramnum)
return en - bg + 1;
}
char param_getchar(const char *line, int paramnum)
{
char param_getchar(const char *line, int paramnum) {
return param_getchar_indx(line, 0, paramnum);
}
char param_getchar_indx(const char *line, int indx, int paramnum) {
int bg, en;
if (param_getptr(line, &bg, &en, paramnum)) return 0;
return line[bg];
if (param_getptr(line, &bg, &en, paramnum)) return 0x00;
if (bg + indx > en)
return '\0';
return line[bg + indx];
}
uint8_t param_get8(const char *line, int paramnum)
@ -487,6 +495,51 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt)
return 0;
}
int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen) {
int bg, en;
uint32_t temp;
char buf[5] = {0};
if (param_getptr(line, &bg, &en, paramnum)) return 1;
*datalen = 0;
int indx = bg;
while (line[indx]) {
if (line[indx] == '\t' || line[indx] == ' ')
continue;
if (isxdigit(line[indx])) {
buf[strlen(buf) + 1] = 0x00;
buf[strlen(buf)] = line[indx];
} else {
// if we have symbols other than spaces and hex
return 1;
}
if (*datalen >= maxdatalen) {
// if we dont have space in buffer and have symbols to translate
return 2;
}
if (strlen(buf) >= 2) {
sscanf(buf, "%x", &temp);
data[*datalen] = (uint8_t)(temp & 0xff);
*buf = 0;
(*datalen)++;
}
indx++;
}
if (strlen(buf) > 0)
//error when not completed hex bytes
return 3;
return 0;
}
int param_getstr(const char *line, int paramnum, char * str)
{
int bg, en;

View file

@ -114,6 +114,7 @@ extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t b
extern int param_getlength(const char *line, int paramnum);
extern char param_getchar(const char *line, int paramnum);
extern char param_getchar_indx(const char *line, int indx, int paramnum);
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
extern uint8_t param_get8(const char *line, int paramnum);
extern uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
@ -123,6 +124,7 @@ extern uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination
extern uint8_t param_isdec(const char *line, int paramnum);
extern int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
extern int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt);
extern int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen);
extern int param_getstr(const char *line, int paramnum, char * str);
extern int hextobinarray( char *target, char *source);