Merge pull request #32 from RfidResearchGroup/master

Update from master
This commit is contained in:
mwalker33 2020-04-10 13:38:47 +10:00 committed by GitHub
commit 40d2a3c072
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1079 additions and 666 deletions

View file

@ -3,8 +3,13 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Updated 'legic.lua' and 'legic_clone.lua' script - works with current command set (@Pizza_4u)
- Rewrote `hf mfdes` functions and added apdu debugging (@bkerler)
- Add Mifare Desfire GetDFNames and improve HF MFDES Enum output (@bkerler)
- Fix Mifare Desfire select appid handling (@bkerler)
- Improved `hf 14a info` - card detection handling (@bkerler)
- Updated helptext layout in all luascripts (@iceman1001) - Updated helptext layout in all luascripts (@iceman1001)
- Change `hf mfdes info` - output and logging (@brkeler) - Change `hf mfdes info` - output and logging (@bkerler)
- Updated texts in legic commands (@ikarus23) - Updated texts in legic commands (@ikarus23)
- Fix timing bug inside 40x5 (@mwalker33) - Fix timing bug inside 40x5 (@mwalker33)
- Refactored all Hitag2 attacks (@doegox) - Refactored all Hitag2 attacks (@doegox)

View file

@ -150,6 +150,7 @@ enum DESFIRE_CMD {
GET_FREE_MEMORY = 0x6e, GET_FREE_MEMORY = 0x6e,
GET_FILE_IDS = 0x6f, GET_FILE_IDS = 0x6f,
GET_FILE_SETTINGS = 0xf5, GET_FILE_SETTINGS = 0xf5,
GET_DF_NAMES = 0x6d,
CHANGE_FILE_SETTINGS = 0x5f, CHANGE_FILE_SETTINGS = 0x5f,
CREATE_STD_DATA_FILE = 0xcd, CREATE_STD_DATA_FILE = 0xcd,
CREATE_BACKUP_DATA_FILE = 0xcb, CREATE_BACKUP_DATA_FILE = 0xcb,

View file

@ -263,7 +263,7 @@ static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) {
EPA_Finish(); EPA_Finish();
// send the USB packet // send the USB packet
reply_old(CMD_ACK, step, func_return, 0, 0, 0); reply_mix(CMD_ACK, step, func_return, 0, 0, 0);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -280,12 +280,8 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
* d: * d:
* Encrypted nonce * Encrypted nonce
*/ */
// return value of a function
int func_return = 0;
// set up communication // set up communication
func_return = EPA_Setup(); int func_return = EPA_Setup();
if (func_return != 0) { if (func_return != 0) {
EPA_PACE_Collect_Nonce_Abort(1, func_return); EPA_PACE_Collect_Nonce_Abort(1, func_return);
return; return;
@ -335,7 +331,7 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
EPA_Finish(); EPA_Finish();
// save received information // save received information
reply_old(CMD_ACK, 0, func_return, 0, nonce, func_return); reply_mix(CMD_ACK, 0, func_return, 0, nonce, func_return);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -447,7 +443,7 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
if (c->oldarg[0] != 0) { if (c->oldarg[0] != 0) {
// make sure it's not too big // make sure it's not too big
if (c->oldarg[2] > apdus_replay[c->oldarg[0] - 1].len) { if (c->oldarg[2] > apdus_replay[c->oldarg[0] - 1].len) {
reply_old(CMD_ACK, 1, 0, 0, NULL, 0); reply_mix(CMD_ACK, 1, 0, 0, NULL, 0);
} }
memcpy(apdus_replay[c->oldarg[0] - 1].data + c->oldarg[1], memcpy(apdus_replay[c->oldarg[0] - 1].data + c->oldarg[1],
c->data.asBytes, c->data.asBytes,
@ -458,7 +454,7 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
} else { } else {
apdu_lengths_replay[c->oldarg[0] - 1] += c->oldarg[2]; apdu_lengths_replay[c->oldarg[0] - 1] += c->oldarg[2];
} }
reply_old(CMD_ACK, 0, 0, 0, NULL, 0); reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
return; return;
} }
@ -469,7 +465,7 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
func_return = EPA_Setup(); func_return = EPA_Setup();
if (func_return != 0) { if (func_return != 0) {
EPA_Finish(); EPA_Finish();
reply_old(CMD_ACK, 2, func_return, 0, NULL, 0); reply_mix(CMD_ACK, 2, func_return, 0, NULL, 0);
return; return;
} }
@ -492,12 +488,12 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
|| response_apdu[func_return - 4] != 0x90 || response_apdu[func_return - 4] != 0x90
|| response_apdu[func_return - 3] != 0x00)) { || response_apdu[func_return - 3] != 0x00)) {
EPA_Finish(); EPA_Finish();
reply_old(CMD_ACK, 3 + i, func_return, 0, timings, 20); reply_mix(CMD_ACK, 3 + i, func_return, 0, timings, 20);
return; return;
} }
} }
EPA_Finish(); EPA_Finish();
reply_old(CMD_ACK, 0, 0, 0, timings, 20); reply_mix(CMD_ACK, 0, 0, 0, timings, 20);
return; return;
} }
@ -506,14 +502,13 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
// Returns 0 on success or a non-zero error code on failure // Returns 0 on success or a non-zero error code on failure
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int EPA_Setup() { int EPA_Setup() {
uint8_t uid[10];
iso14a_card_select_t card_a_info;
// first, look for type A cards // first, look for type A cards
// power up the field // power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card iso14a_card_select_t card_a_info;
int return_code = iso14443a_select_card(uid, &card_a_info, NULL, true, 0, false); int return_code = iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false);
if (return_code == 1) { if (return_code == 1) {
uint8_t pps_response[3]; uint8_t pps_response[3];
uint8_t pps_response_par[1]; uint8_t pps_response_par[1];
@ -528,12 +523,14 @@ int EPA_Setup() {
return 0; return 0;
} }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// if we're here, there is no type A card, so we look for type B // if we're here, there is no type A card, so we look for type B
// power up the field // power up the field
iso14443b_setup(); iso14443b_setup();
iso14b_card_select_t card_b_info; iso14b_card_select_t card_b_info;
// select the card
return_code = iso14443b_select_card(&card_b_info); return_code = iso14443b_select_card(&card_b_info);
if (return_code == 0) { if (return_code == 0) {
Dbprintf("ISO 14443 Type B"); Dbprintf("ISO 14443 Type B");
iso_type = 'b'; iso_type = 'b';

View file

@ -621,7 +621,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
set_tracelen(BigBuf_max_traceLen()); set_tracelen(BigBuf_max_traceLen());
Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen()); Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen());
reply_old(CMD_ACK, 1, numbts, 0, 0, 0); reply_mix(CMD_ACK, 1, numbts, 0, 0, 0);
LED_D_OFF(); LED_D_OFF();
} }
@ -812,5 +812,5 @@ void felica_dump_lite_s() {
//setting tracelen - important! it was set by buffer overflow before //setting tracelen - important! it was set by buffer overflow before
set_tracelen(cnt); set_tracelen(cnt);
reply_old(CMD_ACK, isOK, cnt, 0, 0, 0); reply_mix(CMD_ACK, isOK, cnt, 0, 0, 0);
} }

View file

