mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
added Ultralight-C simulation. hf mfu sim -t 13. Use eload first. Also added support to upload UL-C dictionaries and UL-AES to spiffs memory. A lot of textual reworked across client. Unifiy texts and a bit more color ;)
This commit is contained in:
@@ -3,6 +3,9 @@ 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...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `mem load` - now handles UL-C and UL-AES dictionary files (@iceman1001)
|
||||
- Changed `hf mfu sim` - now support UL-C simulation (@iceman1001)
|
||||
- Added `!` - run system commands from inside the client. Potentially dangerous if running client as SUDO, SU, ROOT (@iceman1001)
|
||||
|
||||
## [Daddy Iceman.4.20469][2025-06-16]
|
||||
- Fixed edge case in fm11rf08s key recovery tools (@doegox)
|
||||
|
||||
@@ -157,7 +157,7 @@ void RunMod(void) {
|
||||
if (button_pressed != BUTTON_NO_CLICK || data_available())
|
||||
break;
|
||||
else if (state == STATE_SEARCH) {
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) {
|
||||
if (iso14443a_select_card(NULL, &card, NULL, true, 0, true) == 0) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
@@ -246,7 +246,7 @@ void RunMod(void) {
|
||||
FLAG_SET_UID_IN_DATA(flags, 7);
|
||||
|
||||
Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
|
||||
SimulateIso14443aTag(7, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(7, flags, card.uid, 0, NULL, 0, false, false);
|
||||
|
||||
// Go back to search state if user presses pm3-button
|
||||
state = STATE_SEARCH;
|
||||
|
||||
@@ -234,7 +234,7 @@ static void become_card(void) {
|
||||
tag_response_info_t *canned;
|
||||
uint32_t cuid;
|
||||
uint8_t pages;
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &canned, &cuid, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &canned, &cuid, &pages, NULL) == false) {
|
||||
DbpString(_RED_("Error initializing the emulation process!"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@ failtag:
|
||||
SpinOff(50);
|
||||
LED_A_ON();
|
||||
|
||||
while (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) {
|
||||
while (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) {
|
||||
WDT_HIT();
|
||||
if (BUTTON_HELD(10) == BUTTON_HOLD) {
|
||||
WDT_HIT();
|
||||
@@ -785,7 +785,7 @@ static int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype) {
|
||||
|
||||
bool isOK = true;
|
||||
|
||||
if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) {
|
||||
if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) {
|
||||
isOK = false;
|
||||
}
|
||||
|
||||
@@ -844,8 +844,7 @@ static int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTr
|
||||
for (uint8_t i = 0; i < keyCount; i++) {
|
||||
|
||||
/* no need for anticollision. just verify tag is still here */
|
||||
// if (!iso14443a_fast_select_card(colin_cjuid, 0)) {
|
||||
if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) {
|
||||
if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) {
|
||||
cjSetCursLeft();
|
||||
DbprintfEx(FLAG_NEWLINE, "%sFATAL%s : E_MF_LOSTTAG", _XRED_, _XWHITE_);
|
||||
break;
|
||||
@@ -963,7 +962,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, const
|
||||
|
||||
// get UID from chip
|
||||
if (workFlags & 0x01) {
|
||||
if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) {
|
||||
if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Can't select card");
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -89,22 +89,22 @@ void RunMod(void) {
|
||||
Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
|
||||
if (card.sak == 0x08 && card.atqa[0] == 0x04 && card.atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 1k");
|
||||
SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0, false, false);
|
||||
} else if (card.sak == 0x08 && card.atqa[0] == 0x44 && card.atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 4k ");
|
||||
SimulateIso14443aTag(8, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(8, flags, card.uid, 0, NULL, 0, false, false);
|
||||
} else if (card.sak == 0x00 && card.atqa[0] == 0x44 && card.atqa[1] == 0) {
|
||||
DbpString("Mifare Ultralight");
|
||||
SimulateIso14443aTag(2, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(2, flags, card.uid, 0, NULL, 0, false, false);
|
||||
} else if (card.sak == 0x20 && card.atqa[0] == 0x04 && card.atqa[1] == 0x03) {
|
||||
DbpString("Mifare DESFire");
|
||||
SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0, false, false);
|
||||
} else if (card.sak == 0x20 && card.atqa[0] == 0x44 && card.atqa[1] == 0x03) {
|
||||
DbpString("Mifare DESFire Ev1/Plus/JCOP");
|
||||
SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0, false, false);
|
||||
} else {
|
||||
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
|
||||
SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0);
|
||||
SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0, false, false);
|
||||
}
|
||||
|
||||
// Go back to search state if user presses pm3-button
|
||||
|
||||
@@ -379,7 +379,7 @@ void RunMod(void) {
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
// tag type: 11 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
if (SimulateIso14443aInit(11, flags, data, NULL, 0, &responses, &cuid, NULL) == false) {
|
||||
if (SimulateIso14443aInit(11, flags, data, NULL, 0, &responses, &cuid, NULL, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_RED_("Error initializing the emulation process!"));
|
||||
|
||||
@@ -268,7 +268,7 @@ void RunMod() {
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
// 4 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
if (SimulateIso14443aInit(4, flags, data, NULL, 0, &responses, &cuid, NULL) == false) {
|
||||
if (SimulateIso14443aInit(4, flags, data, NULL, 0, &responses, &cuid, NULL, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_RED_("Error initializing the emulation process!"));
|
||||
|
||||
@@ -191,7 +191,7 @@ void RunMod(void) {
|
||||
|
||||
memcpy(data, stuid, sizeof(stuid));
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the simulation process!");
|
||||
@@ -369,7 +369,7 @@ void RunMod(void) {
|
||||
|
||||
memcpy(data, stuid, sizeof(stuid));
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the simulation process!");
|
||||
|
||||
@@ -96,7 +96,7 @@ void RunMod(void) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
|
||||
if (iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true) == 0) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
@@ -253,25 +253,25 @@ void RunMod(void) {
|
||||
|
||||
if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 1k");
|
||||
SimulateIso14443aTag(1, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(1, flags, data, 0, NULL, 0, false, false);
|
||||
} else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 4k (4b uid)");
|
||||
SimulateIso14443aTag(8, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(8, flags, data, 0, NULL, 0, false, false);
|
||||
} else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 4k (7b uid)");
|
||||
SimulateIso14443aTag(8, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(8, flags, data, 0, NULL, 0, false, false);
|
||||
} else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Ultralight");
|
||||
SimulateIso14443aTag(2, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(2, flags, data, 0, NULL, 0, false, false);
|
||||
} else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) {
|
||||
DbpString("Mifare DESFire");
|
||||
SimulateIso14443aTag(3, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(3, flags, data, 0, NULL, 0, false, false);
|
||||
} else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0x03) {
|
||||
DbpString("Mifare DESFire Ev1/Plus/JCOP");
|
||||
SimulateIso14443aTag(3, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(3, flags, data, 0, NULL, 0, false, false);
|
||||
} else {
|
||||
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
|
||||
SimulateIso14443aTag(1, flags, data, 0, NULL, 0);
|
||||
SimulateIso14443aTag(1, flags, data, 0, NULL, 0, false, false);
|
||||
}
|
||||
|
||||
} else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
|
||||
+30
-1
@@ -480,6 +480,32 @@ static void SendStatus(uint32_t wait) {
|
||||
} else {
|
||||
Dbprintf(" iClass... "_RED_("%u")" keys - "_RED_("%s"), num, ICLASS_KEYS_FILE);
|
||||
}
|
||||
|
||||
if (exists_in_spiffs(MFULC_KEYS_FILE)) {
|
||||
num = size_in_spiffs(MFULC_KEYS_FILE) / MFULC_KEY_LENGTH;
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
Dbprintf(" UL-C..... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MFULC_KEYS_FILE);
|
||||
} else {
|
||||
Dbprintf(" UL-C..... "_RED_("%u")" keys - "_RED_("%s"), num, MFULC_KEYS_FILE);
|
||||
}
|
||||
|
||||
if (exists_in_spiffs(MFULAES_KEYS_FILE)) {
|
||||
num = size_in_spiffs(MFULAES_KEYS_FILE) / MFULAES_KEY_LENGTH;
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
Dbprintf(" UL-AES... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MFULAES_KEYS_FILE);
|
||||
} else {
|
||||
Dbprintf(" UL-AES... "_RED_("%u")" keys - "_RED_("%s"), num, MFULAES_KEYS_FILE);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
DbpString("");
|
||||
reply_ng(CMD_STATUS, PM3_SUCCESS, NULL, 0);
|
||||
@@ -1723,10 +1749,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
uint8_t uid[10];
|
||||
uint8_t exitAfter;
|
||||
uint8_t rats[20];
|
||||
bool ulc_p1;
|
||||
bool ulc_p2;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SimulateIso14443aTag(payload->tagtype, payload->flags, payload->uid,
|
||||
payload->exitAfter, payload->rats, sizeof(payload->rats)); // ## Simulate iso14443a tag - pass tag type & UID
|
||||
payload->exitAfter, payload->rats, sizeof(payload->rats),
|
||||
payload->ulc_p1, payload->ulc_p2); // ## Simulate iso14443a tag - pass tag type & UID
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_SIM_AID: {
|
||||
|
||||
+1
-3
@@ -102,9 +102,7 @@ void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void print_result(const char *name, const uint8_t *d, size_t
|
||||
|
||||
n) {
|
||||
void print_result(const char *name, const uint8_t *d, size_t n) {
|
||||
|
||||
const uint8_t *p = d;
|
||||
uint16_t tmp = n & 0xFFF0;
|
||||
|
||||
+198
-43
@@ -370,16 +370,16 @@ tUart14a *GetUart14a(void) {
|
||||
|
||||
void Uart14aReset(void) {
|
||||
Uart.state = STATE_14A_UNSYNCD;
|
||||
Uart.shiftReg = 0; // shiftreg to hold decoded data bits
|
||||
Uart.bitCount = 0;
|
||||
Uart.len = 0; // number of decoded data bytes
|
||||
Uart.parityLen = 0; // number of decoded parity bytes
|
||||
Uart.shiftReg = 0; // shiftreg to hold decoded data bits
|
||||
Uart.parityBits = 0; // holds 8 parity bits
|
||||
Uart.startTime = 0;
|
||||
Uart.endTime = 0;
|
||||
Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits
|
||||
Uart.posCnt = 0;
|
||||
Uart.syncBit = 9999;
|
||||
Uart.parityBits = 0; // holds 8 parity bits
|
||||
Uart.parityLen = 0; // number of decoded parity bytes
|
||||
Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits
|
||||
Uart.startTime = 0;
|
||||
Uart.endTime = 0;
|
||||
}
|
||||
|
||||
void Uart14aInit(uint8_t *d, uint16_t n, uint8_t *par) {
|
||||
@@ -1188,9 +1188,24 @@ bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_
|
||||
}
|
||||
}
|
||||
|
||||
static void Simulate_reread_ulc_key(uint8_t *ulc_key) {
|
||||
// copy UL-C key from emulator memory
|
||||
|
||||
mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr();
|
||||
|
||||
memcpy(ulc_key, mfu_header->data + (0x2D * 4), 4);
|
||||
memcpy(ulc_key + 4, mfu_header->data + (0x2C * 4), 4);
|
||||
memcpy(ulc_key + 8, mfu_header->data + (0x2F * 4), 4);
|
||||
memcpy(ulc_key + 12, mfu_header->data + (0x2E * 4), 4);
|
||||
|
||||
reverse_array(ulc_key, 4);
|
||||
reverse_array(ulc_key + 4, 4);
|
||||
reverse_array(ulc_key + 8, 4);
|
||||
reverse_array(ulc_key + 12, 4);
|
||||
}
|
||||
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
uint8_t *ats, size_t ats_len, tag_response_info_t **responses,
|
||||
uint32_t *cuid, uint8_t *pages) {
|
||||
uint32_t *cuid, uint8_t *pages, uint8_t *ulc_key) {
|
||||
uint8_t sak = 0;
|
||||
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
||||
static uint8_t rATQA[2] = { 0x00 };
|
||||
@@ -1340,6 +1355,38 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
sak = 0x20;
|
||||
break;
|
||||
}
|
||||
case 13: { // MIFARE Ultralight-C
|
||||
|
||||
rATQA[0] = 0x44;
|
||||
sak = 0x00;
|
||||
|
||||
// some first pages of UL/NTAG dump is special data
|
||||
mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr();
|
||||
*pages = MAX(mfu_header->pages, 47);
|
||||
|
||||
// copy UL-C key from emulator memory
|
||||
memcpy(ulc_key, mfu_header->data + (0x2D * 4), 4);
|
||||
memcpy(ulc_key + 4, mfu_header->data + (0x2C * 4), 4);
|
||||
memcpy(ulc_key + 8, mfu_header->data + (0x2F * 4), 4);
|
||||
memcpy(ulc_key + 12, mfu_header->data + (0x2E * 4), 4);
|
||||
|
||||
reverse_array(ulc_key, 4);
|
||||
reverse_array(ulc_key + 4, 4);
|
||||
reverse_array(ulc_key + 8, 4);
|
||||
reverse_array(ulc_key + 12, 4);
|
||||
|
||||
/*
|
||||
Dbprintf("UL-C Pages....... %u ( 47 )", *pages);
|
||||
DbpString("UL-C 3des key... ");
|
||||
Dbhexdump(16, ulc_key, false);
|
||||
*/
|
||||
|
||||
if (IS_FLAG_UID_IN_DATA(flags, 7)) {
|
||||
DbpString("UL-C UID........ ");
|
||||
Dbhexdump(7, data, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType);
|
||||
return false;
|
||||
@@ -1365,7 +1412,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
|
||||
// if uid not supplied then get from emulator memory
|
||||
if ((memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10) == 0) || IS_FLAG_UID_IN_EMUL(flags)) {
|
||||
if (tagType == 2 || tagType == 7) {
|
||||
if (tagType == 2 || tagType == 7 || tagType == 13) {
|
||||
uint16_t start = MFU_DUMP_PREFIX_LENGTH;
|
||||
uint8_t emdata[8];
|
||||
emlGet(emdata, start, sizeof(emdata));
|
||||
@@ -1532,13 +1579,18 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// 'hf 14a sim'
|
||||
//-----------------------------------------------------------------------------
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||
uint8_t *ats, size_t ats_len) {
|
||||
uint8_t *ats, size_t ats_len, bool ulc_part1, bool ulc_part2) {
|
||||
|
||||
#define ATTACK_KEY_COUNT 16
|
||||
#define ULC_TAG_NONCE "\x01\x02\x03\x04\x05\x06\x07\x08"
|
||||
|
||||
tag_response_info_t *responses;
|
||||
uint32_t cuid = 0;
|
||||
uint32_t nonce = 0;
|
||||
/// Ultralight-C 3des2k
|
||||
uint8_t ulc_key[16] = { 0x00 };
|
||||
uint8_t ulc_iv[8] = { 0x00 };
|
||||
bool ulc_reread_key = false;
|
||||
uint8_t pages = 0;
|
||||
|
||||
// Here, we collect CUID, block1, keytype1, NT1, NR1, AR1, CUID, block2, keytyp2, NT2, NR2, AR2
|
||||
@@ -1582,7 +1634,9 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, useruid, ats, ats_len, &responses, &cuid, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, useruid, ats, ats_len
|
||||
, &responses, &cuid, &pages
|
||||
, ulc_key) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
return;
|
||||
@@ -1670,7 +1724,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
order = ORDER_NONE; // back to work state
|
||||
p_response = NULL;
|
||||
|
||||
} else if (order == ORDER_AUTH && len == 8) {
|
||||
} else if (order == ORDER_AUTH && len == 8 && tagType != 2 && tagType != 7 && tagType != 13) {
|
||||
// Received {nr] and {ar} (part of authentication)
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
uint32_t nr = bytes_to_num(receivedCmd, 4);
|
||||
@@ -1760,7 +1814,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ
|
||||
uint8_t block = receivedCmd[1];
|
||||
// if Ultralight or NTAG (4 byte blocks)
|
||||
if (tagType == 7 || tagType == 2) {
|
||||
if (tagType == 7 || tagType == 2 || tagType == 13) {
|
||||
if (block > pages) {
|
||||
// send NACK 0x0 == invalid argument
|
||||
EmSend4bit(CARD_NACK_IV);
|
||||
@@ -1809,7 +1863,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
EmSendCmd(emdata, len + 2);
|
||||
}
|
||||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7 || tagType == 13)) { // Received a WRITE
|
||||
|
||||
p_response = NULL;
|
||||
|
||||
@@ -1847,12 +1901,15 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
// send ACK
|
||||
EmSend4bit(CARD_ACK);
|
||||
|
||||
if (tagType == 13 && block >= 0x2c && block <= 0x2F) {
|
||||
ulc_reread_key = true;
|
||||
}
|
||||
} else {
|
||||
// send NACK 0x1 == crc/parity error
|
||||
EmSend4bit(CARD_NACK_PA);
|
||||
}
|
||||
goto jump;
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7)) {
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7 || tagType == 13)) {
|
||||
// cmd + block + 2 bytes crc
|
||||
if (CheckCrc14A(receivedCmd, len)) {
|
||||
wrblock = receivedCmd[1];
|
||||
@@ -1926,7 +1983,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
p_response = &responses[RESP_INDEX_VERSION];
|
||||
} else if (receivedCmd[0] == MFDES_GET_VERSION && len == 4 && (tagType == 3)) {
|
||||
p_response = &responses[RESP_INDEX_VERSION];
|
||||
} else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request
|
||||
} else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7 && tagType != 13) { // Received an authentication request
|
||||
cardAUTHKEY = receivedCmd[0] - 0x60;
|
||||
cardAUTHSC = receivedCmd[1] / 4; // received block num
|
||||
|
||||
@@ -1945,9 +2002,84 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
|
||||
} else {
|
||||
p_response = &responses[RESP_INDEX_ATS];
|
||||
}
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1 && len == 4 && tagType == 13) { // ULC authentication, or Desfire Authentication
|
||||
|
||||
// reset IV to all zeros
|
||||
memset(ulc_iv, 0x00, 8);
|
||||
|
||||
if (ulc_reread_key) {
|
||||
Simulate_reread_ulc_key(ulc_key);
|
||||
ulc_reread_key = false;
|
||||
}
|
||||
|
||||
dynamic_response_info.response[0] = MIFARE_ULC_AUTH_2;
|
||||
|
||||
// our very random TAG NONCE
|
||||
memcpy(dynamic_response_info.response + 1, ULC_TAG_NONCE, 8);
|
||||
|
||||
if (ulc_part1) {
|
||||
memset(dynamic_response_info.response + 1, 0, 8);
|
||||
} else {
|
||||
// encrypt TAG NONCE
|
||||
tdes_nxp_send(dynamic_response_info.response + 1, dynamic_response_info.response + 1, 8, ulc_key, ulc_iv, 2);
|
||||
}
|
||||
|
||||
// Add CRC
|
||||
AddCrc14A(dynamic_response_info.response, 9);
|
||||
|
||||
// prepare to send
|
||||
dynamic_response_info.response_n = 1 + 8 + 2;
|
||||
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
|
||||
p_response = &dynamic_response_info;
|
||||
order = ORDER_AUTH;
|
||||
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_2 && len == 19 && tagType == 13) { // ULC authentication, or Desfire Authentication
|
||||
|
||||
uint8_t enc_rnd_ab[16] = { 0x00 };
|
||||
uint8_t rnd_ab[16] = { 0x00 };
|
||||
|
||||
// copy reader response
|
||||
memcpy(enc_rnd_ab, receivedCmd + 1, 16);
|
||||
|
||||
// decrypt
|
||||
tdes_nxp_receive(enc_rnd_ab, rnd_ab, 16, ulc_key, ulc_iv, 2);
|
||||
|
||||
ror(rnd_ab + 8, 8);
|
||||
|
||||
if (memcmp(rnd_ab + 8, ULC_TAG_NONCE, 8) != 0) {
|
||||
Dbprintf("failed authentication");
|
||||
}
|
||||
|
||||
// OK response
|
||||
dynamic_response_info.response[0] = 0x00;
|
||||
|
||||
if (ulc_part2) {
|
||||
// try empty auth but with correct CRC and 0x00 command
|
||||
memset(dynamic_response_info.response + 1, 0, 8);
|
||||
} else {
|
||||
// rol RndA
|
||||
rol(rnd_ab, 8);
|
||||
|
||||
// encrypt RndA
|
||||
tdes_nxp_send(rnd_ab, dynamic_response_info.response + 1, 8, ulc_key, ulc_iv, 2);
|
||||
}
|
||||
|
||||
// Add CRC
|
||||
AddCrc14A(dynamic_response_info.response, 9);
|
||||
|
||||
dynamic_response_info.response_n = 1 + 8 + 2;
|
||||
|
||||
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
|
||||
p_response = &dynamic_response_info;
|
||||
order = ORDER_NONE;
|
||||
// Add CRC
|
||||
AddCrc14A(dynamic_response_info.response, 17);
|
||||
|
||||
dynamic_response_info.response_n = 1 + 16 + 2;
|
||||
|
||||
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
|
||||
p_response = &dynamic_response_info;
|
||||
order = ORDER_NONE;
|
||||
} else if (receivedCmd[0] == MIFARE_ULEV1_AUTH && len == 7 && tagType == 7) { // NTAG / EV-1
|
||||
uint8_t pwd[4] = {0, 0, 0, 0};
|
||||
emlGet(pwd, (pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd));
|
||||
@@ -2128,13 +2260,16 @@ jump:
|
||||
// of bits specified in the delay parameter.
|
||||
static void PrepareDelayedTransfer(uint16_t delay) {
|
||||
delay &= 0x07;
|
||||
if (!delay) return;
|
||||
if (delay == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t bitmask = 0;
|
||||
uint8_t bits_shifted = 0;
|
||||
|
||||
for (uint16_t i = 0; i < delay; i++)
|
||||
for (uint16_t i = 0; i < delay; i++) {
|
||||
bitmask |= (0x01 << i);
|
||||
}
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
@@ -2163,6 +2298,7 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing
|
||||
Dbprintf("Warning: HF field is off");
|
||||
return;
|
||||
}
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (timing) {
|
||||
@@ -2337,7 +2473,7 @@ int EmGetCmd(uint8_t *received, uint16_t received_max_len, uint16_t *len, uint8_
|
||||
// button press, takes a bit time, might mess with simualtion
|
||||
if (checker-- == 0) {
|
||||
if (BUTTON_PRESS()) {
|
||||
Dbprintf("----------- " _GREEN_("Breaking / User aborted") " ----------");
|
||||
Dbprintf("----------- " _GREEN_("Button pressed, user aborted") " ----------");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2515,9 +2651,9 @@ int EmSendPrecompiledCmd(tag_response_info_t *p_response) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime,
|
||||
uint32_t reader_EndTime, uint8_t *reader_Parity, uint8_t *tag_data,
|
||||
uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) {
|
||||
bool EmLogTrace(const uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime,
|
||||
uint32_t reader_EndTime, const uint8_t *reader_Parity, const uint8_t *tag_data,
|
||||
uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, const uint8_t *tag_Parity) {
|
||||
|
||||
// we cannot exactly measure the end and start of a received command from reader. However we know that the delay from
|
||||
// end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp.
|
||||
@@ -2851,7 +2987,7 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
||||
// requests ATS unless no_rats is true
|
||||
int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr,
|
||||
bool anticollision, uint8_t num_cascades, bool no_rats,
|
||||
iso14a_polling_parameters_t *polling_parameters) {
|
||||
const iso14a_polling_parameters_t *polling_parameters) {
|
||||
|
||||
uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller
|
||||
|
||||
@@ -3106,7 +3242,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades) {
|
||||
int iso14443a_fast_select_card(const uint8_t *uid_ptr, uint8_t num_cascades) {
|
||||
uint8_t resp[3] = { 0 }; // theoretically. max 1 Byte SAK, 2 Byte CRC, 3 bytes is enough
|
||||
uint8_t resp_par[1] = {0};
|
||||
|
||||
@@ -3524,17 +3660,23 @@ OUT:
|
||||
// Therefore try in alternating directions.
|
||||
static int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
|
||||
|
||||
if (nt1 == nt2) return 0;
|
||||
if (nt1 == nt2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t nttmp1 = nt1;
|
||||
uint32_t nttmp2 = nt2;
|
||||
|
||||
for (uint16_t i = 1; i < 32768; i++) {
|
||||
nttmp1 = prng_successor(nttmp1, 1);
|
||||
if (nttmp1 == nt2) return i;
|
||||
if (nttmp1 == nt2) {
|
||||
return i;
|
||||
}
|
||||
|
||||
nttmp2 = prng_successor(nttmp2, 1);
|
||||
if (nttmp2 == nt1) return -i;
|
||||
if (nttmp2 == nt1) {
|
||||
return -i;
|
||||
}
|
||||
}
|
||||
|
||||
return (-99999); // either nt1 or nt2 are invalid nonces
|
||||
@@ -3542,8 +3684,8 @@ static int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
|
||||
|
||||
|
||||
#define PRNG_SEQUENCE_LENGTH (1 << 16)
|
||||
#define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
|
||||
#define MAX_SYNC_TRIES 32
|
||||
#define MAX_UNEXPECTED_RANDOM (4) // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up.
|
||||
#define MAX_SYNC_TRIES (32)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Recover several bits of the cypher stream. This implements (first stages of)
|
||||
@@ -3697,9 +3839,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
|
||||
// we didn't calibrate our clock yet,
|
||||
// iceman: has to be calibrated every time.
|
||||
if (previous_nt && !nt_attacked) {
|
||||
if (previous_nt && (nt_attacked == 0)) {
|
||||
|
||||
int nt_distance = dist_nt(previous_nt, nt);
|
||||
int32_t nt_distance = dist_nt(previous_nt, nt);
|
||||
|
||||
// if no distance between, then we are in sync.
|
||||
if (nt_distance == 0) {
|
||||
@@ -3725,7 +3867,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences;
|
||||
|
||||
// no negative sync_cycles, and too small sync_cycles will result in continuous misses
|
||||
if (sync_cycles <= 10) sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||
if (sync_cycles <= 10) {
|
||||
sync_cycles += PRNG_SEQUENCE_LENGTH;
|
||||
}
|
||||
|
||||
// reset sync_cycles
|
||||
if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) {
|
||||
@@ -3733,8 +3877,14 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
sync_time = GetCountSspClk() & 0xfffffff8;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n"
|
||||
, i
|
||||
, nt_distance
|
||||
, elapsed_prng_sequences
|
||||
, sync_cycles
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -3764,8 +3914,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
} else {
|
||||
sync_cycles += catch_up_cycles;
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles);
|
||||
}
|
||||
|
||||
last_catch_up = 0;
|
||||
catch_up_cycles = 0;
|
||||
@@ -3778,8 +3929,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
if (received_nack) {
|
||||
catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer
|
||||
|
||||
if (nt_diff == 0)
|
||||
if (nt_diff == 0) {
|
||||
par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change
|
||||
}
|
||||
|
||||
par_list[nt_diff] = reflect8(par[0]);
|
||||
ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // xor with NACK value to get keystream
|
||||
@@ -3798,12 +3950,15 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
|
||||
} else {
|
||||
// No NACK.
|
||||
if (nt_diff == 0 && first_try) {
|
||||
|
||||
par[0]++;
|
||||
|
||||
if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK.
|
||||
isOK = 2;
|
||||
return_status = PM3_ESOFT;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Why this?
|
||||
par[0] = ((par[0] & 0x1F) + 1) | par_low;
|
||||
@@ -3854,7 +4009,7 @@ void DetectNACKbug(void) {
|
||||
uint8_t uid[10] = { 0x00 };
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = { 0x00 };
|
||||
uint8_t par[1] = {0x00 }; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
|
||||
uint8_t par[2] = {0x00 }; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
|
||||
|
||||
uint32_t nt = 0, previous_nt = 0, nt_attacked = 0, cuid = 0;
|
||||
int32_t catch_up_cycles = 0, last_catch_up = 0;
|
||||
@@ -3905,9 +4060,9 @@ void DetectNACKbug(void) {
|
||||
++checkbtn_cnt;
|
||||
|
||||
// this part is from Piwi's faster nonce collecting part in Hardnested.
|
||||
if (!have_uid) { // need a full select cycle to get the uid first
|
||||
if (have_uid == false) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Mifare: Can't select card (ALL)");
|
||||
i = 0;
|
||||
continue;
|
||||
@@ -3929,7 +4084,7 @@ void DetectNACKbug(void) {
|
||||
}
|
||||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Mifare: Can't select card (UID)");
|
||||
i = 0;
|
||||
have_uid = false;
|
||||
@@ -4143,7 +4298,7 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, uid, ats, ats_len, &responses, &cuid, &pages) == false) {
|
||||
if (SimulateIso14443aInit(tagType, flags, uid, ats, ats_len, &responses, &cuid, &pages, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
return;
|
||||
|
||||
+10
-6
@@ -143,7 +143,7 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t
|
||||
|
||||
void RAMFUNC SniffIso14443a(uint8_t param);
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||
uint8_t *ats, size_t ats_len);
|
||||
uint8_t *ats, size_t ats_len, bool ulc_part1, bool ulc_part2);
|
||||
|
||||
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||
uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len,
|
||||
@@ -152,7 +152,8 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||
|
||||
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
uint8_t *ats, size_t ats_len, tag_response_info_t **responses,
|
||||
uint32_t *cuid, uint8_t *pages);
|
||||
uint32_t *cuid, uint8_t *pages,
|
||||
uint8_t *ulc_key);
|
||||
|
||||
bool GetIso14443aCommandFromReader(uint8_t *received, uint16_t received_maxlen, uint8_t *par, int *len);
|
||||
void iso14443a_antifuzz(uint32_t flags);
|
||||
@@ -165,8 +166,10 @@ uint16_t ReaderReceive(uint8_t *receivedAnswer, uint16_t answer_maxlen, uint8_t
|
||||
void iso14443a_setup(uint8_t fpga_minor_mode);
|
||||
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint16_t data_len, uint8_t *res);
|
||||
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
|
||||
int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, iso14a_polling_parameters_t *polling_parameters);
|
||||
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
||||
int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr,
|
||||
bool anticollision, uint8_t num_cascades, bool no_rats,
|
||||
const iso14a_polling_parameters_t *polling_parameters);
|
||||
int iso14443a_fast_select_card(const uint8_t *uid_ptr, uint8_t num_cascades);
|
||||
void iso14a_set_trigger(bool enable);
|
||||
|
||||
int EmSendCmd14443aRaw(const uint8_t *resp, uint16_t respLen);
|
||||
@@ -181,8 +184,9 @@ int EmSendPrecompiledCmd(tag_response_info_t *p_response);
|
||||
bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *max_buffer_size);
|
||||
bool prepare_tag_modulation(tag_response_info_t *response_info, size_t max_buffer_size);
|
||||
|
||||
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
|
||||
uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity);
|
||||
bool EmLogTrace(const uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime,
|
||||
uint32_t reader_EndTime, const uint8_t *reader_Parity, const uint8_t *tag_data,
|
||||
uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, const uint8_t *tag_Parity);
|
||||
|
||||
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype);
|
||||
void DetectNACKbug(void);
|
||||
|
||||
+3
-3
@@ -344,7 +344,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain, sizeof(key));
|
||||
|
||||
if (!mifare_ultra_auth(key)) {
|
||||
if (mifare_ultra_auth(key) == 0) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
@@ -1947,7 +1947,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||
// Now append the SPI flash dictionnary
|
||||
if (SPIFFS_OK == rdv40_spiffs_read_as_filetype(MF_KEYS_FILE, dictkeys + (keyCount * MF_KEY_LENGTH), (key_mem_available - keyCount) * MF_KEY_LENGTH, RDV40_SPIFFS_SAFETY_SAFE)) {
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("loaded " _GREEN_("%u") " keys from spiffs file `" _YELLOW_("%s") "`", key_mem_available, MF_KEYS_FILE);
|
||||
Dbprintf("loaded " _GREEN_("%u") " keys from spiffs file `" _YELLOW_("%s") "`", key_mem_available - keyCount, MF_KEYS_FILE);
|
||||
}
|
||||
} else {
|
||||
Dbprintf("Spiffs file `" _RED_("%s") "` cannot be read", MF_KEYS_FILE);
|
||||
@@ -3561,7 +3561,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
|
||||
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);
|
||||
|
||||
if (doReselect) {
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ bool InitDesfireCard(void) {
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
|
||||
if (iso14443a_select_card(NULL, &card, NULL, true, 0, false) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) DbpString("Can't select card");
|
||||
OnError(1);
|
||||
return false;
|
||||
@@ -157,7 +157,7 @@ void MifareDesfireGetInformation(void) {
|
||||
pcb_blocknum = 0;
|
||||
|
||||
// card select - information
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
|
||||
if (iso14443a_select_card(NULL, &card, NULL, true, 0, false) == 0) {
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
DbpString("Can't select card");
|
||||
}
|
||||
|
||||
+17
-11
@@ -103,10 +103,13 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||
|
||||
nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
||||
|
||||
bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK;
|
||||
bool is_cmd_check = ((nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK);
|
||||
|
||||
if (is_cmd_check && break_on_nr_mac) {
|
||||
|
||||
memcpy(response, nfc_tx_buf, nfc_tx_len);
|
||||
*response_len = nfc_tx_len;
|
||||
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
DbpString("NR-MAC: ");
|
||||
Dbhexdump((*response_len) - 1, response + 1, false);
|
||||
@@ -115,7 +118,8 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||
goto out;
|
||||
}
|
||||
|
||||
bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE;
|
||||
bool is_cmd_update = ((nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE);
|
||||
|
||||
if (is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02) {
|
||||
// block update(2) command and fake the response to prevent update of epurse
|
||||
|
||||
@@ -223,13 +227,13 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re
|
||||
// 07
|
||||
// 90 00
|
||||
if (request_len == 0) {
|
||||
if (
|
||||
!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03)
|
||||
&&
|
||||
!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0)
|
||||
) {
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
|
||||
if (!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03) &&
|
||||
!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0)) {
|
||||
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("No PACS data in SAM response");
|
||||
}
|
||||
res = PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
@@ -361,14 +365,14 @@ int sam_picopass_get_pacs(PacketCommandNG *c) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!skipDetect) {
|
||||
if (skipDetect == false) {
|
||||
// step 2: get card information
|
||||
picopass_hdr_t card_a_info;
|
||||
uint32_t eof_time = 0;
|
||||
|
||||
// implicit StartSspClk() happens here
|
||||
Iso15693InitReader();
|
||||
if (!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)) {
|
||||
if (select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod) == false) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -383,8 +387,10 @@ int sam_picopass_get_pacs(PacketCommandNG *c) {
|
||||
if (res != PM3_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (g_dbglevel >= DBG_INFO)
|
||||
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
print_result("Response data", sam_response, sam_response_len);
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -177,14 +177,15 @@ crack_states_thread(void *x) {
|
||||
|
||||
char progress_text[80];
|
||||
char keystr[19];
|
||||
snprintf(keystr, sizeof(keystr), "%012" PRIX64 " ", key);
|
||||
snprintf(keystr, sizeof(keystr), "%012" PRIX64, key);
|
||||
snprintf(progress_text, sizeof(progress_text), "Brute force phase completed. Key found: " _GREEN_("%s"), keystr);
|
||||
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
|
||||
PrintAndLogEx(INFO, "---------+---------+---------------------------------------------------------+-----------------+-------");
|
||||
break;
|
||||
} else if (keys_found) {
|
||||
break;
|
||||
} else {
|
||||
if (!thread_arg->silent) {
|
||||
if (thread_arg->silent == false) {
|
||||
char progress_text[80];
|
||||
snprintf(progress_text, sizeof(progress_text), "Brute force phase: %6.02f%% ", 100.0 * (float)num_keys_tested / (float)(thread_arg->maximum_states));
|
||||
float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float)num_keys_tested / 2;
|
||||
@@ -337,7 +338,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
|
||||
bucket_count = 0;
|
||||
for (statelist_t *p = candidates; p != NULL; p = p->next) {
|
||||
if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) {
|
||||
if (!ensure_buckets_alloc(bucket_count + 1)) {
|
||||
if (ensure_buckets_alloc(bucket_count + 1) == false) {
|
||||
PrintAndLogEx(ERR, "Can't allocate buckets, abort!");
|
||||
return false;
|
||||
}
|
||||
@@ -375,6 +376,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
|
||||
thread_args[i].best_first_bytes = best_first_bytes;
|
||||
pthread_create(&threads[i], NULL, crack_states_thread, (void *)&thread_args[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_brute_force_threads; i++) {
|
||||
pthread_join(threads[i], 0);
|
||||
}
|
||||
@@ -385,11 +387,13 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
|
||||
|
||||
uint64_t elapsed_time = msclock() - start_time;
|
||||
|
||||
if (bf_rate != NULL)
|
||||
if (bf_rate != NULL) {
|
||||
*bf_rate = (float)num_keys_tested / ((float)elapsed_time / 1000.0);
|
||||
}
|
||||
|
||||
if (keys_found > 0)
|
||||
if (keys_found > 0) {
|
||||
*found_key = found_bs_key;
|
||||
}
|
||||
|
||||
return (keys_found != 0);
|
||||
}
|
||||
|
||||
@@ -584,8 +584,6 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False,
|
||||
if "Found keys have been dumped to" in line:
|
||||
keyfile = line[line.index("`"):].strip("`")
|
||||
else:
|
||||
show()
|
||||
show(color("found keys:", fg="green"), prompt=plus)
|
||||
show(prompt=plus)
|
||||
show("-----+-----+--------------+---+--------------+----", prompt=plus)
|
||||
show(" Sec | Blk | key A |res| key B |res", prompt=plus)
|
||||
|
||||
+65
-17
@@ -192,21 +192,24 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "mem load",
|
||||
"Loads binary file into flash memory on device\n"
|
||||
"Warning: mem area to be written must have been wiped first\n"
|
||||
"( dictionaries are serviced as files in spiffs so no wipe is needed )",
|
||||
"mem load -f myfile -> upload file myfile values at default offset 0\n"
|
||||
"mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n"
|
||||
"mem load -f mfc_default_keys -m -> upload MFC keys\n"
|
||||
"mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n"
|
||||
"mem load -f iclass_default_keys -i -> upload iCLASS keys\n"
|
||||
"Warning! - mem area to be written must have been wiped first\n\n"
|
||||
"OBS! - dictionaries are serviced as files in spiffs so no wipe is needed",
|
||||
"mem load -f myfile -> upload file myfile values at default offset 0\n"
|
||||
"mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n"
|
||||
"mem load -f mfc_default_keys -m -> upload MIFARE Classic keys\n"
|
||||
"mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n"
|
||||
"mem load -f iclass_default_keys -i -> upload iCLASS keys\n"
|
||||
"mem load -f mfulc_default_keys --ulc -> upload MIFARE UL-C keys\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0("o", "offset", "<dec>", "offset in memory"),
|
||||
arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"),
|
||||
arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"),
|
||||
arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"),
|
||||
arg_lit0("m", "mfc", "upload 6 bytes keys (MIFARE Classic dictionary)"),
|
||||
arg_lit0("i", "iclass", "upload 8 bytes keys (iClass dictionary)"),
|
||||
arg_lit0("t", "t55xx", "upload 4 bytes keys (T55xx dictionary)"),
|
||||
arg_lit0(NULL, "ulc", "upload 16 bytes keys (MIFARE UL-C dictionary)"),
|
||||
arg_lit0(NULL, "aes", "upload 16 bytes keys (MIFARE UL-AES dictionary)"),
|
||||
arg_str1("f", "file", "<fn>", "file name"),
|
||||
arg_param_end
|
||||
};
|
||||
@@ -216,28 +219,35 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
||||
bool is_mfc = arg_get_lit(ctx, 2);
|
||||
bool is_iclass = arg_get_lit(ctx, 3);
|
||||
bool is_t55xx = arg_get_lit(ctx, 4);
|
||||
bool is_ulc = arg_get_lit(ctx, 5);
|
||||
bool is_ulaes = arg_get_lit(ctx, 6);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char spiffsDest[32] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
Dictionary_t d = DICTIONARY_NONE;
|
||||
if (is_mfc) {
|
||||
d = DICTIONARY_MIFARE;
|
||||
PrintAndLogEx(INFO, "treating file as MIFARE Classic keys");
|
||||
PrintAndLogEx(INFO, "Treating file as MIFARE Classic keys");
|
||||
} else if (is_iclass) {
|
||||
d = DICTIONARY_ICLASS;
|
||||
PrintAndLogEx(INFO, "treating file as iCLASS keys");
|
||||
PrintAndLogEx(INFO, "Treating file as iCLASS keys");
|
||||
} else if (is_t55xx) {
|
||||
d = DICTIONARY_T55XX;
|
||||
PrintAndLogEx(INFO, "treating file as T55xx passwords");
|
||||
PrintAndLogEx(INFO, "Treating file as T55xx passwords");
|
||||
} else if (is_ulc) {
|
||||
d = DICTIONARY_MIFARE_ULC;
|
||||
PrintAndLogEx(INFO, "Treating file as MIFARE Ultralight-C keys");
|
||||
} else if (is_ulaes) {
|
||||
d = DICTIONARY_MIFARE_ULAES;
|
||||
PrintAndLogEx(INFO, "Treating file as MIFARE Ultralight AES keys");
|
||||
}
|
||||
|
||||
uint8_t spi_flash_pages = 0;
|
||||
int res = rdv4_get_flash_pages64k(&spi_flash_pages);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to get flash pages count (%x)", res);
|
||||
PrintAndLogEx(ERR, "Failed to get flash pages count (%x)", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -246,6 +256,8 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
||||
uint8_t keylen = 0;
|
||||
uint8_t *data = calloc(FLASH_MEM_MAX_SIZE_P(spi_flash_pages), sizeof(uint8_t));
|
||||
|
||||
char spiffsDest[32] = {0};
|
||||
|
||||
switch (d) {
|
||||
case DICTIONARY_MIFARE: {
|
||||
keylen = MF_KEY_LENGTH;
|
||||
@@ -292,6 +304,36 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
||||
strcpy(spiffsDest, ICLASS_KEYS_FILE);
|
||||
break;
|
||||
}
|
||||
case DICTIONARY_MIFARE_ULC: {
|
||||
keylen = MFULC_KEY_LENGTH;
|
||||
res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount);
|
||||
if (res || !keycount) {
|
||||
free(data);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) {
|
||||
PrintAndLogEx(ERR, "error, filesize is larger than available memory");
|
||||
free(data);
|
||||
return PM3_EOVFLOW;
|
||||
}
|
||||
strcpy(spiffsDest, MFULC_KEYS_FILE);
|
||||
break;
|
||||
}
|
||||
case DICTIONARY_MIFARE_ULAES: {
|
||||
keylen = MFULAES_KEY_LENGTH;
|
||||
res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount);
|
||||
if (res || !keycount) {
|
||||
free(data);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) {
|
||||
PrintAndLogEx(ERR, "error, filesize is larger than available memory");
|
||||
free(data);
|
||||
return PM3_EOVFLOW;
|
||||
}
|
||||
strcpy(spiffsDest, MFULAES_KEYS_FILE);
|
||||
break;
|
||||
}
|
||||
case DICTIONARY_NONE: {
|
||||
res = loadFile_safe(filename, ".bin", (void **)&data, &datalen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
@@ -330,7 +372,12 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
||||
free(data);
|
||||
return res;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" passwords to file "_GREEN_("%s"), keycount, spiffsDest);
|
||||
|
||||
if (d == DICTIONARY_T55XX) {
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" passwords to file "_GREEN_("%s"), keycount, spiffsDest);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" keys to file "_GREEN_("%s"), keycount, spiffsDest);
|
||||
}
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
|
||||
} else {
|
||||
@@ -729,6 +776,7 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
||||
static command_t CommandTable[] = {
|
||||
{"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "{ SPI File system }"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"-----------", CmdHelp, IfPm3Flash, "------------------- " _CYAN_("Operations") " -------------------"},
|
||||
{"baudrate", CmdFlashmemSpiBaud, IfPm3Flash, "Set Flash memory Spi baudrate"},
|
||||
{"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"},
|
||||
{"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"},
|
||||
|
||||
@@ -26,7 +26,9 @@ typedef enum {
|
||||
DICTIONARY_NONE = 0,
|
||||
DICTIONARY_MIFARE,
|
||||
DICTIONARY_T55XX,
|
||||
DICTIONARY_ICLASS
|
||||
DICTIONARY_ICLASS,
|
||||
DICTIONARY_MIFARE_ULC,
|
||||
DICTIONARY_MIFARE_ULAES,
|
||||
} Dictionary_t;
|
||||
|
||||
int CmdFlashMem(const char *Cmd);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user