From: Merlokbr@gmail.com Date: Thu, 26 May 2011 15:20:03 +0000 (+0000) Subject: nested authentication works ok (tested) X-Git-Tag: v1.0.0~261 X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/4abe4f5867e52615c0e053a2bab4b3b129b12d45 nested authentication works ok (tested) and code cleaning --- diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index bb280807..efe6bfc4 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1502,7 +1502,6 @@ int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, u uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes - //uint8_t* uid = resp + 7; uint8_t sak = 0x04; // cascade uid int cascade_level = 0; @@ -1520,9 +1519,6 @@ int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, u if(resp_data) memcpy(resp_data->atqa, resp, 2); - //ReaderTransmit(sel_all,sizeof(sel_all)); --- avoid duplicate SELECT request - //if(!ReaderReceive(uid)) return 0; - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. @@ -1778,17 +1774,17 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; + byte_t isOK = 0; + byte_t dataoutbuf[16]; uint8_t uid[7]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; -// tracing = false; + traceLen = 0; +// tracing = false; iso14443a_setup(); @@ -1802,7 +1798,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, 0)) { + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { Dbprintf("Auth error"); break; }; @@ -1831,14 +1827,14 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; memcpy(ack.d.asBytes, dataoutbuf, 16); LED_B_ON(); UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); + LED_B_OFF(); // Thats it... @@ -1861,17 +1857,17 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; uint8_t uid[8]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; -// tracing = false; + traceLen = 0; +// tracing = false; iso14443a_setup(); @@ -1885,7 +1881,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; }; - if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, 0)) { + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { Dbprintf("Auth error"); break; }; @@ -1926,7 +1922,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; memcpy(ack.d.asBytes, dataoutbuf, 16 * 2); @@ -1940,7 +1936,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - // Thats it... + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // tracing = TRUE; @@ -1953,25 +1949,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) //----------------------------------------------------------------------------- void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params + // params uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; - byte_t blockdata[16]; + byte_t blockdata[16]; ui64Key = bytes_to_num(datain, 6); memcpy(blockdata, datain + 10, 16); // variables - byte_t isOK = 0; + byte_t isOK = 0; uint8_t uid[8]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; + traceLen = 0; // tracing = false; iso14443a_setup(); @@ -1986,7 +1982,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, 0)) { + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { Dbprintf("Auth error"); break; }; @@ -2015,7 +2011,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; @@ -2024,7 +2020,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_B_OFF(); - // Thats it... + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // tracing = TRUE; @@ -2037,7 +2033,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) //----------------------------------------------------------------------------- void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params + // params uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; @@ -2045,16 +2041,16 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK = 0; + byte_t isOK = 0; uint8_t uid[8]; uint32_t cuid; uint8_t dataoutbuf[16]; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; + traceLen = 0; // tracing = false; iso14443a_setup(); @@ -2069,13 +2065,13 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, 0)) { + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { Dbprintf("Auth error"); break; }; // nested authenticate block = (blockNo + 1) - if(mifare_classic_auth(pcs, (uint32_t)bytes_to_num(uid, 4), blockNo + 1, keyType, ui64Key, 1)) { + if(mifare_classic_auth(pcs, (uint32_t)bytes_to_num(uid, 4), blockNo + 1, keyType, ui64Key, AUTH_NESTED)) { Dbprintf("Auth error"); break; }; @@ -2097,14 +2093,14 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - DbpString("NESTED FINISHED"); + DbpString("NESTED FINISHED"); // add trace trailer uid[0] = 0xff; uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; memcpy(ack.d.asBytes, dataoutbuf, 16); @@ -2113,7 +2109,7 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - // Thats it... + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // tracing = TRUE; diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index ede1cbc9..59dafedc 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -50,7 +50,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, int len = ReaderReceive(answer); - if (crypted) { + if (crypted == CRYPT_ALL) { if (len == 1) { res = 0; for (pos = 0; pos < 4; pos++) @@ -72,20 +72,20 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested) { // variables - int len; + int len; uint32_t pos; uint8_t tmp4[4]; - byte_t par = 0; - byte_t ar[4]; + byte_t par = 0; + byte_t ar[4]; uint32_t nt, ntpp; // Supplied tag nonce uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); - // Transmit MIFARE_CLASSIC_AUTH + // Transmit MIFARE_CLASSIC_AUTH len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer); // Dbprintf("rand nonce len: %x", len); - if (len != 4) return 1; + if (len != 4) return 1; ar[0] = 0x55; ar[1] = 0x41; @@ -94,50 +94,60 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, // Save the tag nonce (nt) nt = bytes_to_num(receivedAnswer, 4); - Dbprintf("uid: %x nt: %x", uid, nt); // ----------------------------- crypto1 create - // Init cipher with key + if (isNested) + crypto1_destroy(pcs); + + // Init cipher with key crypto1_create(pcs, ui64Key); - // Load (plain) uid^nt into the cipher - crypto1_word(pcs, nt ^ uid, 0); + if (isNested == AUTH_NESTED) { + // decrypt nt with help of new key + nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; + } else { + // Load (plain) uid^nt into the cipher + crypto1_word(pcs, nt ^ uid, 0); + } + + // some statistic + Dbprintf("auth uid: %08x nt: %08x", uid, nt); par = 0; - // Generate (encrypted) nr+parity by loading it into the cipher (Nr) - for (pos = 0; pos < 4; pos++) - { - mf_nr_ar[pos] = crypto1_byte(pcs, ar[pos], 0) ^ ar[pos]; + // Generate (encrypted) nr+parity by loading it into the cipher (Nr) + for (pos = 0; pos < 4; pos++) + { + mf_nr_ar[pos] = crypto1_byte(pcs, ar[pos], 0) ^ ar[pos]; par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(ar[pos])) & 0x01) * 0x80 ); - } + } - // Skip 32 bits in pseudo random generator - nt = prng_successor(nt,32); + // Skip 32 bits in pseudo random generator + nt = prng_successor(nt,32); // ar+parity - for (pos = 4; pos < 8; pos++) - { + for (pos = 4; pos < 8; pos++) + { nt = prng_successor(nt,8); - mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); + mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); par = (par >> 1)| ( ((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) * 0x80 ); - } + } - // Transmit reader nonce and reader answer - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par); + // Transmit reader nonce and reader answer + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par); - // Receive 4 bit answer + // Receive 4 bit answer len = ReaderReceive(receivedAnswer); - if (!len) - { - Dbprintf("Authentication failed. Card timeout."); + if (!len) + { + Dbprintf("Authentication failed. Card timeout."); return 2; - } + } - memcpy(tmp4, receivedAnswer, 4); + memcpy(tmp4, receivedAnswer, 4); ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); if (ntpp != bytes_to_num(tmp4, 4)) { - Dbprintf("Authentication failed. Error card response."); + Dbprintf("Authentication failed. Error card response."); return 3; } @@ -147,12 +157,12 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len; + int len; uint8_t bt[2]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); - // command MIFARE_CLASSIC_READBLOCK + // command MIFARE_CLASSIC_READBLOCK len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer); if (len == 1) { Dbprintf("Cmd Error: %02x", receivedAnswer[0]); @@ -164,7 +174,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo } memcpy(bt, receivedAnswer + 16, 2); - AppendCrc14443a(receivedAnswer, 16); + AppendCrc14443a(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { Dbprintf("Cmd CRC response error."); return 3; @@ -177,15 +187,15 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len, i; + int len, i; uint32_t pos; - uint32_t par = 0; - byte_t res; + uint32_t par = 0; + byte_t res; uint8_t d_block[18], d_block_enc[18]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); - // command MIFARE_CLASSIC_WRITEBLOCK + // command MIFARE_CLASSIC_WRITEBLOCK len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK @@ -198,15 +208,15 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl // crypto par = 0; - for (pos = 0; pos < 18; pos++) - { - d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; + for (pos = 0; pos < 18; pos++) + { + d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) * 0x20000 ); - } + } - ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par); + ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par); - // Receive the response + // Receive the response len = ReaderReceive(receivedAnswer); res = 0; @@ -224,13 +234,13 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { // variables - int len; + int len; // Mifare HALT - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); len = mifare_sendcmd_short(pcs, 1, 0x50, 0x00, receivedAnswer); - if (len != 0) { + if (len != 0) { Dbprintf("halt error. response len: %x", len); return 1; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index ed2779fc..a75d0d32 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -9,6 +9,12 @@ // code for work with mifare cards. //----------------------------------------------------------------------------- +#define CRYPT_NONE 0 +#define CRYPT_ALL 1 +#define CRYPT_REQUEST 2 +#define AUTH_FIRST 0 +#define AUTH_NESTED 2 + int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 922d1b7f..25c46d1a 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -387,6 +387,109 @@ int CmdHF14AMfRdSc(const char *Cmd) return 0; } +int CmdHF14AMfNested(const char *Cmd) +{ + int i, temp; + uint8_t sectorNo = 0; + uint8_t keyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + + const char *cmdp = Cmd; + + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf 14a nested "); + PrintAndLog(" sample: hf 14a nested 0 A FFFFFFFFFFFF "); + return 0; + } + + // skip spaces + while (*cmdp==' ' || *cmdp=='\t') cmdp++; + sectorNo = strtol(cmdp, NULL, 0) & 0xff; + + // next value + while (*cmdp!=' ' && *cmdp!='\t') cmdp++; + while (*cmdp==' ' || *cmdp=='\t') cmdp++; + if (*cmdp != 'A' && *cmdp != 'a') { + keyType = 1; + } + + // next value + while (*cmdp!=' ' && *cmdp!='\t') cmdp++; + while (*cmdp==' ' || *cmdp=='\t') cmdp++; + + if (strlen(cmdp) != 12) { + PrintAndLog("Length of key must be 12 hex symbols"); + return 0; + } + + for(i = 0; i < 6; i++) { + sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); + key[i] = temp & 0xff; + cmdp++; + cmdp++; + } + PrintAndLog(" sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); + + UsbCommand c = {CMD_MIFARE_NESTED, {sectorNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); + PrintAndLog(" "); + + if (resp != NULL) { + uint8_t isOK = resp->arg[0] & 0xff; + uint8_t * data = resp->d.asBytes; + + PrintAndLog("isOk:%02x", isOK); + for (i = 0; i < 2; i++) { + PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); + } + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHF14AMf1kSim(const char *Cmd) +{ + int i, temp; + uint8_t uid[4] = {0, 0, 0, 0}; + + const char *cmdp = Cmd; + + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf 14a mfsim "); + PrintAndLog(" sample: hf 14a mfsim 0a0a0a0a "); + return 0; + } + + // skip spaces + while (*cmdp==' ' || *cmdp=='\t') cmdp++; + + if (strlen(cmdp) != 8) { + PrintAndLog("Length of UID must be 8 hex symbols"); + return 0; + } + + for(i = 0; i < 4; i++) { + sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); + uid[i] = temp & 0xff; + cmdp++; + cmdp++; + } + PrintAndLog(" uid:%s ", sprint_hex(uid, 4)); + + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}}; + memcpy(c.d.asBytes, uid, 6); + SendCommand(&c); + + return 0; +} + + int CmdHF14AReader(const char *Cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; @@ -439,15 +542,17 @@ int CmdHF14ASnoop(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "List ISO 14443a history"}, - {"mifare", CmdHF14AMifare, 0, "Read out sector 0 parity error messages"}, - {"mfrdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"mfrdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, - {"mfwrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, - {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, - {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, - {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, + {"help", CmdHelp, 1, "This help"}, + {"list", CmdHF14AList, 0, "List ISO 14443a history"}, + {"mifare", CmdHF14AMifare, 0, "Read out sector 0 parity error messages"}, + {"mfrdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, + {"mfrdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, + {"mfwrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, + {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"mfsim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card - NOT WORKING!!!"}, + {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, + {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, + {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, {NULL, NULL, 0, NULL} };