@ -1407,7 +1407,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
set_tracing(false); set_tracing(false);
lf_finalize(); lf_finalize();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }
/* /*
@ -1624,7 +1624,7 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
lf_finalize(); lf_finalize();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }
/* /*
@ -1860,5 +1860,5 @@ void check_challenges(bool file_given, uint8_t *data) {
set_tracing(false); set_tracing(false);
lf_finalize(); lf_finalize();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }

View file

@ -438,7 +438,7 @@ void LegicRfInfo(void) {
} }
// OK // OK
reply_old(CMD_ACK, 1, 0, 0, (uint8_t *)&card, sizeof(legic_card_select_t)); reply_mix(CMD_ACK, 1, 0, 0, (uint8_t *)&card, sizeof(legic_card_select_t));
OUT: OUT:
switch_off(); switch_off();
@ -513,7 +513,7 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
} }
// OK // OK
reply_old(CMD_ACK, 1, len, 0, legic_mem, len); reply_mix(CMD_ACK, 1, len, 0, 0, 0);
OUT: OUT:
switch_off(); switch_off();
@ -552,7 +552,7 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
} }
// OK // OK
reply_old(CMD_ACK, 1, len, 0, legic_mem, len); reply_mix(CMD_ACK, 1, len, 0, 0, 0);
OUT: OUT:
switch_off(); switch_off();

View file

@ -2040,7 +2040,7 @@ void T55xx_ChkPwds(uint8_t flags) {
if (isok != sizeof(counter)) if (isok != sizeof(counter))
goto OUT; goto OUT;
pwdCount = counter[1] << 8 | counter[0]; pwdCount = (uint16_t)(counter[1] << 8 | counter[0]);
if (pwdCount == 0 || pwdCount == 0xFFFF) if (pwdCount == 0 || pwdCount == 0xFFFF)
goto OUT; goto OUT;

View file

@ -204,7 +204,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
uint8_t decRndB[16] = {0x00}; uint8_t decRndB[16] = {0x00};
uint8_t both[32] = {0x00}; uint8_t both[32] = {0x00};
InitDesfireCard(); //InitDesfireCard();
LED_A_ON(); LED_A_ON();
LED_B_OFF(); LED_B_OFF();
@ -455,8 +455,12 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
mbedtls_aes_init(&ctx); mbedtls_aes_init(&ctx);
cmd[0] = AUTHENTICATE_AES; cmd[0] = AUTHENTICATE_AES;
cmd[1] = 0x00; //keynumber cmd[1] = 0x0;
len = DesfireAPDU(cmd, 2, resp); cmd[2] = 0x0;
cmd[3] = 0x1;
cmd[4] = arg2; //keynumber
cmd[5] = 0x0;
len = DesfireAPDU(cmd, 6, resp);
if (!len) { if (!len) {
if (DBGLEVEL >= DBG_ERROR) { if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout."); DbpString("Authentication failed. Card timeout.");
@ -465,7 +469,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
return; return;
} }
memcpy(encRndB, resp + 3, 16); memcpy(encRndB, resp + 1, 16);
// dekryptera tagnonce. // dekryptera tagnonce.
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
@ -491,9 +495,13 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, both, encBoth); mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, both, encBoth);
cmd[0] = ADDITIONAL_FRAME; cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd + 1, encBoth, 32); cmd[1] = 0x00;
cmd[2] = 0x00;
cmd[3] = 0x20;
memcpy(cmd + 4, encBoth, 32);
cmd[36]=0x0;
len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33 len = DesfireAPDU(cmd, 37, resp); // 4 + 32 + 1 == 37
if (!len) { if (!len) {
if (DBGLEVEL >= DBG_ERROR) { if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout."); DbpString("Authentication failed. Card timeout.");
@ -502,7 +510,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
return; return;
} }
if (resp[2] == 0x00) { if ((resp[1+16] == 0x91)&&(resp[1+16+1] == 0x00)) {
// Create AES Session key // Create AES Session key
struct desfire_key sessionKey = {0}; struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey; desfirekey_t skey = &sessionKey;
@ -601,6 +609,6 @@ void OnSuccess() {
} }
void OnError(uint8_t reason) { void OnError(uint8_t reason) {
reply_old(CMD_ACK, 0, reason, 0, 0, 0); reply_mix(CMD_ACK, 0, reason, 0, 0, 0);
OnSuccess(); OnSuccess();
} }

View file

@ -193,7 +193,7 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); // PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n");
return 0; return PM3_SUCCESS;
} }
static int usage_hf_14a_sniff(void) { static int usage_hf_14a_sniff(void) {
PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer.");
@ -203,7 +203,7 @@ static int usage_hf_14a_sniff(void) {
PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r"));
return 0; return PM3_SUCCESS;
} }
static int usage_hf_14a_raw(void) { static int usage_hf_14a_raw(void) {
PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-p] [-a] [-T] [-t] <milliseconds> [-b] <number of bits> <0A 0B 0C ... hex>"); PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-p] [-a] [-T] [-t] <milliseconds> [-b] <number of bits> <0A 0B 0C ... hex>");
@ -217,7 +217,7 @@ static int usage_hf_14a_raw(void) {
PrintAndLogEx(NORMAL, " -t timeout in ms"); PrintAndLogEx(NORMAL, " -t timeout in ms");
PrintAndLogEx(NORMAL, " -T use Topaz protocol to send command"); PrintAndLogEx(NORMAL, " -T use Topaz protocol to send command");
PrintAndLogEx(NORMAL, " -3 ISO14443-3 select only (skip RATS)"); PrintAndLogEx(NORMAL, " -3 ISO14443-3 select only (skip RATS)");
return 0; return PM3_SUCCESS;
} }
static int usage_hf_14a_reader(void) { static int usage_hf_14a_reader(void) {
PrintAndLogEx(NORMAL, "Usage: hf 14a reader [k|s|x] [3]"); PrintAndLogEx(NORMAL, "Usage: hf 14a reader [k|s|x] [3]");
@ -225,7 +225,7 @@ static int usage_hf_14a_reader(void) {
PrintAndLogEx(NORMAL, " s silent (no messages)"); PrintAndLogEx(NORMAL, " s silent (no messages)");
PrintAndLogEx(NORMAL, " x just drop the signal field"); PrintAndLogEx(NORMAL, " x just drop the signal field");
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
return 0; return PM3_SUCCESS;
} }
static int CmdHF14AList(const char *Cmd) { static int CmdHF14AList(const char *Cmd) {
@ -580,7 +580,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS // get ATS
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
return 1; return 1;
@ -674,7 +674,7 @@ static int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) {
if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS // get ATS
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, sizeof(rats), 0, rats, sizeof(rats)); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, sizeof(rats), 0, rats, sizeof(rats));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(ERR, "Proxmark3 connection timeout."); PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
return 1; return 1;
@ -1237,7 +1237,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return PM3_SUCCESS;
} }
int CmdHF14A(const char *Cmd) { int CmdHF14A(const char *Cmd) {
@ -1246,89 +1246,92 @@ int CmdHF14A(const char *Cmd) {
} }
static void printTag(char *tag) { static void printTag(char *tag) {
PrintAndLogEx(SUCCESS, _YELLOW_(" %s"), tag); PrintAndLogEx(SUCCESS, "POSSIBLE TYPE:" _YELLOW_(" %s"), tag);
} }
typedef enum { typedef enum {
mtNone = 0, MTNONE = 0,
mtClassic = 1, MTCLASSIC = 1,
mtMini = 2, MTMINI = 2,
mtDESFire = 4, MTDESFIRE = 4,
mtPlus = 8, MTPLUS = 8,
mtUltralight = 16, MTULTRALIGHT = 16,
mtOther = 32 MTOTHER = 32
} nxp_mifare_type; } nxp_mifare_type_t;
// According to NXP AN10833 Rev 3.6 MIFARE Type Identification, Table 6 // According to NXP AN10833 Rev 3.6 MIFARE Type Identification, Table 6
int detect_nxp_card(uint8_t sak, uint16_t atqa) { int detect_nxp_card(uint8_t sak, uint16_t atqa) {
int type = mtNone; int type = MTNONE;
if (sak == 0x00) { if (sak == 0x00) {
printTag("MIFARE Ultralight C / Ultralight CL2"); printTag("NTAG 20x / 21x / 21x TT / I2C plus");
type = mtUltralight; printTag("MIFARE Ultralight / C / EV1 / Nano");
type = MTULTRALIGHT;
} }
if (sak == 0x01) { if (sak == 0x01) {
printTag("TNP3xxx (Activision Game Appliance)"); printTag("TNP3xxx (Activision Game Appliance)");
type = mtOther; type = MTCLASSIC;
} }
if ((sak & 0x04) == 0x04) { if ((sak & 0x04) == 0x04) {
printTag("Any MIFARE CL1"); printTag("Any MIFARE CL1 / NTAG424DNA");
type |= mtDESFire; type |= MTDESFIRE;
} }
if ((sak & 0x08) == 0x08) { if ((sak & 0x08) == 0x08) {
printTag("MIFARE Classic 1K / Classic 1K CL2"); printTag("MIFARE Classic 1K / Classic 1K CL2");
printTag("MIFARE Plus 2K / Plus EV1 2K"); printTag("MIFARE Plus 2K / Plus EV1 2K");
printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 2K"); printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 2K");
type |= mtClassic; type |= MTCLASSIC;
type |= mtPlus; type |= MTPLUS;
} }
if ((sak & 0x09) == 0x09) { if ((sak & 0x09) == 0x09) {
printTag("MIFARE Mini 0.3K / Mini CL2 0.3K"); printTag("MIFARE Mini 0.3K / Mini CL2 0.3K");
type |= mtMini; type |= MTMINI;
} }
if ((sak & 0x10) == 0x10) { if ((sak & 0x10) == 0x10) {
printTag("MIFARE Plus 2K / Plus CL2 2K"); printTag("MIFARE Plus 2K / Plus CL2 2K");
type |= mtPlus; type |= MTPLUS;
} }
if ((sak & 0x11) == 0x11) { if ((sak & 0x11) == 0x11) {
printTag("MIFARE Plus 4K / Plus CL2 4K"); printTag("MIFARE Plus 4K / Plus CL2 4K");
type |= mtPlus; type |= MTPLUS;
} }
if ((sak & 0x18) == 0x18) { if ((sak & 0x18) == 0x18) {
if (atqa == 0x0042) { if (atqa == 0x0042) {
printTag("MIFARE Plus 4K / Plus EV1 4K"); printTag("MIFARE Plus 4K / Plus EV1 4K");
printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K"); printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K");
type |= mtPlus; type |= MTPLUS;
} else { } else {
printTag("MIFARE Classic 4K / Classic 4K CL2"); printTag("MIFARE Classic 4K / Classic 4K CL2");
type |= mtClassic; type |= MTCLASSIC;
} }
} }
if ((sak & 0x20) == 0x20) { if ((sak & 0x20) == 0x20) {
if (atqa == 0x0344) { if (atqa == 0x0344) {
printTag("MIFARE DESFire EV1 2K/4K/8K / DESFire EV1 CL2 2K/4K/8K"); printTag("MIFARE DESFire EV1 2K/4K/8K / DESFire EV1 CL2 2K/4K/8K");
type |= mtDESFire; printTag("MIFARE NTAG424DNA");
type |= MTDESFIRE;
} else if (atqa == 0x0304) {
printTag("MIFARE NTAG424DNA (Random ID feature)");
type |= MTDESFIRE;
} else { } else {
printTag("MIFARE Plus 2K / Plus EV1 2K"); printTag("MIFARE Plus 2K/4K / Plus EV1 2K/4K");
printTag("MIFARE Plus 4K / Plus EV1 4K"); printTag("MIFARE Plus CL2 2K/4K / Plus CL2 EV1 2K/4K");
printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 4K"); type |= MTPLUS;
printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K");
type |= mtPlus;
} }
} }
if ((sak & 0x24) == 0x24) { if ((sak & 0x24) == 0x24) {
if (atqa == 0x0344) { if (atqa == 0x0344) {
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1"); printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
type |= mtDESFire; type |= MTDESFIRE;
} }
} }
if ((sak & 0x28) == 0x28) { if ((sak & 0x28) == 0x28) {
if (atqa == 0x0344) { if (atqa == 0x0344) {
printTag("MIFARE DESFire CL1 / DESFire EV1 CL1"); printTag("MIFARE DESFire CL1 / DESFire EV1 CL1");
type |= mtDESFire; type |= MTDESFIRE;
} }
} }
return type; return type;
@ -1342,16 +1345,6 @@ typedef struct {
const uidname uidmap[] = { const uidname uidmap[] = {
// UID0, UID1, TEXT // UID0, UID1, TEXT
{0x02, 0x00, "SR176"},
{0x02, 0x03, "SRIX4K"},
{0x02, 0x0C, "SRT512"},
{0x02, 0x0F, "SRI2K"},
{0x02, 0x1B, "25TB512-AC"},
{0x02, 0x3D, "SRIX4K"},
{0x02, 0x3F, "25TB02K"},
{0x02, 0x4D, "SRIX512"},
{0x02, 0x6D, "SRI512"},
{0x02, 0x7D, "SRI4K"},
{0x02, 0x84, "M24SR64-Y"}, {0x02, 0x84, "M24SR64-Y"},
{0x02, 0xA3, "25TA02KB-P"}, {0x02, 0xA3, "25TA02KB-P"},
{0x02, 0xC4, "25TA64K"}, {0x02, 0xC4, "25TA64K"},
@ -1422,42 +1415,33 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
bool isMifareDESFire = false; bool isMifareDESFire = false;
bool isMifarePlus = false; bool isMifarePlus = false;
bool isMifareUltralight = false; bool isMifareUltralight = false;
int nxptype = mtNone; int nxptype = MTNONE;
// Double & triple sized UID, can be mapped to a manufacturer. // Double & triple sized UID, can be mapped to a manufacturer.
if (card.uidlen <= 4) { if (card.uidlen <= 4) {
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0])); nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
if ((nxptype & mtClassic) == mtClassic) isMifareClassic = true;
else isMifareClassic = false; isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
if ((nxptype & mtDESFire) == mtDESFire) { isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifareDESFire = true; isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
} else { isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT);
isMifareDESFire = false;
} if ((nxptype & MTOTHER) == MTOTHER)
if ((nxptype & mtPlus) == mtPlus) isMifarePlus = true; isMifareClassic = true;
else isMifarePlus = false;
if ((nxptype & mtUltralight) == mtUltralight) isMifareUltralight = true;
else isMifareUltralight = false;
if ((nxptype & mtOther) == mtOther) isMifareClassic = true;
} }
if (card.uidlen > 4) { if (card.uidlen > 4) {
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
PrintAndLogEx(SUCCESS, "Possible Type:");
switch (card.uid[0]) { switch (card.uid[0]) {
case 0x04: // NXP case 0x04: // NXP
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0])); nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
if ((nxptype & mtClassic) == mtClassic) isMifareClassic = true;
else isMifareClassic = false; isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC);
if ((nxptype & mtDESFire) == mtDESFire) { isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifareDESFire = true; isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
} else { isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT);
isMifareDESFire = false;
} if ((nxptype & MTOTHER) == MTOTHER)
if ((nxptype & mtPlus) == mtPlus) isMifarePlus = true; isMifareClassic = true;
else isMifarePlus = false;
if ((nxptype & mtUltralight) == mtUltralight) isMifareUltralight = true;
else isMifareUltralight = false;
if ((nxptype & mtOther) == mtOther) isMifareClassic = true;
break; break;
case 0x05: // Infineon case 0x05: // Infineon
if ((card.uid[1] & 0xF0) == 0x10) { if ((card.uid[1] & 0xF0) == 0x10) {
@ -1478,7 +1462,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
default: default:
getTagLabel(card.uid[0], card.uid[1]); getTagLabel(card.uid[0], card.uid[1]);
switch (card.sak) { switch (card.sak) {
case 0x00: case 0x00: {
isMifareClassic = false; isMifareClassic = false;
// ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc)
@ -1507,24 +1491,31 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
return select_status; return select_status;
} }
break; break;
case 0x0A: }
case 0x0A: {
printTag("FM11RF005SH (Shanghai Metro)"); printTag("FM11RF005SH (Shanghai Metro)");
break; break;
case 0x20: }
case 0x20: {
printTag("JCOP 31/41"); printTag("JCOP 31/41");
break; break;
case 0x28: }
case 0x28: {
printTag("JCOP31 or JCOP41 v2.3.1"); printTag("JCOP31 or JCOP41 v2.3.1");
break; break;
case 0x38: }
case 0x38: {
printTag("Nokia 6212 or 6131"); printTag("Nokia 6212 or 6131");
break; break;
case 0x98: }
case 0x98: {
printTag("Gemplus MPCOS"); printTag("Gemplus MPCOS");
break; break;
default: }
default: {
break; break;
} }
}
break; break;
} }
} }
@ -1765,7 +1756,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`")); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
} }
if (((card.sak & 0x08) == 0x08) || ((card.sak & 0x18) == 0x18)) { if (isMifareClassic || isMifareUltralight) {
detect_classic_magic(); detect_classic_magic();
if (isMifareClassic) { if (isMifareClassic) {
@ -1775,7 +1766,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
else if (res == 0) else if (res == 0)
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard")); PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
else else
PrintAndLogEx(FAILED, "prng detection: " _RED_("fail")); PrintAndLogEx(FAILED, "Prng detection: " _RED_("fail"));
if (do_nack_test) if (do_nack_test)
detect_classic_nackbug(false); detect_classic_nackbug(false);
@ -1789,5 +1780,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
} }
DropField();
return select_status; return select_status;
} }

View file

@ -658,6 +658,16 @@ static int CmdLegicWrbl(const char *Cmd) {
} }
} }
} }
// OUT-OF-BOUNDS checks
// UID 4+1 bytes can't be written to.
if (offset < 5) {
if (data)
free(data);
PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
return PM3_EOUTOFBOUND;
}
//Validations //Validations
if (errors || cmdp == 0) { if (errors || cmdp == 0) {
if (data) if (data)
@ -674,14 +684,7 @@ static int CmdLegicWrbl(const char *Cmd) {
legic_print_type(card.cardsize, 0); legic_print_type(card.cardsize, 0);
// OUT-OF-BOUNDS checks if (len + offset > card.cardsize) {
// UID 4+1 bytes can't be written to.
if (offset < 5) {
PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
return PM3_EOUTOFBOUND;
}
if (len + offset >= card.cardsize) {
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset); PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset);
return PM3_EOUTOFBOUND; return PM3_EOUTOFBOUND;
} }

View file

@ -674,7 +674,8 @@ void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
// it's basically a ISO14443a tag, so try annotation from there // it's basically a ISO14443a tag, so try annotation from there
if (!applyIso14443a(exp, size, cmd, cmdsize)) { if (applyIso14443a(exp, size, cmd, cmdsize) == 0) {
// S-block 11xxx010 // S-block 11xxx010
if ((cmd[0] & 0xC0) && (cmdsize == 3)) { if ((cmd[0] & 0xC0) && (cmdsize == 3)) {
switch ((cmd[0] & 0x30)) { switch ((cmd[0] & 0x30)) {
@ -698,12 +699,17 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
} }
// I-block 000xCN1x // I-block 000xCN1x
else if ((cmd[0] & 0xC0) == 0x00) { else if ((cmd[0] & 0xC0) == 0x00) {
// PCB [CID] [NAD] [INF] CRC CRC // PCB [CID] [NAD] [INF] CRC CRC
int pos = 1; int pos = 1;
if ((cmd[0] & 0x08) == 0x08) // cid byte following if ((cmd[0] & 0x08) == 0x08) // cid byte following
pos = pos + 1; pos++;
if ((cmd[0] & 0x04) == 0x04) // nad byte following if ((cmd[0] & 0x04) == 0x04) // nad byte following
pos = pos + 1; pos++;
for (uint8_t i = 0; i < 2; i++, pos++) {
switch (cmd[pos]) { switch (cmd[pos]) {
case MFDES_CREATE_APPLICATION: case MFDES_CREATE_APPLICATION:
snprintf(exp, size, "CREATE APPLICATION"); snprintf(exp, size, "CREATE APPLICATION");
@ -762,6 +768,9 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case MFDES_GET_FILE_IDS: case MFDES_GET_FILE_IDS:
snprintf(exp, size, "GET FILE IDS"); snprintf(exp, size, "GET FILE IDS");
break; break;
case MFDES_GET_DF_NAMES:
snprintf(exp, size, "GET DF NAMES");
break;
case MFDES_GET_ISOFILE_IDS: case MFDES_GET_ISOFILE_IDS:
snprintf(exp, size, "GET ISOFILE IDS"); snprintf(exp, size, "GET ISOFILE IDS");
break; break;
@ -816,6 +825,7 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
default: default:
break; break;
} }
}
} else { } else {
// anything else // anything else
snprintf(exp, size, "?"); snprintf(exp, size, "?");

View file

@ -16,11 +16,18 @@
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmdhw.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "mbedtls/des.h" #include "mbedtls/des.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
#include "protocols.h" #include "protocols.h"
#include "mifare.h" // desfire raw command options #include "mifare.h" // desfire raw command options
#include "cmdtrace.h"
#include "cliparser/cliparser.h"
#include "emv/apduinfo.h" // APDU manipulation / errorcodes
#include "emv/emvcore.h" // APDU logging
#include "util_posix.h" // msleep
#include "mifare/mifare4.h" // MIFARE Authenticate / MAC
uint8_t key_zero_data[16] = { 0x00 }; uint8_t key_zero_data[16] = { 0x00 };
uint8_t key_ones_data[16] = { 0x01 }; uint8_t key_ones_data[16] = { 0x01 };
@ -32,36 +39,126 @@ typedef enum {
MF3ICD40, MF3ICD40,
EV1, EV1,
EV2, EV2,
EV3,
LIGHT, LIGHT,
} desfire_cardtype_t; } desfire_cardtype_t;
typedef struct {
uint8_t aid[3];
uint8_t fid[2];
uint8_t name[16];
} dfname_t;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/*
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
static int SendDesfireCmd(uint8_t *c, size_t len, int p0, int p1, int p2, PacketResponseNG *response, int timeout) { if (!res && datalen > 1 && data[0] == 0x09) {
PacketResponseNG resp; SLmode = 0;
}
if (response == NULL) */
response = &resp;
clearCommandBuffer(); int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) {
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, p0, p1, p2, c, len);
if (!WaitForResponseTimeout(CMD_ACK, response, timeout)) { *result_len = 0;
PrintAndLogEx(WARNING, "[SendDesfireCmd] Timed-out: " _RED_("%s"), sprint_hex(c, len)); if (sw) *sw = 0;
uint16_t isw = 0;
int res = 0;
if (activate_field) {
DropField(); DropField();
return PM3_ETIMEOUT; msleep(50);
} }
uint8_t isOK = response->data.asBytes[0] & 0xff; // select?
if (!isOK) { uint8_t data[APDU_RES_LEN] = {0};
PrintAndLogEx(WARNING, "[SendDesfireCmd] Unsuccessful: " _RED_("%s"), sprint_hex(c, len));
return PM3_ESOFT; // COMPUTE APDU
int datalen = 0;
//if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) {
if (APDUEncodeS(&apdu, false, 0x100, data, &datalen)) {
PrintAndLogEx(ERR, "APDU encoding error.");
return PM3_EAPDU_ENCODEFAIL;
} }
if (GetAPDULogging() || (g_debugMode > 1))
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
res = ExchangeAPDU14a(data, datalen, activate_field, leavefield_on, result, max_result_len, result_len);
if (res) {
return res;
}
if (GetAPDULogging() || (g_debugMode > 1))
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
if (*result_len < 2) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
*result_len -= 2;
isw = (result[*result_len] << 8) + result[*result_len + 1];
if (sw)
*sw = isw;
if (isw != 0x9000 && isw != MFDES_SUCCESS_FRAME_RESP && isw != MFDES_ADDITIONAL_FRAME_RESP) {
if (GetAPDULogging()) {
if (isw >> 8 == 0x61) {
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", isw & 0xff);
} else {
PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(isw >> 8, isw & 0xff));
return PM3_EAPDU_FAIL;
}
}
}
return PM3_SUCCESS;
}
static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize) {
//SetAPDULogging(true);
*sw = 0;
uint8_t data[255 * 5] = {0x00};
int resplen = 0;
int pos = 0;
int i = 1;
int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) return res;
if (*sw != MFDES_ADDITIONAL_FRAME_RESP && *sw != MFDES_SUCCESS_FRAME_RESP) return PM3_ESOFT;
if (dest != NULL) {
memcpy(dest, data, resplen);
}
pos += resplen;
if (*sw == MFDES_ADDITIONAL_FRAME_RESP) {
apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF
res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
if (res != PM3_SUCCESS) return res;
if (dest != NULL) {
if (splitbysize) {
memcpy(&dest[i * splitbysize], data, resplen);
i += 1;
} else {
memcpy(&dest[pos], data, resplen);
}
}
pos += resplen;
}
if (splitbysize) *recv_len = i;
else {
*recv_len = pos;
}
//SetAPDULogging(false);
return PM3_SUCCESS;
}
static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) { static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) {
if (major == 0x00) if (major == 0x00)
@ -70,59 +167,39 @@ static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) {
return EV1; return EV1;
else if (major == 0x12 && minor == 0x00) else if (major == 0x12 && minor == 0x00)
return EV2; return EV2;
// else if (major == 0x13 && minor == 0x00)
// return EV3;
else if (major == 0x30 && minor == 0x00) else if (major == 0x30 && minor == 0x00)
return LIGHT; return LIGHT;
else else
return UNKNOWN; return UNKNOWN;
} }
//ICEMAN: Turn on field method?
//none //none
static int test_desfire_authenticate() { static int test_desfire_authenticate() {
uint8_t c[] = {AUTHENTICATE, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x0A, KEY 0 uint8_t data[] = {0x00};
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c)); sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0
PacketResponseNG resp; int recv_len = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { uint16_t sw = 0;
DropField(); return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0);
return PM3_ETIMEOUT;
}
if (resp.length == 13)
return PM3_SUCCESS;
return PM3_ESOFT;
} }
// none // none
static int test_desfire_authenticate_iso() { static int test_desfire_authenticate_iso() {
uint8_t c[] = {AUTHENTICATE_ISO, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x1A, KEY 0 uint8_t data[] = {0x00};
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c)); sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0
PacketResponseNG resp; int recv_len = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { uint16_t sw = 0;
DropField(); return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0);
return PM3_ETIMEOUT;
}
if (resp.length >= 13)
return PM3_SUCCESS;
return PM3_ESOFT;
} }
//none //none
static int test_desfire_authenticate_aes() { static int test_desfire_authenticate_aes() {
/* Just left here for future use, from TI TRF7970A sloa213 document uint8_t data[] = {0x00};
const static u08_t CustomKey1[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int recv_len = 0;
const static u08_t CustomKey2[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, uint16_t sw = 0;
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0);
const static u08_t CustomKey3[16] = {0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25,
0x53, 0x79, 0x70, 0x25, 0x53, 0x79, 0x70, 0x25, 0x53};
*/
uint8_t c[] = {AUTHENTICATE_AES, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0xAA, KEY 0
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
DropField();
return PM3_ETIMEOUT;
}
if (resp.length >= 13)
return PM3_SUCCESS;
return PM3_ESOFT;
} }
// --- FREE MEM // --- FREE MEM
@ -133,20 +210,18 @@ static int desfire_print_freemem(uint32_t free_mem) {
// init / disconnect // init / disconnect
static int get_desfire_freemem(uint32_t *free_mem) { static int get_desfire_freemem(uint32_t *free_mem) {
uint8_t c[] = {GET_FREE_MEMORY, 0x00, 0x00, 0x00}; // 0x6E sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), sizeof(c), 0, c, sizeof(c)); int recv_len = 0;
PacketResponseNG resp; uint16_t sw = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t fmem[4] = {0};
return PM3_ETIMEOUT;
}
if (resp.length == 8) { int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0);
*free_mem = le24toh(resp.data.asBytes + 1); if (res == PM3_SUCCESS) {
return PM3_SUCCESS; *free_mem = le24toh(fmem);
return res;
} }
*free_mem = 0; *free_mem = 0;
return PM3_ESOFT; return res;
} }
@ -163,7 +238,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
{"DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {"DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"Mifare Plus", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} {"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
}; };
uint8_t i; uint8_t i;
@ -188,36 +263,41 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_desfire_public_keys[i].desc); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 32); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 32);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 48); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 48);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1"); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 16)); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 16, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 32, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 48, signature_len - 48)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// init / disconnect // init / disconnect
static int get_desfire_signature(uint8_t *signature, size_t *signature_len) { static int get_desfire_signature(uint8_t *signature, size_t *signature_len) {
uint8_t c[] = {MFDES_READSIG, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x3C uint8_t c = 0x00;
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), sizeof(c), 0, c, sizeof(c)); sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, 0x01, &c}; // 0x3C
PacketResponseNG resp; int recv_len = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) uint16_t sw = 0;
return PM3_ETIMEOUT; int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0);
if (res == PM3_SUCCESS) {
if (resp.length == 61) { if (recv_len != 56) {
memcpy(signature, resp.data.asBytes + 1, 56);
*signature_len = 56;
return PM3_SUCCESS;
} else {
*signature_len = 0; *signature_len = 0;
DropField();
return PM3_ESOFT; return PM3_ESOFT;
} else {
*signature_len = recv_len;
} }
DropField();
return PM3_SUCCESS;
}
DropField();
return res;
} }
@ -255,18 +335,21 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
// none // none
static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) { static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) {
PacketResponseNG resp; sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45
uint8_t c[] = {MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00}; // 0x45 int recv_len = 0;
int ret = SendDesfireCmd(c, sizeof(c), NONE, sizeof(c), 0, &resp, 1500); uint16_t sw = 0;
if (ret != PM3_SUCCESS) return ret; uint8_t data[2] = {0};
if (num_keys == NULL) return PM3_ESOFT;
if (resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0xae) { if (key_settings == NULL) return PM3_ESOFT;
int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0);
if (sw == MFDES_EAUTH_RESP) {
PrintAndLogEx(WARNING, _RED_("[get_desfire_keysettings] Authentication error")); PrintAndLogEx(WARNING, _RED_("[get_desfire_keysettings] Authentication error"));
return PM3_ESOFT; return PM3_ESOFT;
} }
// PrintAndLogEx(INFO, "ICE: KEYSETTING resp :: %s", sprint_hex(resp.data.asBytes, resp.length)); if (res != PM3_SUCCESS) return res;
*key_settings = resp.data.asBytes[1];
*num_keys = resp.data.asBytes[2]; *key_settings = data[0];
*num_keys = data[1];
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -278,83 +361,72 @@ static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
// none // none
static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
PacketResponseNG resp; sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
uint8_t c[] = {MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, curr_key, 0x00}; // 0x64 int recv_len = 0;
int ret = SendDesfireCmd(c, sizeof(c), NONE, sizeof(c), 0, &resp, 1500); uint16_t sw = 0;
if (ret != PM3_SUCCESS) return ret; if (num_versions == NULL) return PM3_ESOFT;
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0);
if (resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0x40) { if (sw == MFDES_ENO_SUCH_KEY_RESP) {
PrintAndLogEx(WARNING, _RED_("[get_desfire_keyversion] Key %d doesn't exist"), curr_key);
return PM3_ESOFT; return PM3_ESOFT;
} }
return res;
*num_versions = resp.data.asBytes[1];
return PM3_SUCCESS;
}
// init
static int get_desfire_select_application(uint8_t *aid) {
if (aid == NULL) return PM3_ESOFT;
uint8_t c[] = {SELECT_APPLICATION, 0x00, 0x00, 0x03, aid[0], aid[1], aid[2], 0x00}; // 0x5a
PacketResponseNG resp;
int ret = SendDesfireCmd(c, sizeof(c), INIT, sizeof(c), 0, &resp, 3000);
if (ret != PM3_SUCCESS) {
if (ret == PM3_ESOFT) {
PrintAndLogEx(WARNING, "[get_desfire_select_application] Can't select AID: " _RED_("%s"), sprint_hex(aid, 3));
}
return ret;
}
if (resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0x00) {
return PM3_SUCCESS;
}
return PM3_ESOFT;
} }
// init / disconnect // init / disconnect
static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) { static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) {
sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a
uint8_t c[] = {GET_APPLICATION_IDS, 0x00, 0x00, 0x00}; //0x6a int recv_len = 0;
PacketResponseNG resp; uint16_t sw = 0;
int ret = SendDesfireCmd(c, sizeof(c), INIT | CLEARTRACE | DISCONNECT, sizeof(c), 0, &resp, 1500); if (dest == NULL) return PM3_ESOFT;
if (ret != PM3_SUCCESS) return ret; if (app_ids_len == NULL) return PM3_ESOFT;
int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0);
*app_ids_len = resp.length - 5; if (res != PM3_SUCCESS) return res;
*app_ids_len = (uint8_t)recv_len & 0xFF;
// resp.length - 2crc, 2status, 1pcb... return res;
memcpy(dest, resp.data.asBytes + 1, *app_ids_len);
if (resp.data.asBytes[resp.length - 3] == MFDES_ADDITIONAL_FRAME) {
c[0] = MFDES_ADDITIONAL_FRAME; //0xAF
ret = SendDesfireCmd(c, sizeof(c), NONE, sizeof(c), 0, &resp, 1500);
if (ret != PM3_SUCCESS) return ret;
memcpy(dest + *app_ids_len, resp.data.asBytes + 1, resp.length - 5);
*app_ids_len += (resp.length - 5);
}
return PM3_SUCCESS;
} }
static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
sAPDU apdu = {0x90, MFDES_GET_DF_NAMES, 0x00, 0x00, 0x00, NULL}; //0x6d
int recv_len = 0;
uint16_t sw = 0;
if (dest == NULL) return PM3_ESOFT;
if (dfname_count == NULL) return PM3_ESOFT;
int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t));
if (res != PM3_SUCCESS) return res;
*dfname_count = recv_len;
return res;
}
// init
static int get_desfire_select_application(uint8_t *aid) {
sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a
int recv_len = 0;
uint16_t sw = 0;
if (aid == NULL) return PM3_ESOFT;
return send_desfire_cmd(&apdu, true, NULL, &recv_len, &sw, sizeof(dfname_t));
}
// none // none
static int get_desfire_fileids(uint8_t *dest, uint8_t *file_ids_len) { static int get_desfire_fileids(uint8_t *dest, uint8_t *file_ids_len) {
uint8_t c[] = {MFDES_GET_FILE_IDS, 0x00, 0x00, 0x00}; // 0x6f sAPDU apdu = {0x90, MFDES_GET_FILE_IDS, 0x00, 0x00, 0x00, NULL}; //0x6f
PacketResponseNG resp; int recv_len = 0;
int ret = SendDesfireCmd(c, sizeof(c), NONE, sizeof(c), 0, &resp, 1500); uint16_t sw = 0;
if (ret != PM3_SUCCESS) return ret; if (dest == NULL) return PM3_ESOFT;
if (file_ids_len == NULL) return PM3_ESOFT;
if (resp.data.asBytes[resp.length - 4] == 0x91 && resp.data.asBytes[resp.length - 3] == 0x00) { *file_ids_len = 0;
*file_ids_len = resp.length - 5; int res = send_desfire_cmd(&apdu, false, dest, &recv_len, &sw, 0);
memcpy(dest, resp.data.asBytes + 1, *file_ids_len); if (res != PM3_SUCCESS) return res;
return PM3_SUCCESS; *file_ids_len = recv_len;
return res;
} }
return PM3_ESOFT; static int get_desfire_filesettings(uint8_t file_id, uint8_t *dest, int *destlen) {
sAPDU apdu = {0x90, MFDES_GET_FILE_SETTINGS, 0x00, 0x00, 0x01, &file_id}; // 0xF5
uint16_t sw = 0;
return send_desfire_cmd(&apdu, false, dest, destlen, &sw, 0);
} }
static int CmdHF14ADesInfo(const char *Cmd) { static int CmdHF14ADesInfo(const char *Cmd) {
@ -430,11 +502,13 @@ static int CmdHF14ADesInfo(const char *Cmd) {
if (major == 0 && minor == 6) if (major == 0 && minor == 6)
PrintAndLogEx(INFO, "\t0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility"); PrintAndLogEx(INFO, "\t0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility");
if (major == 1 && minor == 3) if (major == 1 && minor == 3)
PrintAndLogEx(INFO, "\t1.3 - DESFire Ev1, Support extended APDU commands"); PrintAndLogEx(INFO, "\t1.3 - DESFire Ev1 MF3ICD21/41/81, Support extended APDU commands, EAL4+");
if (major == 1 && minor == 4) if (major == 1 && minor == 4)
PrintAndLogEx(INFO, "\t1.4 - DESFire Ev1, N/A information about this version. report to iceman!"); PrintAndLogEx(INFO, "\t1.4 - DESFire Ev1 MF3ICD21/41/81, EAL4+, N/A (report to iceman!)");
if (major == 2 && minor == 0) if (major == 2 && minor == 0)
PrintAndLogEx(INFO, "\t2.0 - DESFire Ev2, Originality check, proximity check"); PrintAndLogEx(INFO, "\t2.0 - DESFire Ev2, Originality check, proximity check, EAL5");
// if (major == 3 && minor == 0)
// PrintAndLogEx(INFO, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL5");
if (major == 0 && minor == 2) if (major == 0 && minor == 2)
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
@ -526,6 +600,8 @@ char *getVersionStr(uint8_t major, uint8_t minor) {
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
else if (major == 0x12 && minor == 0x00) else if (major == 0x12 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
// else if (major == 0x13 && minor == 0x00)
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
else if (major == 0x30 && minor == 0x00) else if (major == 0x30 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
else else
@ -538,9 +614,7 @@ void getKeySettings(uint8_t *aid) {
if (memcmp(aid, "\x00\x00\x00", 3) == 0) { if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
// CARD MASTER KEY // CARD MASTER KEY
PrintAndLogEx(NORMAL, ""); //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
if (get_desfire_select_application(aid) != PM3_SUCCESS) { if (get_desfire_select_application(aid) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't select AID")); PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
DropField(); DropField();
@ -603,9 +677,7 @@ void getKeySettings(uint8_t *aid) {
} else { } else {
// AID - APPLICATION MASTER KEYS // AID - APPLICATION MASTER KEYS
PrintAndLogEx(NORMAL, ""); //PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
if (get_desfire_select_application(aid) != PM3_SUCCESS) { if (get_desfire_select_application(aid) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't select AID")); PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
DropField(); DropField();
@ -651,15 +723,25 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
// uint8_t isOK = 0x00; // uint8_t isOK = 0x00;
uint8_t aid[3]; uint8_t aid[3] = {0};
uint8_t app_ids[78] = {0}; uint8_t app_ids[78] = {0};
uint8_t app_ids_len = 0; uint8_t app_ids_len = 0;
uint8_t file_ids[33] = {0}; uint8_t file_ids[33] = {0};
uint8_t file_ids_len = 0; uint8_t file_ids_len = 0;
dfname_t dfnames[255];
uint8_t dfname_count = 0;
if (get_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) { if (get_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Can't get list of applications on tag"); PrintAndLogEx(ERR, "Can't get list of applications on tag");
DropField();
return PM3_ESOFT;
}
if (get_desfire_dfnames(dfnames, &dfname_count) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_("Can't get DF Names"));
DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -674,17 +756,48 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
aid[1] = app_ids[i + 1]; aid[1] = app_ids[i + 1];
aid[2] = app_ids[i + 2]; aid[2] = app_ids[i + 2];
PrintAndLogEx(SUCCESS, " AID %d : " _GREEN_("%02X %02X %02X"), i, app_ids[i], app_ids[i + 1], app_ids[i + 2]); PrintAndLogEx(NORMAL, "");
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
// CARD MASTER KEY
PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
} else {
PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
}
PrintAndLogEx(SUCCESS, " AID : " _GREEN_("%02X %02X %02X"), aid[0], aid[1], aid[2]);
for (int m = 0; m < dfname_count; m++) {
if (dfnames[m].aid[0] == aid[0] && dfnames[m].aid[1] == aid[1] && dfnames[m].aid[2] == aid[2]) {
PrintAndLogEx(SUCCESS, " - DF " _YELLOW_("%02X %02X") " Name : " _YELLOW_("%s"), dfnames[m].fid[0], dfnames[m].fid[1], dfnames[m].name);
}
}
getKeySettings(aid); getKeySettings(aid);
if (get_desfire_select_application(aid) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
DropField();
return PM3_ESOFT;
}
// Get File IDs // Get File IDs
if (get_desfire_fileids(file_ids, &file_ids_len) == PM3_SUCCESS) { if (get_desfire_fileids(file_ids, &file_ids_len) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") "file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's'); PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") "file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's');
for (int j = 0; j < file_ids_len; ++j) { for (int j = 0; j < file_ids_len; ++j) {
PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[j], file_ids[j]); PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[j], file_ids[j]);
uint8_t filesettings[20] = {0};
int fileset_len = 0;
int res = get_desfire_filesettings(j, filesettings, &fileset_len);
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, " Settings [%u] %s", fileset_len, sprint_hex(filesettings, fileset_len));
} }
} }
}
/* /*
// Get ISO File IDs // Get ISO File IDs
@ -713,70 +826,90 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
DropField(); DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/*
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0;
}
*/
// MIAFRE DESFire Authentication // MIAFRE DESFire Authentication
// //
#define BUFSIZE 256 #define BUFSIZE 256
static int CmdHF14ADesAuth(const char *Cmd) { static int CmdHF14ADesAuth(const char *Cmd) {
clearCommandBuffer();
// NR DESC KEYLENGHT // NR DESC KEYLENGHT
// ------------------------ // ------------------------
// 1 = DES 8 // 1 = DES 8
// 2 = 3DES 16 // 2 = 3DES 16
// 3 = 3K 3DES 24 // 3 = 3K 3DES 24
// 4 = AES 16 // 4 = AES 16
//SetAPDULogging(true);
uint8_t keylength = 8; uint8_t keylength = 8;
unsigned char key[24];
if (strlen(Cmd) < 3) { CLIParserInit("hf mfdes auth",
PrintAndLogEx(NORMAL, "Usage: hf mfdes auth <1|2|3> <1|2|3|4> <keyno> <key> "); "Authenticates Mifare DESFire using Key",
PrintAndLogEx(NORMAL, " Auth modes"); "Usage:\n\t-m Auth type (1=normal, 2=iso, 3=aes)\n\t-t Crypt algo (1=DES, 2=3DES, 3=3K3DES, 4=aes)\n\t-a aid (3 bytes)\n\t-n keyno\n\t-k key (8-24 bytes)\n\n"
PrintAndLogEx(NORMAL, " 1 = normal, 2 = iso, 3 = aes"); "Example:\n\thf mfdes auth -m 3 -t 4 -a 018380 -n 0 -k 404142434445464748494a4b4c4d4e4f\n"
PrintAndLogEx(NORMAL, " Crypto"); );
PrintAndLogEx(NORMAL, " 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES");
PrintAndLogEx(NORMAL, ""); void *argtable[] = {
PrintAndLogEx(NORMAL, "Examples:"); arg_param_begin,
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfdes auth 1 1 0 11223344")); arg_int0("mM", "type", "Auth type (1=normal, 2=iso, 3=aes)", NULL),
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f")); arg_int0("tT", "algo", "Crypt algo (1=DES, 2=3DES, 3=3K3DES, 4=aes)", NULL),
return PM3_SUCCESS; arg_strx0("aA", "aid", "<aid>", "AID used for authentification"),
arg_int0("nN", "keyno", "Key number used for authentification", NULL),
arg_str0("kK", "key", "<Key>", "Key for checking (HEX 16 bytes)"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
uint8_t cmdAuthMode = arg_get_int_def(1, 0);
uint8_t cmdAuthAlgo = arg_get_int_def(2, 0);
int aidlength = 3;
uint8_t aid[3] = {0};
CLIGetHexWithReturn(3, aid, &aidlength);
uint8_t cmdKeyNo = arg_get_int_def(4, 0);
uint8_t key[24] = {0};
int keylen = 0;
CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree();
if ((keylen < 8) || (keylen > 24)) {
PrintAndLogEx(ERR, "Specified key must have 16 bytes length.");
//SetAPDULogging(false);
return PM3_EINVARG;
}
// AID
if (aidlength != 3) {
PrintAndLogEx(WARNING, "aid must include %d HEX symbols", 3);
//SetAPDULogging(false);
return PM3_EINVARG;
} }
uint8_t cmdAuthMode = param_get8(Cmd, 0);
uint8_t cmdAuthAlgo = param_get8(Cmd, 1);
uint8_t cmdKeyNo = param_get8(Cmd, 2);
switch (cmdAuthMode) { switch (cmdAuthMode) {
case 1: case 1:
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
//SetAPDULogging(false);
return PM3_EINVARG; return PM3_EINVARG;
} }
break; break;
case 2: case 2:
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
//SetAPDULogging(false);
return PM3_EINVARG; return PM3_EINVARG;
} }
break; break;
case 3: case 3:
if (cmdAuthAlgo != 4) { if (cmdAuthAlgo != 4) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
//SetAPDULogging(false);
return PM3_EINVARG; return PM3_EINVARG;
} }
break; break;
default: default:
PrintAndLogEx(WARNING, "Wrong Auth mode"); PrintAndLogEx(WARNING, "Wrong Auth mode (%d) -> (1=normal, 2=iso, 3=aes)", cmdAuthMode);
//SetAPDULogging(false);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -800,21 +933,37 @@ static int CmdHF14ADesAuth(const char *Cmd) {
break; break;
} }
// key // KEY
if (param_gethex(Cmd, 3, key, keylength * 2)) { if (keylen != keylength) {
PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength); PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (get_desfire_select_application(aid) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
DropField();
return PM3_ESOFT;
}
uint8_t file_ids[33] = {0};
uint8_t file_ids_len = 0;
int res = get_desfire_fileids(file_ids, &file_ids_len);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Get file ids error.");
DropField();
return res;
}
// algo, keylength, // algo, keylength,
uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES) uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES)
memcpy(data + 1, key, keylength); memcpy(data + 1, key, keylength);
clearCommandBuffer();
SendCommandOLD(CMD_HF_DESFIRE_AUTH1, cmdAuthMode, cmdAuthAlgo, cmdKeyNo, data, keylength + 1); SendCommandOLD(CMD_HF_DESFIRE_AUTH1, cmdAuthMode, cmdAuthAlgo, cmdKeyNo, data, keylength + 1);
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
PrintAndLogEx(WARNING, "Client command execute timeout"); PrintAndLogEx(WARNING, "Client command execute timeout");
DropField();
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
@ -833,9 +982,15 @@ static int CmdHF14ADesAuth(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHF14ADesList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
return CmdTraceList("des");
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"}, {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"},
{"list", CmdHF14ADesList, AlwaysAvailable, "List DESFire (ISO 14443A) history"},
{"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"}, {"enum", CmdHF14ADesEnumApplications, IfPm3Iso14443a, "Tries enumerate all applications"},
{"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"}, {"auth", CmdHF14ADesAuth, IfPm3Iso14443a, "Tries a MIFARE DesFire Authentication"},
// {"rdbl", CmdHF14ADesRb, IfPm3Iso14443a, "Read MIFARE DesFire block"}, // {"rdbl", CmdHF14ADesRb, IfPm3Iso14443a, "Read MIFARE DesFire block"},

View file

@ -19,50 +19,14 @@ char *getProtocolStr(uint8_t id);
char *getVersionStr(uint8_t major, uint8_t minor); char *getVersionStr(uint8_t major, uint8_t minor);
void getKeySettings(uint8_t *aid); void getKeySettings(uint8_t *aid);
#define CREATE_APPLICATION 0xca // Ev1 card limits
#define DELETE_APPLICATION 0xda
#define GET_APPLICATION_IDS 0x6a
#define SELECT_APPLICATION 0x5a
#define FORMAT_PICC 0xfc
#define GET_VERSION 0x60
#define READ_DATA 0xbd
#define WRITE_DATA 0x3d
#define GET_VALUE 0x6c
#define CREDIT 0x0c
#define DEBIT 0xdc
#define LIMITED_CREDIT 0x1c
#define WRITE_RECORD 0x3b
#define READ_RECORDS 0xbb
#define CLEAR_RECORD_FILE 0xeb
#define COMMIT_TRANSACTION 0xc7
#define ABORT_TRANSACTION 0xa7
#define GET_FREE_MEMORY 0x6e
#define GET_FILE_IDS 0x6f
#define GET_ISOFILE_IDS 0x61
#define GET_FILE_SETTINGS 0xf5
#define CHANGE_FILE_SETTINGS 0x5f
#define CREATE_STD_DATA_FILE 0xcd
#define CREATE_BACKUP_DATA_FILE 0xcb
#define CREATE_VALUE_FILE 0xcc
#define CREATE_LINEAR_RECORD_FILE 0xc1
#define CREATE_CYCLIC_RECORD_FILE 0xc0
#define DELETE_FILE 0xdf
#define AUTHENTICATE 0x0a // AUTHENTICATE_NATIVE
#define AUTHENTICATE_ISO 0x1a // AUTHENTICATE_STANDARD
#define AUTHENTICATE_AES 0xaa
#define CHANGE_KEY_SETTINGS 0x54
#define GET_KEY_SETTINGS 0x45
#define CHANGE_KEY 0xc4
#define GET_KEY_VERSION 0x64
#define AUTHENTICATION_FRAME 0xAF
#define MAX_NUM_KEYS 0x0F #define MAX_NUM_KEYS 0x0F
#define MAX_APPLICATION_COUNT 28 #define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 32 #define MAX_FILE_COUNT 32
#define MAX_FRAME_SIZE 60 #define MAX_FRAME_SIZE 60
#define NOT_YET_AUTHENTICATED 255
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) #define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
#define NOT_YET_AUTHENTICATED 0xFF
// status- and error codes | // status- and error codes |
#define OPERATION_OK 0x00 // Successful operation #define OPERATION_OK 0x00 // Successful operation

View file

@ -10,12 +10,9 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhfmfp.h" #include "cmdhfmfp.h"
#include <string.h> #include <string.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
@ -27,6 +24,9 @@
#include "mifare/mifaredefault.h" #include "mifare/mifaredefault.h"
#include "util_posix.h" #include "util_posix.h"
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h"
#include "crypto/libpcrypto.h"
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
@ -34,21 +34,188 @@ uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA0
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/*
The 7 MSBits (= n) code the storage size itself based on 2^n,
the LSBit is set to '0' if the size is exactly 2^n
and set to '1' if the storage size is between 2^n and 2^(n+1).
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
*/
static char *getCardSizeStr(uint8_t fsize) {
static char buf[40] = {0x00};
char *retStr = buf;
uint16_t usize = 1 << ((fsize >> 1) + 1);
uint16_t lsize = 1 << (fsize >> 1);
// is LSB set?
if (fsize & 1)
sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
return buf;
}
static char *getProtocolStr(uint8_t id) {
static char buf[40] = {0x00};
char *retStr = buf;
if (id == 0x05)
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
else
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
return buf;
}
static char *getVersionStr(uint8_t major, uint8_t minor) {
static char buf[40] = {0x00};
char *retStr = buf;
if (major == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
else if (major == 0x01 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
else if (major == 0x12 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
// else if (major == 0x13 && minor == 0x00)
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
else if (major == 0x30 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
else if (major == 0x11 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("Plus EV1") ")", major, minor);
else
sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
return buf;
}
// --- GET SIGNATURE
static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
// ref: MIFARE Plus EV1 Originality Signature Validation
#define PUBLIC_PLUS_ECDA_KEYLEN 57
const ecdsa_publickey_t nxp_plus_public_keys[] = {
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
};
uint8_t i;
int res;
bool is_valid = false;
for (i = 0; i < ARRAYLEN(nxp_plus_public_keys); i++) {
int dl = 0;
uint8_t key[PUBLIC_PLUS_ECDA_KEYLEN];
param_gethex_to_eol(nxp_plus_public_keys[i].value, 0, key, PUBLIC_PLUS_ECDA_KEYLEN, &dl);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, uidlen, signature, signature_len, false);
is_valid = (res == 0);
if (is_valid)
break;
}
if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_plus_public_keys[i].value);
PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 16);
PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 32);
PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 48);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
return PM3_SUCCESS;
}
static int get_plus_signature(uint8_t *signature, int *signature_len) {
mfpSetVerboseMode(false);
uint8_t data[59] = {0};
int resplen = 0, retval = PM3_SUCCESS;
MFPGetSignature(true, false, data, sizeof(data), &resplen);
if (resplen == 59) {
memcpy(signature, data + 1, 56);
*signature_len = 56;
} else {
*signature_len = 0;
retval = PM3_ESOFT;
}
mfpSetVerboseMode(false);
return retval;
}
// GET VERSION
static int plus_print_version(uint8_t *version) {
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7));
PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(version + 21, 5));
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") "/ " _GREEN_("20%02x"), version[7+7+7+5], version[7+7+7+5+1]);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]);
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]);
PrintAndLogEx(INFO, " Version: %s", getVersionStr(version[3], version[4]));
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6]));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), version[1]);
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]);
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), version[3], version[4]);
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(version[5]));
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6]));
return PM3_SUCCESS;
}
static int get_plus_version(uint8_t *version, int *version_len) {
int resplen = 0, retval = PM3_SUCCESS;
mfpSetVerboseMode(false);
MFPGetVersion(true, false, version, *version_len, &resplen);
mfpSetVerboseMode(false);
*version_len = resplen;
if (resplen != 28) {
retval = PM3_ESOFT;
}
return retval;
}
static int CmdHFMFPInfo(const char *Cmd) { static int CmdHFMFPInfo(const char *Cmd) {
if (Cmd && strlen(Cmd) > 0) if (Cmd && strlen(Cmd) > 0)
PrintAndLogEx(WARNING, "command don't have any parameters.\n"); PrintAndLogEx(WARNING, "command don't have any parameters.\n");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-- Mifare Plus Tag Information ------------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
bool supportVersion = false;
bool supportSignature = false;
// version check
uint8_t version[30] = {0};
int version_len = sizeof(version);
if (get_plus_version(version, &version_len) == PM3_SUCCESS) {
plus_print_version(version);
supportVersion = true;
} else {
// info about 14a part // info about 14a part
infoHF14A(false, false, false); infoHF14A(false, false, false);
}
// Mifare Plus info // Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
WaitForResponse(CMD_ACK, &resp); WaitForResponse(CMD_ACK, &resp);
@ -57,55 +224,60 @@ static int CmdHFMFPInfo(const char *Cmd) {
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// Signature originality check
uint8_t signature[56] = {0};
int signature_len = sizeof(signature);
if (get_plus_signature(signature, &signature_len) == PM3_SUCCESS) {
plus_print_signature(card.uid, card.uidlen, signature, signature_len);
supportSignature = true;
}
if (select_status == 1 || select_status == 2) { if (select_status == 1 || select_status == 2) {
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint"));
PrintAndLogEx(INFO, " Fingerprint");
if (supportVersion && supportSignature) {
PrintAndLogEx(INFO, " Tech: " _GREEN_("MIFARE Plus EV1"));
} else {
PrintAndLogEx(INFO, " Tech: " _YELLOW_("MIFARE Plus SE/X"));
}
// MIFARE Type Identification Procedure // MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf // https://www.nxp.com/docs/en/application-note/AN10833.pdf
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8); uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
bool isPlus = false; bool isPlus = false;
if (ATQA == 0x0004) { if (ATQA & 0x0004) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (4b UID)"); PrintAndLogEx(INFO, " SIZE: " _GREEN_("2K") "(%s UID)", (ATQA & 0x0040) ? "7" : "4");
isPlus = true; isPlus = true;
} }
if (ATQA == 0x0002) { if (ATQA & 0x0002) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (4b UID)"); PrintAndLogEx(INFO, " SIZE: " _GREEN_("4K") "(%s UID)", (ATQA & 0x0040) ? "7" : "4");
isPlus = true;
}
if (ATQA == 0x0044) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (7b UID)");
isPlus = true;
}
if (ATQA == 0x0042) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (7b UID)");
isPlus = true; isPlus = true;
} }
uint8_t SLmode = 0xff; uint8_t SLmode = 0xFF;
if (isPlus) { if (isPlus) {
if (card.sak == 0x08) { if (card.sak == 0x08) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K 7b UID")); PrintAndLogEx(INFO, " SAK: " _GREEN_("2K 7b UID"));
if (select_status == 2) SLmode = 1; if (select_status == 2) SLmode = 1;
} }
if (card.sak == 0x18) { if (card.sak == 0x18) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K 7b UID")); PrintAndLogEx(INFO, " SAK: " _GREEN_("4K 7b UID"));
if (select_status == 2) SLmode = 1; if (select_status == 2) SLmode = 1;
} }
if (card.sak == 0x10) { if (card.sak == 0x10) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K")); PrintAndLogEx(INFO, " SAK: " _GREEN_("2K"));
if (select_status == 2) SLmode = 2; if (select_status == 2) SLmode = 2;
} }
if (card.sak == 0x11) { if (card.sak == 0x11) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K")); PrintAndLogEx(INFO, " SAK: " _GREEN_("4K"));
if (select_status == 2) SLmode = 2; if (select_status == 2) SLmode = 2;
} }
} }
if (card.sak == 0x20) { if (card.sak == 0x20) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus SL0/SL3") "or " _GREEN_("Mifare DESFire")); PrintAndLogEx(INFO, " SAK: " _GREEN_("MIFARE Plus SL0/SL3") "or " _GREEN_("MIFARE DESFire"));
if (card.ats_len > 0) { if (card.ats_len > 0) {
@ -118,7 +290,7 @@ static int CmdHFMFPInfo(const char *Cmd) {
int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false); int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false);
if (memcmp(data, "\x67\x00", 2) == 0) { if (memcmp(data, "\x67\x00", 2) == 0) {
PrintAndLogEx(INFO, "\tMost likely a Mifare DESFire tag"); PrintAndLogEx(INFO, "\tMost likely a MIFARE DESFire tag");
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`")); PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`"));
DropField(); DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
@ -130,8 +302,14 @@ static int CmdHFMFPInfo(const char *Cmd) {
} }
} }
if (isPlus) {
// How do we detect SL0 / SL1 / SL2 / SL3 modes?!? // How do we detect SL0 / SL1 / SL2 / SL3 modes?!?
PrintAndLogEx(INFO, "Security Level (SL)"); PrintAndLogEx(INFO, "--- " _CYAN_("Security Level (SL)"));
if (SLmode != 0xFF )
PrintAndLogEx(SUCCESS, " SL mode: " _YELLOW_("SL%d"), SLmode);
else
PrintAndLogEx(WARNING, " SL mode: " _YELLOW_("unknown"));
switch(SLmode) { switch(SLmode) {
case 0: case 0:
PrintAndLogEx(INFO, " SL 0: initial delivery configuration, used for card personalization"); PrintAndLogEx(INFO, " SL 0: initial delivery configuration, used for card personalization");
@ -148,15 +326,11 @@ static int CmdHFMFPInfo(const char *Cmd) {
default: default:
break; break;
} }
}
if (SLmode != 0xFF)
PrintAndLogEx(SUCCESS, "\tMifare Plus SL mode: " _YELLOW_("SL%d"), SLmode);
else
PrintAndLogEx(WARNING, "\tMifare Plus SL mode: " _YELLOW_("unknown"));
} else { } else {
PrintAndLogEx(INFO, "\tMifare Plus info not available."); PrintAndLogEx(INFO, "\tMifare Plus info not available.");
} }
PrintAndLogEx(NORMAL, "");
DropField(); DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -503,7 +503,17 @@ void APDUPrint(APDUStruct apdu) {
void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) { void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) {
PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)", PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)",
apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le); apdu.extended_apdu ? "[e]" : "",
apdu.case_type,
apdu.cla,
apdu.ins,
apdu.p1,
apdu.p2,
apdu.lc,
apdu.lc,
apdu.le,
apdu.le
);
if (maxdatalen > 0) if (maxdatalen > 0)
PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : "");
} }

View file

@ -136,6 +136,10 @@ void SetAPDULogging(bool logging) {
APDULogging = logging; APDULogging = logging;
} }
bool GetAPDULogging(void) {
return APDULogging;
}
enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen) { enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen) {
char buf[100] = {0}; char buf[100] = {0};
if (AIDlen < 1) if (AIDlen < 1)

View file

@ -57,6 +57,7 @@ struct tlvdb *GetPANFromTrack2(const struct tlv *track2);
struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
void SetAPDULogging(bool logging); void SetAPDULogging(bool logging);
bool GetAPDULogging(void);
// exchange // exchange
int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);

View file

@ -91,14 +91,20 @@ CRC1 = crc8 over addr 0x00..0x03+0x07..0x0E (special 'gantner crc8')
CRC2 = MCD + MSB0..2+ addr 0x06 + addr 0x05 + addr 0x07 + Stamp (regular Master-Token-CRC) CRC2 = MCD + MSB0..2+ addr 0x06 + addr 0x05 + addr 0x07 + Stamp (regular Master-Token-CRC)
--]] --]]
--[[
Known issues; needs to be fixed:
* last byte in last segment is handled incorrectly when it is the last bytes on the card itself (MIM256: => byte 256)
--]]
example = "script run legic" example = "script run legic"
author = "Mosci" author = "Mosci, uhei"
version = "1.0.3" version = "1.0.4"
desc = desc =
[[ [[
This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024) This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024)
The virtual tag (and therefore the file to be saved) is always a MIM1024 tag.
it's kinda interactive with following commands in three categories: it's kinda interactive with following commands in three categories:
Data I/O Segment Manipulation Token-Data Data I/O Segment Manipulation Token-Data
@ -108,8 +114,8 @@ it's kinda interactive with following commands in three categories:
ed => edit Segment Data tk => toggle KGH-Flag ed => edit Segment Data tk => toggle KGH-Flag
File I/O rs => remove Segment File I/O rs => remove Segment
----------------- cc => check Segment-CRC ----------------- cc => check Segment-CRC
lf => load File ck => check KGH lf => load bin File ck => check KGH
sf => save File ds => dump Segments sf => save eml/bin File ds => dump Segments
xf => xor to File xf => xor to File
@ -128,8 +134,8 @@ it's kinda interactive with following commands in three categories:
without the need of changing anything - MCD,MSN,MCC will be read from the tag without the need of changing anything - MCD,MSN,MCC will be read from the tag
before and applied to the output. before and applied to the output.
lf: 'load file' - load a (xored) file from the local Filesystem into the 'virtual inTag' lf: 'load file' - load a (xored) binary file (*.bin) from the local Filesystem into the 'virtual inTag'
sf: 'save file' - saves the 'virtual inTag' to the local Filesystem (xored with Tag-MCC) sf: 'save file' - saves the 'virtual inTag' to the local Filesystem as eml and bin (xored with Tag-MCC)
xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values) xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values)
ct: 'copy tag' - copy the 'virtual Tag' to a second 'virtual TAG' - not usefull yet, but inernally needed ct: 'copy tag' - copy the 'virtual Tag' to a second 'virtual TAG' - not usefull yet, but inernally needed
@ -242,6 +248,16 @@ function istable(t)
return type(t) == 'table' return type(t) == 'table'
end end
---
-- To have two char string for a byte
local function padString(str)
if (#str == 1) then
return '0'..str
end
return str
end
--- ---
-- creates a 'deep copy' of a table (a=b only references) -- creates a 'deep copy' of a table (a=b only references)
function deepCopy(object) function deepCopy(object)
@ -387,15 +403,15 @@ end
function bytesToTag(bytes, tag) function bytesToTag(bytes, tag)
if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end
tag.MCD =bytes[1]; tag.MCD =padString(bytes[1]);
tag.MSN0=bytes[2]; tag.MSN0=padString(bytes[2]);
tag.MSN1=bytes[3]; tag.MSN1=padString(bytes[3]);
tag.MSN2=bytes[4]; tag.MSN2=padString(bytes[4]);
tag.MCC =bytes[5]; tag.MCC =padString(bytes[5]);
tag.DCFl=bytes[6]; tag.DCFl=padString(bytes[6]);
tag.DCFh=bytes[7]; tag.DCFh=padString(bytes[7]);
tag.raw =bytes[8]; tag.raw =padString(bytes[8]);
tag.SSC =bytes[9]; tag.SSC =padString(bytes[9]);
tag.Type=getTokenType(tag.DCFl); tag.Type=getTokenType(tag.DCFl);
tag.OLE=bbit("0x"..tag.DCFl,7,1) tag.OLE=bbit("0x"..tag.DCFl,7,1)
tag.WRP=("%d"):format(bbit("0x"..bytes[8],0,4)) tag.WRP=("%d"):format(bbit("0x"..bytes[8],0,4))
@ -500,42 +516,26 @@ function tagToBytes(tag)
return bytes return bytes
end end
---
--- PM3 I/O --- --- PM3 I/O ---
---
-- read from pm3 into virtual-tag
function readFromPM3()
local tag, bytes, infile
infile="legic.temp"
-- core.console("hf legic reader")
-- core.console("hf legic esave "..infile)
core.console("hf legic dump o "..infile)
tag=readFile(infile..".bin")
return tag
end
local function padString(str)
if (#str == 1) then
return '0'..str
end
return str
end
---
-- write virtual Tag to real Tag -- write virtual Tag to real Tag
function writeToTag(tag) function writeToTag(tag)
local bytes local bytes
local filename = 'MylegicClone.hex'
local taglen = 22 local taglen = 22
if(utils.confirm(acred.."\nplace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then local writeDCF = false
if(utils.confirm(acred.."\nPlace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then
return return
end end
if(utils.confirm(acred.."\nShould the decremental field (DCF) be written?: "..acoff) == true) then
writeDCF = true
end
-- get used bytes / tag-len -- get used bytes / tag-len
if (istable(tag.SEG)) then if (istable(tag.SEG)) then
if (istable(tag.Bck)) then if (istable(tag.Bck)) then
for i=0, #tag.SEG do for i=0, #tag.SEG do
taglen = taglen + tag.SEG[i] . len + 5 taglen = taglen + tag.SEG[i] . len
end end
end end
local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
@ -571,37 +571,32 @@ function writeToTag(tag)
bytes[22] = calcMtCrc(bytes) bytes[22] = calcMtCrc(bytes)
end end
if (bytes) then if (bytes) then
print("write temp-file '"..filename.."'") bytes = xorBytes(bytes,tag.MCC)
print(accyan)
writeFile(bytes, filename..".bin")
print(acoff)
end end
end end
-- write data to file -- write data to file
if (taglen > 0) then if (taglen > 0) then
WriteBytes = input(acyellow.."enter number of bytes to write?"..acoff, taglen) WriteBytes = input(acyellow.."enter number of bytes to write?"..acoff, taglen)
-- load file into pm3-buffer
if (type(filename) ~= "string") then
filename = input(acyellow.."filename to load to pm3-buffer?"..acoff, "legic.temp")
end
cmd = 'hf legic eload 2 '..filename
core.console(cmd)
-- write pm3-buffer to Tag -- write pm3-buffer to Tag
for i=0, WriteBytes do for i=1, WriteBytes do
if (i > 6) then if (i > 7) then
cmd = ("hf legic write o %x d %s "):format(i, padString(bytes[i])) cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i]))
print(acgreen..cmd..acoff) print(acgreen..cmd..acoff)
core.console(cmd) core.console(cmd)
core.clearCommandBuffer() core.clearCommandBuffer()
elseif (i == 6) then elseif (i == 7) then
if (writeDCF) then
-- write DCF in reverse order (requires 'mosci-patch') -- write DCF in reverse order (requires 'mosci-patch')
cmd = ('hf legic write o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i]))
print(acgreen..cmd..acoff) print(acgreen..cmd..acoff)
core.console(cmd) core.console(cmd)
core.clearCommandBuffer() core.clearCommandBuffer()
elseif (i == 5) then else
print(acgreen.."skip byte 0x05-0x06 - DCF"..acoff)
end
elseif (i == 6) then
print(acgreen.."skip byte 0x05 - will be written next step"..acoff) print(acgreen.."skip byte 0x05 - will be written next step"..acoff)
else else
print(acgreen.."skip byte 0x00-0x04 - unwritable area"..acoff) print(acgreen.."skip byte 0x00-0x04 - unwritable area"..acoff)
@ -641,12 +636,12 @@ end
local function save_BIN(data, filename) local function save_BIN(data, filename)
local outfile local outfile
local counter = 1 local counter = 1
local ext = filename:match("^.+(%..+)$") or '' local ext = ".bin"
local fn = filename local fn = filename..ext
-- Make sure we don't overwrite a file -- Make sure we don't overwrite a file
while file_check(fn) do while file_check(fn) do
fn = filename:gsub(ext, tostring(counter)..ext) fn = filename..ext:gsub(ext, "-"..tostring(counter)..ext)
counter = counter + 1 counter = counter + 1
end end
@ -664,26 +659,27 @@ end
--- ---
-- write bytes to file -- write bytes to file
function writeFile(bytes, filename) function writeFile(bytes, filename)
if (filename ~= 'MylegicClone.hex') then local emlext = ".eml"
if (file_check(filename)) then if (filename ~= 'MyLegicClone') then
local answer = confirm("\nthe output-file "..filename.." already exists!\nthis will delete the previous content!\ncontinue?") if (file_check(filename..emlext)) then
local answer = confirm("\nthe output-file "..filename..emlext.." already exists!\nthis will delete the previous content!\ncontinue?")
if not answer then return print("user abort") end if not answer then return print("user abort") end
end end
end end
local line local line
local bcnt = 0 local bcnt = 0
local fho, err = io.open(filename, "w") local fho, err = io.open(filename..emlext, "w")
if err then if err then
return oops("OOps ... failed to open output-file ".. filename) return oops("OOps ... failed to open output-file ".. filename..emlext)
end end
bytes = xorBytes(bytes, bytes[5]) bytes = xorBytes(bytes, bytes[5])
for i = 1, #bytes do for i = 1, #bytes do
if (bcnt == 0) then if (bcnt == 0) then
line = bytes[i] line = padString(bytes[i])
elseif (bcnt <= 7) then elseif (bcnt <= 7) then
line = line.." "..bytes[i] line = line.." "..padString(bytes[i])
end end
if (bcnt == 7) then if (bcnt == 7) then
-- write line to new file -- write line to new file
@ -699,7 +695,7 @@ function writeFile(bytes, filename)
-- save binary -- save binary
local fn_bin, fn_bin_num = save_BIN(bytes, filename) local fn_bin, fn_bin_num = save_BIN(bytes, filename)
print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..acoff) print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..emlext..acoff)
if fn_bin and fn_bin_num then if fn_bin and fn_bin_num then
print("\nwrote "..acyellow..fn_bin_num..acoff.." bytes to BINARY file "..acyellow..fn_bin..acoff) print("\nwrote "..acyellow..fn_bin_num..acoff.." bytes to BINARY file "..acyellow..fn_bin..acoff)
@ -708,6 +704,21 @@ function writeFile(bytes, filename)
return true return true
end end
---
-- read from pm3 into virtual-tag
function readFromPM3()
local tag, bytes, infile
--infile="legic.temp"
infile=os.tmpname()
core.console("hf legic dump f "..infile)
tag=readFile(infile..".bin")
os.remove(infile)
os.remove(infile..".bin")
os.remove(infile..".eml")
os.remove(infile..".json")
return tag
end
--- Map related --- --- Map related ---
--- ---
-- make tagMap -- make tagMap
@ -2265,8 +2276,8 @@ function modifyHelp()
ed => edit Segment Data tk => toggle KGH-Flag ed => edit Segment Data tk => toggle KGH-Flag
File I/O rs => remove Segment File I/O rs => remove Segment
----------------- cc => check Segment-CRC ----------------- cc => check Segment-CRC
lf => load File ck => check KGH lf => load bin File ck => check KGH
sf => save File ds => dump Segments sf => save eml/bin File ds => dump Segments
xf => xor to File xf => xor to File
@ -2352,10 +2363,10 @@ function modifyMode()
-- save values of mainTAG to a file (xored with MCC of mainTAG) -- save values of mainTAG to a file (xored with MCC of mainTAG)
["sf"] = function(x) ["sf"] = function(x)
if istable(inTAG) then if istable(inTAG) then
outfile = input("enter filename:", "legic.temp") outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2)
bytes = tagToBytes(inTAG) bytes = tagToBytes(inTAG)
--bytes=xorBytes(bytes, inTAG.MCC) --bytes=xorBytes(bytes, inTAG.MCC)
if bytes then if (bytes) then
writeFile(bytes, outfile) writeFile(bytes, outfile)
end end
end end
@ -2364,7 +2375,7 @@ function modifyMode()
-- save values of mainTAG to a file (xored with 'specific' MCC) -- save values of mainTAG to a file (xored with 'specific' MCC)
["xf"] = function(x) ["xf"] = function(x)
if istable(inTAG) then if istable(inTAG) then
outfile = input("enter filename:", "legic.temp") outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2)
crc = input("enter new crc: ('00' for a plain dump)", inTAG.MCC) crc = input("enter new crc: ('00' for a plain dump)", inTAG.MCC)
print("obfuscate with: "..crc) print("obfuscate with: "..crc)
bytes=tagToBytes(inTAG) bytes=tagToBytes(inTAG)

View file

@ -429,6 +429,46 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data
return 0; return 0;
} }
int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint8_t c[] = {0x3c, 0x00};
return intExchangeRAW14aPlus(c, sizeof(c), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
}
int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint8_t tmp[20] = {0};
uint8_t c[] = {0x60};
int res = intExchangeRAW14aPlus(c, sizeof(c), activateField, true, tmp, maxdataoutlen, dataoutlen);
if (res != 0) {
DropField();
*dataoutlen = 0;
return res;
}
memcpy(dataout, tmp + 1, (*dataoutlen - 3));
*dataoutlen = 0;
// MFDES_ADDITIONAL_FRAME
if (tmp[0] == 0xAF) {
c[0] = 0xAF;
res = intExchangeRAW14aPlus(c, sizeof(c), false, true, tmp, maxdataoutlen, dataoutlen);
if (res == 0) {
memcpy(dataout + 7, tmp + 1, (*dataoutlen - 3));
// MFDES_ADDITIONAL_FRAME
res = intExchangeRAW14aPlus(c, sizeof(c), false, false, tmp, maxdataoutlen, dataoutlen);
if (res == 0) {
if (tmp[0] == 0x90) {
memcpy(dataout + 7 + 7, tmp + 1, (*dataoutlen - 3));
*dataoutlen = 28;
}
}
}
}
DropField();
return res;
}
// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), // Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards),
// plus evtl. 8 sectors with 16 blocks each (4k cards) // plus evtl. 8 sectors with 16 blocks each (4k cards)
uint8_t mfNumBlocksPerSector(uint8_t sectorNo) { uint8_t mfNumBlocksPerSector(uint8_t sectorNo) {

View file

@ -59,6 +59,9 @@ int MFPReadBlock(mf4Session_t *session, bool plain, uint8_t blockNum, uint8_t bl
int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose); int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose);
int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
int MFPGetVersion(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
const char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data); const char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data);
uint8_t mfNumBlocksPerSector(uint8_t sectorNo); uint8_t mfNumBlocksPerSector(uint8_t sectorNo);

View file

@ -44,8 +44,7 @@
#include "emv/emvjson.h" #include "emv/emvjson.h"
// Load all settings into memory (struct) // Load all settings into memory (struct)
int settings_load (void) int settings_load (void) {
{
// loadFileJson wants these, so pass in place holder values, though not used // loadFileJson wants these, so pass in place holder values, though not used
// in settings load; // in settings load;
uint8_t dummyData = 0x00; uint8_t dummyData = 0x00;
@ -68,6 +67,8 @@ int settings_load (void)
int window_ypos; int window_ypos;
int window_hsize; int window_hsize;
int window_wsize; int window_wsize;
bool use_emojis
bool use_hints
*/ */
printf (" Settings Version : [%s]\n", mySettings.version); printf (" Settings Version : [%s]\n", mySettings.version);
printf (" os_windows_usecolor (bool) : [%d]\n", mySettings.os_windows_usecolor); printf (" os_windows_usecolor (bool) : [%d]\n", mySettings.os_windows_usecolor);
@ -76,13 +77,13 @@ int settings_load (void)
printf (" window_ypos (int) : [%d]\n", mySettings.window_ypos); printf (" window_ypos (int) : [%d]\n", mySettings.window_ypos);
printf (" window_hsize (int) : [%d]\n", mySettings.window_hsize); printf (" window_hsize (int) : [%d]\n", mySettings.window_hsize);
printf (" window_wsize (int) : [%d]\n", mySettings.window_wsize); printf (" window_wsize (int) : [%d]\n", mySettings.window_wsize);
printf (" use emoji (bool) : [%d]\n", mySettings.use_emojis);
printf (" use hints (bool) : [%d]\n", mySettings.use_hints);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// Save all settings from memory (struct) to file // Save all settings from memory (struct) to file
int settings_save (void) int settings_save(void) {
{
// Note sure if backup has value ? // Note sure if backup has value ?
char backupFilename[500]; char backupFilename[500];
@ -105,17 +106,13 @@ int settings_save (void)
uint8_t dummyData = 0x00; uint8_t dummyData = 0x00;
size_t dummyDL = 0x00; size_t dummyDL = 0x00;
// int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen);
if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS) if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS)
PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename); PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
void settings_save_callback (json_t *root) void settings_save_callback(json_t *root) {
{
// extern settings_t mySettings;
printf ("==> Save Settings\n"); printf ("==> Save Settings\n");
//JsonSaveStr(root, "FileType", "settings"); //JsonSaveStr(root, "FileType", "settings");
@ -137,11 +134,12 @@ void settings_save_callback (json_t *root)
JsonSaveInt (root,"window.ypos", mySettings.window_ypos); JsonSaveInt (root,"window.ypos", mySettings.window_ypos);
JsonSaveInt (root,"window.hsize", mySettings.window_hsize); JsonSaveInt (root,"window.hsize", mySettings.window_hsize);
JsonSaveInt (root,"window.wsize", mySettings.window_wsize); JsonSaveInt (root,"window.wsize", mySettings.window_wsize);
JsonSaveBoolean (root,"client.useEmojis", mySettings.use_emojis);
JsonSaveBoolean (root,"client.useHints", mySettings.use_hints);
} }
void settings_load_callback (json_t *root) void settings_load_callback(json_t *root) {
{
// extern settings_t mySettings;
json_error_t up_error = {0}; json_error_t up_error = {0};
int b1; int b1;
int i1; int i1;
@ -181,4 +179,16 @@ void settings_load_callback (json_t *root)
else // default else // default
mySettings.window_wsize = 0; mySettings.window_wsize = 0;
// Use EMOJIS
if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useEmojis",&b1) == 0)
mySettings.use_emojis = b1;
else // default
mySettings.use_emojis = false;
// Use Hints
if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useHints",&b1) == 0)
mySettings.use_hints = b1;
else // default
mySettings.use_hints = false;
} }

View file

@ -24,6 +24,8 @@ typedef struct {
int window_ypos; int window_ypos;
int window_hsize; int window_hsize;
int window_wsize; int window_wsize;
bool use_emojis;
bool use_hints;
} settings_t; } settings_t;
// Settings struct so as to be available to other modules by including settings.h // Settings struct so as to be available to other modules by including settings.h

View file

@ -18,7 +18,7 @@ Always use the latest repository commits from *master* branch. There are always
* [File not found](#file-not-found) * [File not found](#file-not-found)
* [Pixmap / pixbuf warnings](#pixmap--pixbuf-warnings) * [Pixmap / pixbuf warnings](#pixmap--pixbuf-warnings)
* [Usb cable](#usb-cable) * [Usb cable](#usb-cable)
* [WSL 2 explorer.exe . doesnt work](WSL-2) * [WSL 2 explorer.exe . doesnt work](#WSL-2)
## `pm3` or `pm3-flash*` doesn't see my Proxmark ## `pm3` or `pm3-flash*` doesn't see my Proxmark

View file

@ -618,6 +618,11 @@ typedef struct {
#define PM3_EOUTOFBOUND -17 #define PM3_EOUTOFBOUND -17
// exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer // exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer
#define PM3_ECARDEXCHANGE -18 #define PM3_ECARDEXCHANGE -18
// Failed to create APDU,
#define PM3_EAPDU_ENCODEFAIL -19
// APDU responded with a failure code
#define PM3_EAPDU_FAIL -20
// No data pm3: no data available, no host frame available (not really an error) // No data pm3: no data available, no host frame available (not really an error)
#define PM3_ENODATA -98 #define PM3_ENODATA -98
// Quit program client: reserved, order to quit the program // Quit program client: reserved, order to quit the program

View file

@ -349,44 +349,62 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
// 6x xx = ERROR // 6x xx = ERROR
// MIFARE DESFire command set: // MIFARE DESFire command set:
#define MFDES_CREATE_APPLICATION 0xca
#define MFDES_DELETE_APPLICATION 0xda
#define MFDES_GET_APPLICATION_IDS 0x6a
#define MFDES_SELECT_APPLICATION 0x5a
#define MFDES_FORMAT_PICC 0xfc
#define MFDES_GET_VERSION 0x60 #define MFDES_GET_VERSION 0x60
#define MFDES_READ_DATA 0xbd
#define MFDES_WRITE_DATA 0x3d #define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE
#define MFDES_GET_VALUE 0x6c #define MFDES_AUTHENTICATE_ISO 0x1A // AUTHENTICATE_STANDARD
#define MFDES_CREDIT 0x0c #define MFDES_AUTHENTICATE_AES 0xAA
#define MFDES_DEBIT 0xdc
#define MFDES_LIMITED_CREDIT 0x1c #define MFDES_CREDIT 0x0C
#define MFDES_WRITE_RECORD 0x3b #define MFDES_LIMITED_CREDIT 0x1C
#define MFDES_READ_RECORDS 0xbb #define MFDES_DEBIT 0xDC
#define MFDES_CLEAR_RECORD_FILE 0xeb
#define MFDES_COMMIT_TRANSACTION 0xc7 #define MFDES_WRITE_RECORD 0x3B
#define MFDES_ABORT_TRANSACTION 0xa7 #define MFDES_READSIG 0x3C
#define MFDES_GET_FREE_MEMORY 0x6e #define MFDES_WRITE_DATA 0x3D
#define MFDES_GET_FILE_IDS 0x6f
#define MFDES_GET_ISOFILE_IDS 0x61
#define MFDES_GET_FILE_SETTINGS 0xf5
#define MFDES_CHANGE_FILE_SETTINGS 0x5f
#define MFDES_CREATE_STD_DATA_FILE 0xcd
#define MFDES_CREATE_BACKUP_DATA_FILE 0xcb
#define MFDES_CREATE_VALUE_FILE 0xcc
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xc1
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xc0
#define MFDES_DELETE_FILE 0xdf
#define MFDES_AUTHENTICATE 0x0a // AUTHENTICATE_NATIVE
#define MFDES_AUTHENTICATE_ISO 0x1a // AUTHENTICATE_STANDARD
#define MFDES_AUTHENTICATE_AES 0xaa
#define MFDES_CHANGE_KEY_SETTINGS 0x54
#define MFDES_GET_KEY_SETTINGS 0x45 #define MFDES_GET_KEY_SETTINGS 0x45
#define MFDES_CHANGE_KEY 0xc4 #define MFDES_CHANGE_KEY_SETTINGS 0x54
#define MFDES_SELECT_APPLICATION 0x5A
#define MFDES_CHANGE_FILE_SETTINGS 0x5F
#define MFDES_GET_ISOFILE_IDS 0x61
#define MFDES_GET_KEY_VERSION 0x64 #define MFDES_GET_KEY_VERSION 0x64
#define MFDES_GET_APPLICATION_IDS 0x6A
#define MFDES_GET_VALUE 0x6C
#define MFDES_GET_FREE_MEMORY 0x6E
#define MFDES_GET_DF_NAMES 0x6D
#define MFDES_GET_FILE_IDS 0x6F
#define MFDES_ABORT_TRANSACTION 0xA7
#define MFDES_AUTHENTICATION_FRAME 0xAF #define MFDES_AUTHENTICATION_FRAME 0xAF
#define MFDES_ADDITIONAL_FRAME 0xAF #define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_READSIG 0x3C #define MFDES_ADDITIONAL_FRAME_RESP 0x91AF
#define MFDES_SUCCESS_FRAME_RESP 0x9100
#define MFDES_EAUTH_RESP 0x91AE
#define MFDES_ENO_SUCH_KEY_RESP 0x9140
#define MFDES_READ_RECORDS 0xBB
#define MFDES_READ_DATA 0xBD
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1
#define MFDES_CHANGE_KEY 0xC4
#define MFDES_COMMIT_TRANSACTION 0xC7
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB
#define MFDES_CREATE_VALUE_FILE 0xCC
#define MFDES_CREATE_STD_DATA_FILE 0xCD
#define MFDES_CLEAR_RECORD_FILE 0xEB
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_DELETE_FILE 0xDF
#define MFDES_GET_FILE_SETTINGS 0xF5
#define MFDES_FORMAT_PICC 0xFC
// LEGIC Commands // LEGIC Commands
#define LEGIC_MIM_22 0x0D #define LEGIC_MIM_22 0x0D