Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Alex 2023-07-03 14:45:52 +02:00 committed by GitHub
commit 9a1f0356a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 1953 additions and 1419 deletions

View file

@ -3,6 +3,20 @@ 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]
## [Seven.4.16717][2023-06-25]
- Change `hf 14a info` - now identifes QL88 tags (@iceman1001)
- Added support for compiling on iOS (@The-SamminAter)
- Fixed viewing MFC dump - border char is now white (@iceman1001)
- Changed `data diff` - to print filenames in header if it fits (@iceman1001)
- Changed viewing MFC dump files - it now colors ACL + GPB bytes (@iceman1001)
- Added `hf mf supercard --furui` - now supports key recovery from Furui detection card. Thanks foxushka! (@iceman1001)
- Added `hf topaz dump --ns` - now supports nosave param (@iceman1001)
- Changed `hf topaz rdbl` - unified output (@iceman1001)
- Fixed `hf topaz wrbl` - now supports tear off and write_nonerase command (@iceman1001)
- Fixed `hf mf` commands (@iceman1001)
- Fixed `hf mfp` commands (@iceman1001)
- Added more default keys (@iceman1001) Thanks anon!
- Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001) - Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001)
- Fixed `hf 15693/iclass sniff` trace timings (@nvx) - Fixed `hf 15693/iclass sniff` trace timings (@nvx)
- Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp) - Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp)

View file

@ -75,7 +75,15 @@ else
endif endif
ifeq ($(platform),Darwin) ifeq ($(platform),Darwin)
ifeq ($(shell uname -p),arm64)
# The platform is iOS
USE_BREW ?= 0
# iOS refuses to compile unless this is set
export IPHONEOS_DEPLOYMENT_TARGET=11.0
else
# M* macOS devices return arm
USE_BREW ?= 1 USE_BREW ?= 1
endif
USE_MACPORTS ?= 0 USE_MACPORTS ?= 0
AR= /usr/bin/ar rcs AR= /usr/bin/ar rcs
RANLIB= /usr/bin/ranlib RANLIB= /usr/bin/ranlib
@ -132,6 +140,10 @@ ifeq ($(shell expr $(CC_VERSION) \>= 10), 1)
endif endif
endif endif
ifeq ($(platform),Darwin) ifeq ($(platform),Darwin)
ifeq ($(shell uname -p),arm64)
# iOS will refuse to compile without the minimum target of iOS 11.0
DEFCFLAGS += -mios-version-min=11.0
endif
# their readline has strict-prototype issues # their readline has strict-prototype issues
DEFCFLAGS += -Wno-strict-prototypes DEFCFLAGS += -Wno-strict-prototypes
# some warnings about braced initializers on structs we want to ignore # some warnings about braced initializers on structs we want to ignore

View file

@ -1,4 +1,4 @@
# Iceman Fork - Proxmark3 a RFID / NFC project. # Iceman Fork - Proxmark3
The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the vast majority of RFID tags on a global scale. Originally built by Jonathan Westhues, the device is now the goto tool for RFID Analysis for the enthusiast. Iceman repository is considered to be the pinnacle of features and functionality, enabling a huge range of extremely useful and convenient commands and LUA scripts to automate chip identification, penetration testing, and programming The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the vast majority of RFID tags on a global scale. Originally built by Jonathan Westhues, the device is now the goto tool for RFID Analysis for the enthusiast. Iceman repository is considered to be the pinnacle of features and functionality, enabling a huge range of extremely useful and convenient commands and LUA scripts to automate chip identification, penetration testing, and programming

View file

@ -3094,6 +3094,9 @@ void ReaderIso14443a(PacketCommandNG *c) {
} }
} }
if ((param & ISO14A_TOPAZMODE)) {
if (cmd[0] == TOPAZ_WRITE_E8 || cmd[0] == TOPAZ_WRITE_NE8) {
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing(); FpgaDisableTracing();
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
@ -3102,6 +3105,23 @@ void ReaderIso14443a(PacketCommandNG *c) {
FpgaDisableTracing(); FpgaDisableTracing();
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
} }
} else {
arg0 = ReaderReceive(buf, par);
FpgaDisableTracing();
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
}
} else {
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing();
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
} else {
arg0 = ReaderReceive(buf, par);
FpgaDisableTracing();
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
}
}
} }
if ((param & ISO14A_REQUEST_TRIGGER)) if ((param & ISO14A_REQUEST_TRIGGER))

View file

@ -1835,6 +1835,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
switch_off(); switch_off();
DbpString(""); DbpString("");
if (g_dbglevel > DBG_ERROR) {
DbpString(_CYAN_("Sniff statistics")); DbpString(_CYAN_("Sniff statistics"));
DbpString("================================="); DbpString("=================================");
Dbprintf("DecodeTag State........ %d", dtag.state); Dbprintf("DecodeTag State........ %d", dtag.state);
@ -1846,9 +1847,8 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
Dbprintf("DecodeReader State..... %d", dreader.state); Dbprintf("DecodeReader State..... %d", dreader.state);
Dbprintf("DecodeReader byteCnt... %d", dreader.byteCount); Dbprintf("DecodeReader byteCnt... %d", dreader.byteCount);
Dbprintf("DecodeReader posCount.. %d", dreader.posCount); Dbprintf("DecodeReader posCount.. %d", dreader.posCount);
}
Dbprintf("Trace length........... " _YELLOW_("%d"), BigBuf_get_traceLen()); Dbprintf("Trace length........... " _YELLOW_("%d"), BigBuf_get_traceLen());
DbpString("");
} }
// Initialize Proxmark3 as ISO15693 reader // Initialize Proxmark3 as ISO15693 reader

View file

@ -484,8 +484,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
if (res == PM3_ETEAROFF) { if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF; retval = PM3_ETEAROFF;
goto OUT; goto OUT;
} else if (res) { } else if (res != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
retval = PM3_ESOFT; retval = PM3_ESOFT;
goto OUT; goto OUT;
} }
@ -554,7 +554,7 @@ void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t
if (res == PM3_ETEAROFF) { if (res == PM3_ETEAROFF) {
retval = PM3_ETEAROFF; retval = PM3_ETEAROFF;
goto OUT; goto OUT;
} else if (res) { } else if (res != PM3_SUCCESS) {
retval = PM3_ESOFT; retval = PM3_ESOFT;
goto OUT; goto OUT;
} }
@ -688,8 +688,8 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
break; break;
}; };
if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action)) { if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
break; break;
}; };
@ -777,8 +777,8 @@ static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, boo
} }
} }
if (mifare_ultra_writeblock(blockNo, blockdata)) { if (mifare_ultra_writeblock(blockNo, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(0); OnError(0);
return; return;
}; };
@ -851,8 +851,8 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
} }
} }
if (mifare_ultra_writeblock_compat(blockNo, blockdata)) { if (mifare_ultra_writeblock_compat(blockNo, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(0); OnError(0);
return; return;
}; };
@ -896,8 +896,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[1] = pwd[6]; blockdata[1] = pwd[6];
blockdata[2] = pwd[5]; blockdata[2] = pwd[5];
blockdata[3] = pwd[4]; blockdata[3] = pwd[4];
if (mifare_ultra_writeblock(44, blockdata)) { if (mifare_ultra_writeblock(44, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(44); OnError(44);
return; return;
}; };
@ -906,8 +906,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[1] = pwd[2]; blockdata[1] = pwd[2];
blockdata[2] = pwd[1]; blockdata[2] = pwd[1];
blockdata[3] = pwd[0]; blockdata[3] = pwd[0];
if (mifare_ultra_writeblock(45, blockdata)) { if (mifare_ultra_writeblock(45, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(45); OnError(45);
return; return;
}; };
@ -916,8 +916,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[1] = pwd[14]; blockdata[1] = pwd[14];
blockdata[2] = pwd[13]; blockdata[2] = pwd[13];
blockdata[3] = pwd[12]; blockdata[3] = pwd[12];
if (mifare_ultra_writeblock(46, blockdata)) { if (mifare_ultra_writeblock(46, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(46); OnError(46);
return; return;
}; };
@ -926,8 +926,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[1] = pwd[10]; blockdata[1] = pwd[10];
blockdata[2] = pwd[9]; blockdata[2] = pwd[9];
blockdata[3] = pwd[8]; blockdata[3] = pwd[8];
if (mifare_ultra_writeblock(47, blockdata)) { if (mifare_ultra_writeblock(47, blockdata) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
OnError(47); OnError(47);
return; return;
}; };
@ -1522,7 +1522,6 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
target_ks[0] = nt2 ^ target_nt[0]; target_ks[0] = nt2 ^ target_nt[0];
// second collection // second collection
if (mifare_classic_halt(pcs, cuid)) { if (mifare_classic_halt(pcs, cuid)) {
continue; continue;
} }
@ -2303,74 +2302,105 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype) {
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// variables
uint8_t dataoutbuf[16] = {0x00};
uint8_t dataoutbuf2[16] = {0x00};
uint8_t uid[10] = {0x00};
LED_A_ON(); LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace(); clear_trace();
set_tracing(true); set_tracing(true);
// variables
bool have_uid = false;
uint8_t cascade_levels = 0;
uint32_t cuid = 0;
uint8_t uid[10] = {0x00};
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { for (uint8_t s = 0; s < sectorcnt; s++) {
retval = PM3_ESOFT; uint64_t ui64Key = emlGetKey(s, keytype);
if (g_dbglevel > DBG_ERROR) Dbprintf("Can't select card");
goto out;
}
for (uint8_t sectorNo = 0; sectorNo < sectorcnt; sectorNo++) { // MFC 1K EV1 sector 16,17 don't use key A.
uint64_t ui64Key = emlGetKey(sectorNo, keytype); if ((sectorcnt == 18) && (keytype == 0) && s > 15) {
if (sectorNo == 0) {
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) {
retval = PM3_EPARTIAL;
if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo);
continue; continue;
} }
// use fast select
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) == 0) {
continue;
}
switch (card_info.uidlen) {
case 4 :
cascade_levels = 1;
break;
case 7 :
cascade_levels = 2;
break;
case 10:
cascade_levels = 3;
break;
default:
break;
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
continue;
}
}
// Auth
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(s), keytype, ui64Key, AUTH_FIRST)) {
retval = PM3_EPARTIAL;
if (g_dbglevel > DBG_ERROR) {
Dbprintf("Sector %2d - Auth error", s);
}
continue;
}
#define MAX_RETRIES 2
uint8_t data[16] = {0x00};
for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
memset(data, 0x00, sizeof(data));
for (uint8_t r = 0; r < MAX_RETRIES; r++) {
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(s) + b, data)) {
retval |= PM3_EPARTIAL;
if (g_dbglevel > DBG_ERROR) {
Dbprintf("Error reading sector %2d block %2d", s, b);
}
continue;
}
// No need to copy empty
if (memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
continue;
}
if (b < NumBlocksPerSector(s) - 1) {
emlSetMem(data, FirstBlockOfSector(s) + b, 1);
} else { } else {
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) { // sector trailer, keep the keys, set only the AC
retval = PM3_EPARTIAL; uint8_t st[16] = {0x00};
if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); emlGetMem(st, FirstBlockOfSector(s) + b, 1);
continue; memcpy(st + 6, data + 6, 4);
emlSetMem(st, FirstBlockOfSector(s) + b, 1);
} }
} }
for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
retval = PM3_EPARTIAL;
if (g_dbglevel > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
continue;
}
if (memcmp(dataoutbuf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
continue;
}
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
} else { // sector trailer, keep the keys, set only the AC
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
memcpy(dataoutbuf2 + 6, dataoutbuf + 6, 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
}
} }
} }
int res = mifare_classic_halt(pcs, cuid); int res = mifare_classic_halt(pcs, cuid);
(void)res; (void)res;
if (g_dbglevel >= DBG_INFO) DbpString("Emulator fill sectors finished");
out:
crypto1_deinit(pcs); crypto1_deinit(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
@ -2601,6 +2631,7 @@ void MifareCIdent(bool is_mfc) {
uint8_t gen4gmd[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92}; uint8_t gen4gmd[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0}; uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D}; uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
uint8_t *uid = BigBuf_malloc(10); uint8_t *uid = BigBuf_malloc(10);
@ -2757,7 +2788,24 @@ void MifareCIdent(bool is_mfc) {
isGen = MAGIC_GEN_4GDM; isGen = MAGIC_GEN_4GDM;
} }
} }
if (isGen != MAGIC_GEN_4GDM) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(40);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if (res == 2) {
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
isGen = MAGIC_QL88;
} }
crypto1_deinit(pcs);
}
}
}
} }
}; };
@ -2836,6 +2884,10 @@ OUT:
crypto1_deinit(pcs); crypto1_deinit(pcs);
} }
// FUDAN card w static encrypted nonces
// 2B F9 1C 1B D5 08 48 48 03 A4 B1 B1 75 FF 2D 90
// ^^ ^^
void OnSuccessMagic(void) { void OnSuccessMagic(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
@ -3218,7 +3270,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain) {
return; return;
}; };
if (mifare_desfire_des_auth1(cuid, dataout)) { if (mifare_desfire_des_auth1(cuid, dataout) != PM3_SUCCESS) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication part1: Fail."); if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication part1: Fail.");
OnError(4); OnError(4);
return; return;
@ -3238,7 +3290,7 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
isOK = mifare_desfire_des_auth2(cuid, key, dataout); isOK = mifare_desfire_des_auth2(cuid, key, dataout);
if (isOK) { if (isOK != PM3_SUCCESS) {
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication part2: Failed");
OnError(4); OnError(4);
return; return;

View file

@ -46,6 +46,15 @@
#include "dbprint.h" #include "dbprint.h"
#include "ticks.h" #include "ticks.h"
static bool IsKeyBReadable(uint8_t blockNo) {
uint8_t sector_trailer[16];
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
| ((sector_trailer[8] >> 2) & 0x02)
| ((sector_trailer[8] >> 7) & 0x01);
return (AC == 0x00 || AC == 0x01 || AC == 0x02);
}
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
uint8_t sector_trailer[16]; uint8_t sector_trailer[16];
emlGetMem(sector_trailer, blockNo, 1); emlGetMem(sector_trailer, blockNo, 1);
@ -872,8 +881,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
break; break;
} }
*/ */
blockNo = receivedCmd_dec[1];
if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { if (MifareBlockToSector(blockNo) != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing(); FpgaDisableTracing();
@ -881,6 +890,18 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC);
break; break;
} }
// Compliance of MIFARE Classic EV1 1K Datasheet footnote of Table 8
// If access bits show that key B is Readable, any subsequent memory access will be refused.
if (cardAUTHKEY == AUTHKEYB && IsKeyBReadable(blockNo)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
if (g_dbglevel >= DBG_ERROR)
Dbprintf("[MFEMUL_WORK] Access denied: Reader tried to access memory on authentication with key B while key B is readable in sector (0x%02x)", cardAUTHSC);
break;
}
} }
// case MFEMUL_WORK => CMD READ block // case MFEMUL_WORK => CMD READ block

View file

@ -433,8 +433,8 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
} }
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1; return PM3_EFAILED;
} }
uint8_t d_block[18], d_block_enc[18]; uint8_t d_block[18], d_block_enc[18];
@ -465,11 +465,11 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) { if ((len != 1) || (res != 0x0A)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
return 2; return PM3_EFAILED;
} }
} }
return 0; return PM3_SUCCESS;
} }
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) { int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) {
@ -480,7 +480,7 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u
uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL); uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { if ((len != 1) || (receivedAnswer[0] != 0x0A)) {
return 1; return PM3_EFAILED;
} }
uint8_t d_block[18], d_block_enc[18]; uint8_t d_block[18], d_block_enc[18];
@ -511,14 +511,12 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) { if ((len != 1) || (res != 0x0A)) {
return 2; return PM3_EFAILED;
} }
} }
return 0; return PM3_SUCCESS;
} }
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) { int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
// variables // variables
uint16_t len = 0; uint16_t len = 0;
@ -540,8 +538,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1; return PM3_EFAILED;
} }
memcpy(d_block, blockData, 4); memcpy(d_block, blockData, 4);
@ -566,12 +564,12 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
if ((len != 1) || (res != 0x0A)) { if ((len != 1) || (res != 0x0A)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
return 2; return PM3_EFAILED;
} }
} }
return 0; return PM3_SUCCESS;
} }
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
@ -585,9 +583,10 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
return 1; }
return PM3_EFAILED;
} }
memcpy(d_block, blockData, 16); memcpy(d_block, blockData, 16);
@ -599,11 +598,12 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
len = ReaderReceive(receivedAnswer, receivedAnswerPar); len = ReaderReceive(receivedAnswer, receivedAnswerPar);
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len); Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len);
return 2;
} }
return 0; return PM3_EFAILED;
}
return PM3_SUCCESS;
} }
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) { int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
@ -618,11 +618,12 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL);
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
return 1;
} }
return 0; return PM3_EFAILED;
}
return PM3_SUCCESS;
} }
int mifare_classic_halt_ex(struct Crypto1State *pcs) { int mifare_classic_halt_ex(struct Crypto1State *pcs) {
uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00};
@ -729,8 +730,8 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) {
uint64_t emlGetKey(int sectorNum, int keyType) { uint64_t emlGetKey(int sectorNum, int keyType) {
uint8_t key[6] = {0x00}; uint8_t key[6] = {0x00};
uint8_t *emCARD = BigBuf_get_EM_addr(); uint8_t *em = BigBuf_get_EM_addr();
memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); memcpy(key, em + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
return bytes_to_num(key, 6); return bytes_to_num(key, 6);
} }
@ -804,9 +805,10 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) { if (len == 1) {
if (g_dbglevel >= DBG_ERROR) if (g_dbglevel >= DBG_INFO) {
Dbprintf("Cmd Error: %02x", receivedAnswer[0]); Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1; }
return PM3_EFAILED;
} }
if (len == 12) { if (len == 12) {
@ -817,9 +819,9 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
receivedAnswer[10], receivedAnswer[11]); receivedAnswer[10], receivedAnswer[11]);
} }
memcpy(blockData, receivedAnswer, 12); memcpy(blockData, receivedAnswer, 12);
return 0; return PM3_SUCCESS;
} }
return 1; return PM3_EFAILED;
} }
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) { int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
@ -834,9 +836,10 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL);
if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) {
if (g_dbglevel >= DBG_ERROR) if (g_dbglevel >= DBG_ERROR) {
Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]);
return 1; }
return PM3_EFAILED;
} }
if (len == 12) { if (len == 12) {
@ -847,7 +850,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
receivedAnswer[10], receivedAnswer[11]); receivedAnswer[10], receivedAnswer[11]);
} }
memcpy(blockData, receivedAnswer, 12); memcpy(blockData, receivedAnswer, 12);
return 0; return PM3_SUCCESS;
} }
return 1; return PM3_EFAILED;
} }

View file

@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
if (APPLE) if (APPLE)
message(STATUS "Apple device detected.") message(STATUS "Apple device detected.")
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC}) set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
find_library(UIKIT_LIBRARY UIKit)
if (NOT UIKIT_LIBRARY)
message(STATUS "UIKit.framework NOT found!")
else()
message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}")
set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit")
endif()
find_library(APPKIT_LIBRARY AppKit)
if (NOT APPKIT_LIBRARY)
message(STATUS "AppKit.framework NOT found!")
else()
message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}")
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
endif()
endif (APPLE) endif (APPLE)
if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND)) if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND))

View file

@ -434,8 +434,14 @@ LDFLAGS += $(MYLDFLAGS)
PM3LDFLAGS = $(LDFLAGS) PM3LDFLAGS = $(LDFLAGS)
ifeq ($(platform),Darwin) ifeq ($(platform),Darwin)
ifeq ($(shell uname -p),arm64)
# The platform is iOS
PM3LDFLAGS += -framework Foundation -framework UIKit
else
# M* macOS devices return arm
PM3LDFLAGS += -framework Foundation -framework AppKit PM3LDFLAGS += -framework Foundation -framework AppKit
endif endif
endif
################### ###################
# printing status # # printing status #

View file

@ -22,6 +22,9 @@ endif
ifneq ($(findstring aarch64, $(cpu_arch)), ) ifneq ($(findstring aarch64, $(cpu_arch)), )
IS_SIMD_ARCH=arm64 IS_SIMD_ARCH=arm64
endif endif
ifneq ($(findstring iP, $(cpu_arch)), )
IS_SIMD_ARCH=arm64
endif
ifneq ($(IS_SIMD_ARCH), ) ifneq ($(IS_SIMD_ARCH), )
MULTIARCHSRCS = hardnested_bf_core.c hardnested_bitarray_core.c MULTIARCHSRCS = hardnested_bf_core.c hardnested_bitarray_core.c

View file

@ -31,6 +31,11 @@ D01AFEEB890A
# 17 B # 17 B
4B791BEA7BCC 4B791BEA7BCC
# #
# QL88 keys
# 17 A/B
2612C6DE84CA
707B11FC1481
#
# #
B0B1B2B3B4B5 B0B1B2B3B4B5
C0C1C2C3C4C5 C0C1C2C3C4C5
@ -145,6 +150,9 @@ F1D83F964314
222222222222 222222222222
27DD91F1FCF1 27DD91F1FCF1
# #
# Hotel system
505209016A1F
#
# Directory and eventlog KeyB # Directory and eventlog KeyB
2BA9621E0A36 2BA9621E0A36
# #

View file

@ -37,7 +37,7 @@ A5B4C3D2
E9920427 E9920427
# paxton bullit? # paxton bullit?
575F4F4B 575F4F4B
# # Hotel system
50520901 50520901
# iCopy-X # iCopy-X
20206666 20206666
@ -52,6 +52,8 @@ C0F5009A
# prefered pwds of members in the community # prefered pwds of members in the community
FEEDBEEF FEEDBEEF
DEADC0DE DEADC0DE
# derived from BCARD key B
A9EF2AFC
# Default pwd, simple: # Default pwd, simple:
00000000 00000000
11111111 11111111

View file

@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
if (APPLE) if (APPLE)
message(STATUS "Apple device detected.") message(STATUS "Apple device detected.")
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC}) set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
find_library(UIKIT_LIBRARY UIKit)
if (NOT UIKIT_LIBRARY)
message(STATUS "UIKit.framework NOT found!")
else()
message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}")
set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit")
endif()
find_library(APPKIT_LIBRARY AppKit)
if (NOT APPKIT_LIBRARY)
message(STATUS "AppKit.framework NOT found!")
else()
message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}")
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
endif()
endif (APPLE) endif (APPLE)
if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND)) if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND))

View file

@ -62,21 +62,19 @@ def build_arg_parser():
def build_help_regex(): def build_help_regex():
"""The regex uses to parse the full text output of help data from the pm3 client."""
# Reads the divider followed by the command itself
re_command = r'-{87}\n(?P<command>.+)\n' re_command = r'-{87}\n(?P<command>.+)\n'
# Reads if the command is available offline # Reads if the command is available offline
re_offline = r'available offline: (?P<offline>yes|no)\n+' re_offline = r'available offline: (?P<offline>yes|no)\n+'
# Reads the description lines # Reads the description lines
re_description = r'(?P<description>(?:.+\n)+)\n+' re_description = r'(?P<description>\n[\s\S]*?(?=usage:))'
# Reads the usage string # Reads the usage string
re_usage = r'(?:usage:\n(?P<usage>(?:.+\n)+)\n+)?' re_usage = r'(?:usage:\n(?P<usage>(?:.+\n)+)\n+)?'
# Reads the options and there individual descriptions # Reads the options and there individual descriptions
re_options = r'(?:options:\n(?P<options>(?:.+\n)+)\n+)?' re_options = r'(?:options:\n(?P<options>(?:.+\n)+)\n+)?'
# Reads the notes and examples # Reads the notes and examples
re_notes = r'(?:examples\/notes:\n(?P<notes>(?:.+\n)+)\n+)?' re_notes = r'(?:examples\/notes:\n(?P<notes>[\s\S]*?(?=(===|---|\n\n))))'
# Combine them into a single regex object # Combine them into a single regex object
re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE); re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE)
return re_full return re_full

View file

@ -2255,13 +2255,21 @@
"Description": "Student ID cards", "Description": "Student ID cards",
"Type": "identity" "Type": "identity"
}, },
{
"AID": "D2760000254D010200",
"Vendor": "Zentraler Kreditausschuss (ZKA)",
"Country": "Germany",
"Name": "Girocard Jugendschutz",
"Description": "Age verification",
"Type": "identity"
},
{ {
"AID": "A000000809434343444B467631", "AID": "A000000809434343444B467631",
"Vendor": "Car Connectivity Consortium (CCC)", "Vendor": "Car Connectivity Consortium (CCC)",
"Country": "", "Country": "",
"Name": "Digital Car Key Framework", "Name": "Digital Car Key Framework",
"Description": "Used during key provisioning and configuration", "Description": "Used during key provisioning and configuration",
"Type": "access" "Type": ""
}, },
{ {
"AID": "A000000809434343444B417631", "AID": "A000000809434343444B417631",
@ -2295,13 +2303,69 @@
"Description": "AID prefix used by MIFARE 2GO-based cards", "Description": "AID prefix used by MIFARE 2GO-based cards",
"Type": "" "Type": ""
}, },
{
"AID": "A00000039656434103F1216000000000",
"Vendor": "LV Monorail",
"Country": "United States",
"Name": "Las Vegas Monorail",
"Description": "",
"Type": "transport"
},
{
"AID": "A00000039656434103F8852200000000",
"Vendor": "Ubian",
"Country": "Slovakia",
"Name": "Ubian digital transit card",
"Description": "DESFire-based virtual transit card",
"Type": "transport"
},
{
"AID": "DE5C0D1F1CADA5",
"Vendor": "CRTM",
"Country": "Spain",
"Name": "Madrid transit card",
"Description": "DESFire-based transit card",
"Type": "transport"
},
{
"AID": "A00000F21100",
"Vendor": "PTV",
"Country": "Australia",
"Name": "Myki transit card",
"Description": "DESFire-based transit card",
"Type": "transport"
},
{
"AID": "637001ff4c41",
"Vendor": "Cubic",
"Country": "United States",
"Name": "LA Tap",
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffLA)",
"Type": "transport"
},
{
"AID": "637001ff574d415441",
"Vendor": "Cubic",
"Country": "United States",
"Name": "Smart Trip",
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffWMATA)",
"Type": "transport"
},
{
"AID": "637001ff434c4950504552",
"Vendor": "Cubic",
"Country": "United States",
"Name": "Clipper",
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffCLIPPER)",
"Type": "transport"
},
{ {
"AID": "A0000002164954534F2D31", "AID": "A0000002164954534F2D31",
"Vendor": "ITSO", "Vendor": "ITSO",
"Country": "United Kingdom", "Country": "United Kingdom",
"Name": "ITSO CMD2", "Name": "ITSO CMD2",
"Description": "AID used by ITSO for smartcard/phone-based transit cards", "Description": "AID used by ITSO for smartcard/phone-based transit cards",
"Type": "transit" "Type": "transport"
}, },
{ {
"AID": "A000000632010105", "AID": "A000000632010105",
@ -2309,22 +2373,38 @@
"Country": "China", "Country": "China",
"Name": "China T-Union", "Name": "China T-Union",
"Description": "Universal transit card used by many big public transit operators", "Description": "Universal transit card used by many big public transit operators",
"Type": "transit" "Type": "transport"
},
{
"AID": "D2760000254D010200",
"Vendor": "Zentraler Kreditausschuss (ZKA)",
"Country": "Germany",
"Name": "Girocard Jugendschutz",
"Description": "Age verification",
"Type": ""
}, },
{ {
"AID": "A00000000491", "AID": "A00000000491",
"Vendor": "MasterCard International", "Vendor": "MasterCard International",
"Country": "", "Country": "",
"Name": "Mastercard Private Label Transit", "Name": "Mastercard Private Label Transit",
"Description": "AID prefix used by transit cards that use private label mastercards (E.g. Ventra and HOP)", "Description": "AID prefix used by transit cards that use private label mastercard",
"Type": "transit" "Type": "transport"
},
{
"AID": "A0000000049100",
"Vendor": "MasterCard International",
"Country": "United States",
"Name": "HOP Fastpass",
"Description": "",
"Type": "transport"
},
{
"AID": "A0000000049101",
"Vendor": "MasterCard International",
"Country": "United States",
"Name": "Ventra",
"Description": "",
"Type": "transport"
},
{
"AID": "A000000858044F53452E4348",
"Vendor": "Apple",
"Country": "",
"Name": "AirDrop connection negotiation",
"Description": "Used by NFC-based AirDrop negotiation added in IOS17",
"Type": ""
} }
] ]

View file

@ -4073,6 +4073,20 @@
"service_provider": "HID Corporation", "service_provider": "HID Corporation",
"system_integrator": "HID Corporation" "system_integrator": "HID Corporation"
}, },
{
"application": "City transport, prepaid ticket, cardholder, servicespass",
"company": "Ridango AS",
"mad": "0x3C56",
"service_provider": "Pilet.ee ekaart",
"system_integrator": "Pilet.ee ekaart"
},
{
"application": "City transport, prepaid ticket, cardholder, servicespass",
"company": "Ridango AS",
"mad": "0x3D56",
"service_provider": "Pilet.ee ekaart",
"system_integrator": "Pilet.ee ekaart"
},
{ {
"application": "City transport bus, ferry, administration", "application": "City transport bus, ferry, administration",
"company": "VFJ Technology Pty Ltd", "company": "VFJ Technology Pty Ltd",

View file

@ -2939,7 +2939,7 @@ static int CmdDiff(const char *Cmd) {
// "data diff -a fileA --cb\n" // "data diff -a fileA --cb\n"
"data diff --fa fileA -b fileB\n" "data diff --fa fileA -b fileB\n"
"data diff --fa fileA --fb fileB\n" "data diff --fa fileA --fb fileB\n"
"data diff --ea --cb\n" // "data diff --ea --cb\n"
); );
void *argtable[] = { void *argtable[] = {
@ -3083,10 +3083,19 @@ static int CmdDiff(const char *Cmd) {
PrintAndLogEx(INFO, "inB null"); PrintAndLogEx(INFO, "inB null");
int hdr_sln = (width * 4) + 2; int hdr_sln = (width * 4) + 2;
char hdr0[300] = {0};
char hdr0[200] = " # | " _CYAN_("a"); int max_fn_space = (width * 5);
if (fnlenA && fnlenB && (max_fn_space > fnlenA) && (max_fn_space > fnlenB)) {
snprintf(hdr0, sizeof(hdr0) - 1, " # | " _CYAN_("%.*s"), max_fn_space, filenameA);
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - strlen(filenameA) - 1);
snprintf(hdr0 + strlen(hdr0), sizeof(hdr0) - 1 - strlen(hdr0), "| " _CYAN_("%.*s"), max_fn_space, filenameB);
} else {
strcat(hdr0, " # | " _CYAN_("a"));
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2); memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2);
strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b")); strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b"));
}
char hdr1[200] = "----+"; char hdr1[200] = "----+";
memset(hdr1 + strlen(hdr1), '-', hdr_sln); memset(hdr1 + strlen(hdr1), '-', hdr_sln);

View file

@ -2229,33 +2229,35 @@ int infoHF14B(bool verbose, bool do_aid_search) {
// get and print general info about all known 14b chips // get and print general info about all known 14b chips
int readHF14B(bool loop, bool verbose) { int readHF14B(bool loop, bool verbose) {
bool found = false;
do { do {
found = false;
// try std 14b (atqb) // try std 14b (atqb)
if (HF14B_std_reader(verbose)) found |= HF14B_std_reader(verbose);
if (loop) if (found && loop)
continue; continue;
// try ST Microelectronics 14b // try ST Microelectronics 14b
if (HF14B_st_reader(verbose)) found |= HF14B_st_reader(verbose);
if (loop) if (found && loop)
continue; continue;
// try ASK CT 14b // try ASK CT 14b
if (HF14B_ask_ct_reader(verbose)) found |= HF14B_ask_ct_reader(verbose);
if (loop) if (found && loop)
continue; continue;
// try unknown 14b read commands (to be identified later) // try unknown 14b read commands (to be identified later)
// could be read of calypso, CEPAS, moneo, or pico pass. // could be read of calypso, CEPAS, moneo, or pico pass.
if (HF14B_other_reader(verbose)) found |= HF14B_other_reader(verbose);
if (loop) if (found && loop)
continue; continue;
} while (loop && kbd_enter_pressed() == false); } while (loop && kbd_enter_pressed() == false);
if (verbose) { if (verbose && found == false) {
PrintAndLogEx(FAILED, "no ISO 14443-B tag found"); PrintAndLogEx(FAILED, "no ISO 14443-B tag found");
} }
return PM3_EOPABORTED; return (found) ? PM3_SUCCESS : PM3_EOPABORTED;
} }

View file

@ -355,7 +355,7 @@ static int CmdHFFudanWrBl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf fudan wrbl", CLIParserInit(&ctx, "hf fudan wrbl",
"Write fudan block with 4 hex bytes of data\n", "Write fudan block with 4 hex bytes of data\n",
"hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304" "hf fudan wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,

View file

@ -683,8 +683,13 @@ static int CmdHFiClassSniff(const char *Cmd) {
WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp); WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog");
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing");
if (jam_epurse_update) {
PrintAndLogEx(HINT, "Verify if the jam worked by comparing value in trace and block 2");
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -682,7 +682,7 @@ static int CmdLegicCalcCrc(const char *Cmd) {
switch (type) { switch (type) {
case 16: case 16:
init_table(CRC_LEGIC); init_table(CRC_LEGIC_16);
PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0])); PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0]));
break; break;
default: default:

View file

@ -189,7 +189,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
if (cmd[1] == 0x01 && cmdsize == 7) { if (cmd[1] == 0x01 && cmdsize == 7) {
snprintf(exp, size, "ECP1"); snprintf(exp, size, "ECP1");
return PM3_SUCCESS; return PM3_SUCCESS;
} else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0f) + 7) { } else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0F) + 7) {
// Byte 3 is the reader type // Byte 3 is the reader type
switch (cmd[3]) { switch (cmd[3]) {
case 0x01: case 0x01:
@ -201,6 +201,9 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
case 0x03: case 0x03:
snprintf(exp, size, "ECP2 (Identity)"); snprintf(exp, size, "ECP2 (Identity)");
break; break;
case 0x05:
snprintf(exp, size, "ECP2 (AirDrop)");
break;
default: default:
snprintf(exp, size, "ECP2"); snprintf(exp, size, "ECP2");
break; break;
@ -496,7 +499,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
uint8_t key[8]; uint8_t key[8];
if (check_known_default(csn, epurse, rmac, tmac, key)) { if (check_known_default(csn, epurse, rmac, tmac, key)) {
snprintf(exp, size, "CHECK ( %s )", sprint_hex_inrow(key, 8)); snprintf(exp, size, "CHECK ( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8));
} else { } else {
snprintf(exp, size, "CHECK"); snprintf(exp, size, "CHECK");
} }

File diff suppressed because it is too large Load diff

View file

@ -34,19 +34,12 @@
#include "protocols.h" #include "protocols.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
#include "cmdhfmf.h" // printblock, header #include "cmdhfmf.h" // printblock, header
#include "cmdtrace.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 mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
typedef enum { #define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1))
MFP_UNKNOWN = 0,
DESFIRE_MF3ICD40,
DESFIRE_EV1,
DESFIRE_EV2,
DESFIRE_EV3,
DESFIRE_LIGHT,
PLUS_EV1,
} nxp_cardtype_t;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -233,9 +226,10 @@ static int get_plus_signature(uint8_t *signature, int *signature_len) {
*signature_len = 0; *signature_len = 0;
retval = PM3_ESOFT; retval = PM3_ESOFT;
} }
mfpSetVerboseMode(false);
return retval; return retval;
} }
// GET VERSION // GET VERSION
static int plus_print_version(uint8_t *version) { static int plus_print_version(uint8_t *version) {
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7));
@ -261,12 +255,12 @@ static int plus_print_version(uint8_t *version) {
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false)); PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int get_plus_version(uint8_t *version, int *version_len) { static int get_plus_version(uint8_t *version, int *version_len) {
int resplen = 0, retval = PM3_SUCCESS; int resplen = 0, retval = PM3_SUCCESS;
mfpSetVerboseMode(false); mfpSetVerboseMode(false);
MFPGetVersion(true, false, version, *version_len, &resplen); MFPGetVersion(true, false, version, *version_len, &resplen);
mfpSetVerboseMode(false);
*version_len = resplen; *version_len = resplen;
if (resplen != 28) { if (resplen != 28) {
@ -484,16 +478,16 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keyLen) { if (!keyLen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keyLen = 16; keyLen = 16;
} }
if (keyNumLen != 2) { if (keyNumLen != 2) {
PrintAndLogEx(ERR, "Key number length must be 2 bytes instead of: %d", keyNumLen); PrintAndLogEx(ERR, "Key number length must be 2 bytes. Got %d", keyNumLen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keyLen != 16) { if (keyLen != 16) {
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); PrintAndLogEx(ERR, "Key length must be 16 bytes. Got %d", keyLen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -507,7 +501,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
} }
if (datalen != 3) { if (datalen != 3) {
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -539,17 +533,18 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
bool verbose2 = arg_get_lit(ctx, 1) > 1; bool verbose2 = arg_get_lit(ctx, 1) > 1;
uint8_t key[256] = {0}; uint8_t key[256] = {0};
int keyLen = 0; int keylen = 0;
CLIGetHexWithReturn(ctx, 2, key, &keyLen); CLIGetHexWithReturn(ctx, 2, key, &keylen);
CLIParserFree(ctx); CLIParserFree(ctx);
if (keyLen && keyLen != 16) { if (keylen && keylen != 16) {
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); PrintAndLogEx(FAILED, "Key length must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (!keyLen) if (keylen == 0) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, sizeof(mfp_default_key));
}
uint8_t keyNum[2] = {0}; uint8_t keyNum[2] = {0};
uint8_t data[250] = {0}; uint8_t data[250] = {0};
@ -572,15 +567,15 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
} }
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
for (int i = 0; i < ARRAYLEN(CardAddresses); i++) { for (int i = 0; i < ARRAYLEN(mfp_card_adresses); i++) {
keyNum[0] = CardAddresses[i] >> 8; keyNum[0] = mfp_card_adresses[i] >> 8;
keyNum[1] = CardAddresses[i] & 0xff; keyNum[1] = mfp_card_adresses[i] & 0xff;
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen); res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) { if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLogEx(WARNING, "Skipped[%04x]...", CardAddresses[i]); PrintAndLogEx(WARNING, "Skipped[%04x]...", mfp_card_adresses[i]);
} else { } else {
if (res || (datalen != 3) || data[0] != 0x90) { if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLogEx(ERR, "Write error on address %04x", CardAddresses[i]); PrintAndLogEx(ERR, "Write error on address %04x", mfp_card_adresses[i]);
break; break;
} }
} }
@ -597,7 +592,9 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
static int CmdHFMFPCommitPerso(const char *Cmd) { static int CmdHFMFPCommitPerso(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp commitp", CLIParserInit(&ctx, "hf mfp commitp",
"Executes Commit Perso command. Can be used in SL0 mode only.\nOBS! This command will not be executed if CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.", "Executes Commit Perso command. Can be used in SL0 mode only.\n"
"OBS! This command will not be executed if \n"
"CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
"hf mfp commitp\n" "hf mfp commitp\n"
// "hf mfp commitp --sl 1" // "hf mfp commitp --sl 1"
); );
@ -625,7 +622,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
} }
if (datalen != 3) { if (datalen != 3) {
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -633,7 +630,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
return PM3_EINVARG; return PM3_EINVARG;
} }
PrintAndLogEx(INFO, "Switch level ( " _GREEN_("ok") " )"); PrintAndLogEx(INFO, "Switched security level ( " _GREEN_("ok") " )");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -645,7 +642,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp auth", CLIParserInit(&ctx, "hf mfp auth",
"Executes AES authentication command for Mifare Plus card", "Executes AES authentication command for MIFARE Plus card",
"hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
"hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data"); "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data");
@ -664,12 +661,12 @@ static int CmdHFMFPAuth(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
if (keynlen != 2) { if (keynlen != 2) {
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes long instead of: %d", keynlen); PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes. Got %d", keynlen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes long instead of: %d", keylen); PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -679,7 +676,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
static int CmdHFMFPRdbl(const char *Cmd) { static int CmdHFMFPRdbl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp rdbl", CLIParserInit(&ctx, "hf mfp rdbl",
"Reads several blocks from Mifare Plus card", "Reads blocks from MIFARE Plus card",
"hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
"hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF"); "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF");
@ -710,23 +707,23 @@ static int CmdHFMFPRdbl(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (blockn > 255) { if (blockn > 255) {
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockn); PrintAndLogEx(ERR, "<block number> must be in range [0..255]. got %d", blockn);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
// 3 blocks - wo iso14443-4 chaining // 3 blocks - wo iso14443-4 chaining
if (blocksCount > 3) { if (blocksCount > 3) {
PrintAndLogEx(ERR, "blocks count must be less than 3. got: %d", blocksCount); PrintAndLogEx(ERR, "blocks count must be less than 3. Got %d", blocksCount);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -820,17 +817,17 @@ static int CmdHFMFPRdsc(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (sectorNum > 39) { if (sectorNum > 39) {
PrintAndLogEx(ERR, "<sector number> must be in range [0..39] got: %d", sectorNum); PrintAndLogEx(ERR, "<sector number> must be in range [0..39]. Got %d", sectorNum);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -894,7 +891,7 @@ static int CmdHFMFPRdsc(const char *Cmd) {
static int CmdHFMFPWrbl(const char *Cmd) { static int CmdHFMFPWrbl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp wrbl", CLIParserInit(&ctx, "hf mfp wrbl",
"Writes one block to Mifare Plus card", "Writes one block to MIFARE Plus card",
"hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n" "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n"
"hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF" "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF"
); );
@ -928,22 +925,22 @@ static int CmdHFMFPWrbl(const char *Cmd) {
mfpSetVerboseMode(verbose); mfpSetVerboseMode(verbose);
if (!keylen) { if (!keylen) {
memmove(key, DefaultKey, 16); memmove(key, mfp_default_key, 16);
keylen = 16; keylen = 16;
} }
if (blockNum > 255) { if (blockNum > 255) {
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockNum); PrintAndLogEx(ERR, "<block number> must be in range [0..255]. Got %d", blockNum);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 16) { if (keylen != 16) {
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen); PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (datainlen != 16) { if (datainlen != 16) {
PrintAndLogEx(ERR, "<data> must be 16 bytes long. got: %d", datainlen); PrintAndLogEx(ERR, "<data> must be 16 bytes. Got %d", datainlen);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -997,11 +994,8 @@ static int CmdHFMFPWrbl(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
#define AES_KEY_LEN 16
#define MAX_KEYS_LIST_LEN 1024
static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
bool verbose) { bool verbose) {
int res; int res;
bool selectCard = true; bool selectCard = true;
@ -1088,7 +1082,7 @@ static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startK
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) { static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
keyList[*keyListLen][0] = (pt >> 8) & 0xff; keyList[*keyListLen][0] = (pt >> 8) & 0xff;
keyList[*keyListLen][1] = pt & 0xff; keyList[*keyListLen][1] = pt & 0xff;
@ -1097,7 +1091,7 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3
memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8);
(*keyListLen)++; (*keyListLen)++;
*startPattern = pt; *startPattern = pt;
if (*keyListLen == MAX_KEYS_LIST_LEN) if (*keyListLen == MAX_AES_KEYS_LIST_LEN)
break; break;
} }
(*startPattern)++; (*startPattern)++;
@ -1111,7 +1105,7 @@ static int CmdHFMFPChk(const char *Cmd) {
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
"hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n" "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
"hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n"
"hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00"); "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
void *argtable[] = { void *argtable[] = {
@ -1125,7 +1119,7 @@ static int CmdHFMFPChk(const char *Cmd) {
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
arg_str0("j", "json", "<fn>", "Json filename to save keys"), arg_lit0(NULL, "dump", "Dump found keys to JSON file"),
arg_lit0("v", "verbose", "Verbose mode"), arg_lit0("v", "verbose", "Verbose mode"),
arg_param_end arg_param_end
}; };
@ -1136,7 +1130,7 @@ static int CmdHFMFPChk(const char *Cmd) {
uint8_t startSector = arg_get_int_def(ctx, 3, 0); uint8_t startSector = arg_get_int_def(ctx, 3, 0);
uint8_t endSector = arg_get_int_def(ctx, 4, 0); uint8_t endSector = arg_get_int_def(ctx, 4, 0);
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
uint32_t keyListLen = 0; uint32_t keyListLen = 0;
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
@ -1148,7 +1142,7 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&keyList[keyListLen], vkey, 16); memcpy(&keyList[keyListLen], vkey, 16);
keyListLen++; keyListLen++;
} else { } else {
PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen);
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1185,7 +1179,7 @@ static int CmdHFMFPChk(const char *Cmd) {
if (vpatternlen <= 2) { if (vpatternlen <= 2) {
startPattern = (vpattern[0] << 8) + vpattern[1]; startPattern = (vpattern[0] << 8) + vpattern[1];
} else { } else {
PrintAndLogEx(ERR, "Pattern must be 2-byte length."); PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen);
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1193,17 +1187,8 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
} }
uint8_t jsonname[250] = {0}; bool create_dumpfile = arg_get_lit(ctx, 10);
int jsonnamelen = 0;
if (CLIParamStrToBuf(arg_get_str(ctx, 10), jsonname, sizeof(jsonname), &jsonnamelen)) {
PrintAndLogEx(ERR, "Invalid json name.");
CLIParserFree(ctx);
return PM3_EINVARG;
}
jsonname[jsonnamelen] = 0;
bool verbose = arg_get_lit(ctx, 11); bool verbose = arg_get_lit(ctx, 11);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t startKeyAB = 0; uint8_t startKeyAB = 0;
@ -1227,8 +1212,9 @@ static int CmdHFMFPChk(const char *Cmd) {
} }
// 2-byte pattern search mode // 2-byte pattern search mode
if (pattern2b) if (pattern2b) {
Fill2bPattern(keyList, &keyListLen, &startPattern); Fill2bPattern(keyList, &keyListLen, &startPattern);
}
int res = PM3_SUCCESS; int res = PM3_SUCCESS;
@ -1295,15 +1281,25 @@ static int CmdHFMFPChk(const char *Cmd) {
} }
break; break;
} }
if (verbose == false)
if (verbose == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
}
// print result // print result
char strA[46 + 1] = {0}; char strA[46 + 1] = {0};
char strB[46 + 1] = {0}; char strB[46 + 1] = {0};
uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
bool has_ndef_key = false;
bool printedHeader = false; bool printedHeader = false;
for (uint8_t s = startSector; s <= endSector; s++) { for (uint8_t s = startSector; s <= endSector; s++) {
if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) ||
(memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) {
has_ndef_key = true;
}
if (printedHeader == false) { if (printedHeader == false) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
@ -1333,7 +1329,13 @@ static int CmdHFMFPChk(const char *Cmd) {
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n"); PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n");
// save keys to json // save keys to json
if ((jsonnamelen > 0) && printedHeader) { if (create_dumpfile && printedHeader) {
size_t keys_len = (2 * 64 * (AES_KEY_LEN + 1));
uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len];
memset(data, 0, sizeof(data));
// 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);
@ -1344,8 +1346,6 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
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
uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0};
uint8_t atslen = 0; uint8_t atslen = 0;
if (select_status == 1 || select_status == 2) { if (select_status == 1 || select_status == 2) {
memcpy(data, card.uid, card.uidlen); memcpy(data, card.uid, card.uidlen);
@ -1357,19 +1357,117 @@ static int CmdHFMFPChk(const char *Cmd) {
memcpy(&data[14], card.ats, atslen); memcpy(&data[14], card.ats, atslen);
} }
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t));
strcpy(fptr, "hf-mfp-");
FillFileNameByUID(fptr, card.uid, "-key", card.uidlen);
// length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1)); memcpy(&data[14 + atslen], foundKeys, keys_len);
saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64, NULL); // 64 here is for how many "rows" there is in the data array. A bit confusing
saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL);
free(fptr);
} }
// MAD detection
if ((memcmp(&foundKeys[0][0][1], "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", AES_KEY_LEN) == 0)) {
PrintAndLogEx(HINT, "MAD key detected. Try " _YELLOW_("`hf mfp mad`") " for more details");
}
// NDEF detection
if (has_ndef_key) {
PrintAndLogEx(HINT, "NDEF key detected. Try " _YELLOW_("`hf mfp ndefread -h`") " for more details");
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFMFPDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp dump",
"Dump MIFARE Plus tag to binary file\n"
"If no <name> given, UID will be used as filename",
"hf mfp dump\n"
"hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n");
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump"),
arg_str0("k", "keys", "<fn>", "filename of keys"),
arg_lit0(NULL, "ns", "no save to file"),
arg_lit0("v", "verbose", "Verbose mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int datafnlen = 0;
char data_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)data_fn, FILE_PATH_SIZE, &datafnlen);
int keyfnlen = 0;
char key_fn[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)key_fn, FILE_PATH_SIZE, &keyfnlen);
bool nosave = arg_get_lit(ctx, 3);
bool verbose = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
mfpSetVerboseMode(verbose);
// read card
uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t));
if (mem == NULL) {
PrintAndLogEx(ERR, "failed to allocate memory");
return PM3_EMALLOC;
}
/*
iso14a_card_select_t card ;
int res = mfp_read_tag(&card, mem, key_fn);
if (res != PM3_SUCCESS) {
free(mem);
return res;
}
*/
// Skip saving card data to file
if (nosave) {
PrintAndLogEx(INFO, "Called with no save option");
free(mem);
return PM3_SUCCESS;
}
/*
// Save to file
if (strlen(data_fn) < 1) {
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-dump")) + card.uidlen * 2 + 1, sizeof(uint8_t));
strcpy(fptr, "hf-mfp-");
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
strcpy(data_fn, fptr);
free(fptr);
}
saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES);
saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = mem;
xdump.dumplen = MIFARE_4K_MAX_BYTES;
saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
*/
free(mem);
return PM3_SUCCESS;
}
static int CmdHFMFPMAD(const char *Cmd) { static int CmdHFMFPMAD(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp mad", CLIParserInit(&ctx, "hf mfp mad",
"Checks and prints Mifare Application Directory (MAD)", "Checks and prints MIFARE Application Directory (MAD)",
"hf mfp mad\n" "hf mfp mad\n"
"hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid"); "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid");
@ -1411,9 +1509,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); MADPrintHeader();
PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------");
PrintAndLogEx(INFO, "-----------------------------------------------------");
if (verbose) { if (verbose) {
PrintAndLogEx(SUCCESS, "Raw:"); PrintAndLogEx(SUCCESS, "Raw:");
@ -1427,7 +1523,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
if (haveMAD2) { if (haveMAD2) {
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys"); PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -1505,6 +1601,36 @@ static int CmdHFMFPMAD(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFMFPNDEFFormat(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp ndefformat",
"format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n"
"If no <name> given, UID will be used as filename. \n"
"It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
"\n"
"If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
"hf mfp ndefformat\n"
"hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("k", "keys", "<fn>", "filename of keys"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int keyfnlen = 0;
char keyFilename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
CLIParserFree(ctx);
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
int CmdHFMFPNDEFRead(const char *Cmd) { int CmdHFMFPNDEFRead(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
@ -1641,19 +1767,73 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFMFPNDEFWrite(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp ndefwrite",
"Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
"hf mfp ndefwrite -d 0300FE -> write empty record to tag\n"
"hf mfp ndefwrite -f myfilename\n"
"hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("d", NULL, "<hex>", "raw NDEF hex bytes"),
arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
arg_lit0("p", NULL, "fix NDEF record headers / terminator block if missing"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t raw[4096] = {0};
int rawlen;
CLIGetHexWithReturn(ctx, 1, raw, &rawlen);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool fix_msg = arg_get_lit(ctx, 3);
bool verbose = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (fix_msg) {
PrintAndLogEx(NORMAL, "called with fix NDEF message param");
}
if (verbose) {
PrintAndLogEx(NORMAL, "");
}
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int CmdHFMFPList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf mf", "mf");
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about Mifare Plus tag"}, {"list", CmdHFMFPList, AlwaysAvailable, "List MIFARE Plus history"},
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"}, {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
{"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"}, {"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"},
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
{"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Plus tag to binary file"},
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"},
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"},
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"},
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"},
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------- " _CYAN_("personalization") " -------------------"},
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Configure security layer (SL1/SL3 mode)"},
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("ndef") " ------------------------"},
{"ndefformat", CmdHFMFPNDEFFormat, IfPm3Iso14443a, "Format MIFARE Plus Tag as NFC Tag"},
{"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"}, {"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
{"ndefwrite", CmdHFMFPNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -20,6 +20,30 @@
#include "common.h" #include "common.h"
#define AES_KEY_LEN 16
#define MAX_AES_KEYS_LIST_LEN 1024
typedef enum {
MFP_UNKNOWN = 0,
DESFIRE_MF3ICD40,
DESFIRE_EV1,
DESFIRE_EV2,
DESFIRE_EV3,
DESFIRE_LIGHT,
PLUS_EV1,
} nxp_cardtype_t;
typedef struct mfp_key_item {
uint8_t a[16];
uint8_t b[16];
} mfp_key_item_t;
typedef struct mfp_keys {
uint8_t success;
mfp_key_item_t *keys;
} mfp_keys_t;
int CmdHFMFP(const char *Cmd); int CmdHFMFP(const char *Cmd);
int CmdHFMFPNDEFRead(const char *Cmd); int CmdHFMFPNDEFRead(const char *Cmd);

View file

@ -224,6 +224,8 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) {
uint16_t resp_len = 11; uint16_t resp_len = 11;
uint8_t response[11] = {0}; uint8_t response[11] = {0};
//
if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) { if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) {
topaz_switch_off_field(); topaz_switch_off_field();
return PM3_ESOFT; // WriteErase 8bytes failed return PM3_ESOFT; // WriteErase 8bytes failed
@ -243,6 +245,61 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) {
return PM3_ESOFT; return PM3_ESOFT;
} }
// write a block (8 Bytes) of a selected Topaz tag.
static int topaz_write_nonerase8_block(uint8_t blockno, uint8_t *block_data) {
uint8_t atqa[2] = {0};
uint8_t rid_response[8] = {0};
int res = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), true);
if (res != PM3_SUCCESS) {
return res;
}
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
return res;
}
uint8_t *uid_echo = &rid_response[2];
uint8_t rall_response[124] = {0};
res = topaz_rall(uid_echo, rall_response);
if (res == PM3_ESOFT) {
return res;
}
// ADD
// 7 6 5 4 3 2 1 0
// b b b --- Byte 0 - 7
// B B B B --------- BLOCK
// r ----------------- 0
//
uint8_t wr8_cmd[] = {TOPAZ_WRITE_NE8, blockno, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
memcpy(wr8_cmd + 10, uid_echo, 4);
memcpy(wr8_cmd + 2, block_data, 8);
uint16_t resp_len = 11;
uint8_t response[11] = {0};
//
if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) {
topaz_switch_off_field();
return PM3_ESOFT;
}
if (resp_len != 11) {
return PM3_EFAILED;
}
if (blockno != response[0]) {
return PM3_EFAILED;
}
if (memcmp(block_data, response + 1, 8) == 0) {
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
// search for the lock area descriptor for the lockable area including byteno // search for the lock area descriptor for the lockable area including byteno
static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) { static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) {
@ -402,6 +459,12 @@ static int topaz_print_CC(uint8_t *data) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void topaz_print_hdr(uint8_t blockno) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " # | block " _GREEN_("0x%02X") " | ascii", blockno);
PrintAndLogEx(INFO, "----+-------------------------+---------");
}
// return type, length and value of a TLV, starting at memory position *TLV_ptr // return type, length and value of a TLV, starting at memory position *TLV_ptr
static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) { static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) {
*TLV_length = 0; *TLV_length = 0;
@ -782,6 +845,7 @@ static int CmdHFTopazDump(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump"), arg_str0("f", "file", "<fn>", "filename of dump"),
arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -789,6 +853,8 @@ static int CmdHFTopazDump(const char *Cmd) {
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool nosave = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
int status = readTopazUid(false, false); int status = readTopazUid(false, false);
@ -811,9 +877,18 @@ static int CmdHFTopazDump(const char *Cmd) {
); );
} }
PrintAndLogEx(INFO, "-------------------------------------------------------------");
topaz_switch_off_field(); topaz_switch_off_field();
// Skip saving card data to file
if (nosave) {
PrintAndLogEx(INFO, "Called with no save option");
if (set_dynamic) {
free(topaz_tag.dynamic_memory);
}
return PM3_SUCCESS;
}
// user supplied filename? // user supplied filename?
if (fnlen < 1) { if (fnlen < 1) {
PrintAndLogEx(INFO, "Using UID as filename"); PrintAndLogEx(INFO, "Using UID as filename");
@ -888,13 +963,13 @@ static int CmdHFTopazRdBl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz rdbl", CLIParserInit(&ctx, "hf topaz rdbl",
"Read a block", "Read Topaz block",
"hf topaz rdbl -b 7\n" "hf topaz rdbl --blk 7\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int1("b", "block", "<dec>", "Block number to write"), arg_int1(NULL, "blk", "<dec>", "Block number"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -910,7 +985,11 @@ static int CmdHFTopazRdBl(const char *Cmd) {
uint8_t data[8] = {0}; uint8_t data[8] = {0};
int res = topaz_read_block(blockno, data); int res = topaz_read_block(blockno, data);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, sizeof(data)));
topaz_print_hdr(blockno);
PrintAndLogEx(INFO, " %2d | %s", blockno, sprint_hex_ascii(data, sizeof(data)));
PrintAndLogEx(NORMAL, "");
} }
topaz_switch_off_field(); topaz_switch_off_field();
@ -922,13 +1001,13 @@ static int CmdHFTopazWrBl(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz wrbl", CLIParserInit(&ctx, "hf topaz wrbl",
"Write a block", "Write Topaz block with 8 hex bytes of data",
"hf topaz wrbl -b 7 -d 1122334455667788\n" "hf topaz wrbl --blk 7 -d 1122334455667788\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int1("b", "block", "<dec>", "Block number to write"), arg_int1(NULL, "blk", "<dec>", "Block number"),
arg_str1("d", "data", "<hex>", "Block data (8 hex bytes)"), arg_str1("d", "data", "<hex>", "Block data (8 hex bytes)"),
arg_param_end arg_param_end
}; };
@ -954,14 +1033,23 @@ static int CmdHFTopazWrBl(const char *Cmd) {
PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, dlen)); PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, dlen));
// send write Block int res;
int res = topaz_write_erase8_block(blockno, data); if (blockno != 13 && blockno != 14) {
// send write/erase block
res = topaz_write_erase8_block(blockno, data);
} else {
// send write/non erase block
res = topaz_write_nonerase8_block(blockno, data);
}
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )"); PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
PrintAndLogEx(HINT, "try `" _YELLOW_("hf topaz rdbl --blk %u") "` to verify", blockno);
} else { } else {
PrintAndLogEx(WARNING, "Write ( " _RED_("fail") " )"); PrintAndLogEx(WARNING, "Write ( " _RED_("fail") " )");
} }
PrintAndLogEx(NORMAL, "");
topaz_switch_off_field(); topaz_switch_off_field();
return res; return res;
@ -971,16 +1059,22 @@ static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"},
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"}, {"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
{"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
{"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"},
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"}, {"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
{"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
{"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"},
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"}, {"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"}, {"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"},
{"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"}, {"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
{"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
{"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"},
{"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"}, {"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"},
{"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"}, {"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
// {"ndefformat", CmdHFTopazNDEFFormat, IfPm3Iso14443a, "Format Topaz Tag as NFC Tag"},
// {"ndefread", CmdHFTopazNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
// {"ndefwrite", CmdHFTopazNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -120,7 +120,7 @@ static void decodeHeden2L(uint8_t *bits) {
if (bits[offset + 7]) cardnumber += 16384; if (bits[offset + 7]) cardnumber += 16384;
if (bits[offset + 23]) cardnumber += 32768; if (bits[offset + 23]) cardnumber += 32768;
PrintAndLogEx(SUCCESS, " Heden-2L | %u", cardnumber); PrintAndLogEx(SUCCESS, " Heden-2L...... %u", cardnumber);
} }
// sending three times. Didn't seem to break the previous sim? // sending three times. Didn't seem to break the previous sim?
@ -301,10 +301,11 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
); );
PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01); PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01);
PrintAndLogEx(INFO, "");
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
// This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS // This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS
PrintAndLogEx(SUCCESS, " Printed | __%04d__ [0x%X]", p1, p1); PrintAndLogEx(SUCCESS, " Printed....... __%04d__ ( 0x%X )", p1, p1);
PrintAndLogEx(SUCCESS, " Internal ID | %" PRIu64, foo); PrintAndLogEx(SUCCESS, " Internal ID... %" PRIu64, foo);
decodeHeden2L(g_DemodBuffer); decodeHeden2L(g_DemodBuffer);
} else { } else {
@ -336,6 +337,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Indala - printing DemodBuffer"); PrintAndLogEx(DEBUG, "DEBUG: Indala - printing DemodBuffer");
printDemodBuff(0, false, false, false); printDemodBuff(0, false, false, false);
} }
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -503,7 +505,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
showbits[bit] = '.' + bits[bit]; showbits[bit] = '.' + bits[bit];
} }
showbits[bit + 1] = '\0'; showbits[bit + 1] = '\0';
PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits); PrintAndLogEx(SUCCESS, "Partial UID... %s", showbits);
return PM3_SUCCESS; return PM3_SUCCESS;
} else { } else {
for (bit = 0; bit < uidlen; bit++) { for (bit = 0; bit < uidlen; bit++) {
@ -528,7 +530,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
uid2 = (uid2 << 1) | 1; uid2 = (uid2 << 1) | 1;
} }
} }
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2); PrintAndLogEx(SUCCESS, "UID... %s ( %x%08x )", showbits, uid1, uid2);
} else { } else {
uint32_t uid3 = 0; uint32_t uid3 = 0;
uint32_t uid4 = 0; uint32_t uid4 = 0;
@ -549,7 +551,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
else else
uid7 = (uid7 << 1) | 1; uid7 = (uid7 << 1) | 1;
} }
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); PrintAndLogEx(SUCCESS, "UID... %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
} }
// Checking UID against next occurrences // Checking UID against next occurrences

View file

@ -29,6 +29,7 @@
#include "cmdhficlass.h" // pagemap #include "cmdhficlass.h" // pagemap
#include "protocols.h" // iclass defines #include "protocols.h" // iclass defines
#include "cmdhftopaz.h" // TOPAZ defines #include "cmdhftopaz.h" // TOPAZ defines
#include "mifare/mifaredefault.h" // MFP / AES defines
#ifdef _WIN32 #ifdef _WIN32
#include "scandir.h" #include "scandir.h"
@ -543,13 +544,14 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
break; break;
} }
case jsfMfPlusKeys: { case jsfMfPlusKeys: {
JsonSaveStr(root, "FileType", "mfp"); JsonSaveStr(root, "FileType", "mfpkeys");
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7); JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1); JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2); JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
uint8_t atslen = data[13]; uint8_t atslen = data[13];
if (atslen > 0) if (atslen > 0) {
JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen); JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen);
}
uint8_t vdata[2][64][17] = {{{0}}}; uint8_t vdata[2][64][17] = {{{0}}};
memcpy(vdata, data + (14 + atslen), 2 * 64 * 17); memcpy(vdata, data + (14 + atslen), 2 * 64 * 17);
@ -559,12 +561,12 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
if (vdata[0][i][0]) { if (vdata[0][i][0]) {
snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i); snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i);
JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16); JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN);
} }
if (vdata[1][i][0]) { if (vdata[1][i][0]) {
snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyB", i); snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyB", i);
JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16); JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], AES_KEY_LEN);
} }
} }
break; break;
@ -1296,6 +1298,40 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
*datalen += sptr; *datalen += sptr;
} }
if (!strcmp(ctype, "mfpkeys")) {
JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen);
JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen);
JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen);
uint8_t atslen = udata.bytes[13];
if (atslen > 0) {
JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen);
}
size_t sptr = (14 + atslen);
// memcpy(vdata, udata.bytes + (14 + atslen), 2 * 64 * 17);
for (size_t i = 0; i < 64; i++) {
if ((sptr + (AES_KEY_LEN * 2)) > maxdatalen) {
break;
}
size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN);
char blocks[40] = {0};
snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyA", i);
JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen);
snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyB", i);
JsonLoadBufAsHex(root, blocks, udata.bytes + offset + AES_KEY_LEN, AES_KEY_LEN, datalen);
sptr += (2 * AES_KEY_LEN);
}
*datalen += sptr;
}
out: out:
if (callback != NULL) { if (callback != NULL) {

View file

@ -190,7 +190,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
uint8_t GPB = sector0[(3 * 16) + 9]; uint8_t GPB = sector0[(3 * 16) + 9];
if (verbose) if (verbose)
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x"), "GPB", GPB); PrintAndLogEx(SUCCESS, "GPB....... " _GREEN_("0x%02X"), GPB);
// DA (MAD available) // DA (MAD available)
if (!(GPB & 0x80)) { if (!(GPB & 0x80)) {
@ -200,21 +200,22 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
uint8_t mad_ver = GPB & 0x03; uint8_t mad_ver = GPB & 0x03;
if (verbose) if (verbose)
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("%d"), "MAD version", mad_ver); PrintAndLogEx(SUCCESS, "Version... " _GREEN_("%d"), mad_ver);
// MAD version // MAD version
if ((mad_ver != 0x01) && (mad_ver != 0x02)) { if ((mad_ver != 0x01) && (mad_ver != 0x02)) {
PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02x"), mad_ver); PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02X"), mad_ver);
return PM3_ESOFT; return PM3_ESOFT;
}; };
if (haveMAD2) if (haveMAD2) {
*haveMAD2 = (mad_ver == 2); *haveMAD2 = (mad_ver == 2);
}
int res = madCRCCheck(sector0, true, 1); int res = madCRCCheck(sector0, true, 1);
if (verbose && res == PM3_SUCCESS) {
if (verbose && res == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector0[16], _GREEN_("ok"));
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector0[16], _GREEN_("ok")); }
if (mad_ver == 2 && sector10) { if (mad_ver == 2 && sector10) {
int res2 = madCRCCheck(sector10, true, 2); int res2 = madCRCCheck(sector10, true, 2);
@ -222,7 +223,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
res = res2; res = res2;
if (verbose && !res2) if (verbose && !res2)
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector10[0], _GREEN_("ok")); PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector10[0], _GREEN_("ok"));
} }
// MA (multi-application card) // MA (multi-application card)
@ -284,9 +285,10 @@ static int MADInfoByteDecode(const uint8_t *sector, bool swapmad, int mad_ver, b
info = sector[16 + 1] & 0x3f; info = sector[16 + 1] & 0x3f;
if (info >= 0xF) { if (info >= 0xF) {
PrintAndLogEx(WARNING, "Invalid Info byte (MAD1) value " _YELLOW_("0x%02x"), info); PrintAndLogEx(WARNING, "Invalid Info byte (MAD1) value " _YELLOW_("0x%02x"), info);
if (verbose) if (verbose) {
// I understand the spec in a way that MAD1 InfoByte should not point into MAD2 sectors, @lukaskuzmiak // I understand the spec in a way that MAD1 InfoByte should not point into MAD2 sectors, @lukaskuzmiak
PrintAndLogEx(WARNING, "MAD1 Info byte points outside of MAD1 sector space (0x%02x), report a bug?", info); PrintAndLogEx(WARNING, "MAD1 Info byte points outside of MAD1 sector space (0x%02x), report a bug?", info);
}
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
@ -318,7 +320,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
int ibs = MADInfoByteDecode(sector, swapmad, 1, verbose); int ibs = MADInfoByteDecode(sector, swapmad, 1, verbose);
if (ibs > 0) { if (ibs > 0) {
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs); PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs);
} else { } else {
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs); PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
} }
@ -356,7 +358,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
} }
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
open_mad_file(&mad_known_aids, verbose); open_mad_file(&mad_known_aids, false);
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 details") " -------------"); PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 details") " -------------");
@ -364,14 +366,14 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
int res = madCRCCheck(sector, true, 2); int res = madCRCCheck(sector, true, 2);
if (verbose) { if (verbose) {
if (res == PM3_SUCCESS) if (res == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "CRC8 ( %s )", _GREEN_("ok")); PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _GREEN_("%s") " )", sector[0], "ok");
else else
PrintAndLogEx(WARNING, "CRC8 ( %s )", _RED_("fail")); PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _RED_("%s") " )", sector[0], "fail");
} }
int ibs = MADInfoByteDecode(sector, swapmad, 2, verbose); int ibs = MADInfoByteDecode(sector, swapmad, 2, verbose);
if (ibs > 0) { if (ibs > 0) {
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs); PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs);
} else { } else {
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs); PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
} }
@ -385,12 +387,21 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
for (int i = 1; i < 8 + 8 + 7 + 1; i++) { for (int i = 1; i < 8 + 8 + 7 + 1; i++) {
uint16_t aid = madGetAID(sector, swapmad, 2, i); uint16_t aid = madGetAID(sector, swapmad, 2, i);
if (aid < 6) { if (aid < 6) {
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (%s)") : " %02d [%04X] (%s)", i + 16, aid, aid_admin[aid]); PrintAndLogEx(INFO,
(ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s",
i + 16,
aid,
aid_admin[aid]
);
} else if (prev_aid == aid) { } else if (prev_aid == aid) {
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (continuation)") : " %02d [%04X] (continuation)", i + 16, aid); PrintAndLogEx(INFO,
(ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation",
i + 16,
aid
);
} else { } else {
char fmt[30]; char fmt[60];
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [%04X]%s", i + 16, aid, "%s"); snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i + 16, aid, "%s");
print_aid_description(mad_known_aids, aid, fmt, verbose); print_aid_description(mad_known_aids, aid, fmt, verbose);
prev_aid = aid; prev_aid = aid;
} }

View file

@ -24,9 +24,9 @@
#include "ui.h" #include "ui.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
static bool VerboseMode = false; static bool g_verbose_mode = false;
void mfpSetVerboseMode(bool verbose) { void mfpSetVerboseMode(bool verbose) {
VerboseMode = verbose; g_verbose_mode = verbose;
} }
static const PlusErrorsElm_t PlusErrors[] = { static const PlusErrorsElm_t PlusErrors[] = {
@ -340,12 +340,12 @@ int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool acti
} }
static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
if (VerboseMode) if (g_verbose_mode)
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false); int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false);
if (VerboseMode) if (g_verbose_mode)
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
return res; return res;
@ -367,7 +367,7 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int
int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount}; uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount};
if (!plain && mf4session) if (!plain && mf4session)
CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], g_verbose_mode);
int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
if (res) if (res)
@ -377,7 +377,7 @@ int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t
mf4session->R_Ctr++; mf4session->R_Ctr++;
if (mf4session && mac && *dataoutlen > 11) if (mf4session && mac && *dataoutlen > 11)
CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, g_verbose_mode);
return 0; return 0;
} }
@ -386,7 +386,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
memmove(&rcmd[3], data, 16); memmove(&rcmd[3], data, 16);
if (mf4session) if (mf4session)
CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], g_verbose_mode);
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
if (res) if (res)
@ -396,7 +396,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo
mf4session->W_Ctr++; mf4session->W_Ctr++;
if (mf4session && mac && *dataoutlen > 3) if (mf4session && mac && *dataoutlen > 3)
CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, g_verbose_mode);
return 0; return 0;
} }
@ -534,7 +534,7 @@ uint8_t mfSectorTrailer(uint16_t blockNo) {
if (blockNo < 32 * 4) { if (blockNo < 32 * 4) {
return (blockNo | 0x03); return (blockNo | 0x03);
} else { } else {
return (blockNo | 0x0f); return (blockNo | 0x0F);
} }
} }
@ -551,3 +551,11 @@ uint8_t mfSectorNum(uint16_t blockNo) {
return (32 + (blockNo - 32 * 4) / 16); return (32 + (blockNo - 32 * 4) / 16);
} }
bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno) {
if (sectorno < 32) {
return ((blockno | 0x03) == blockno);
} else {
return ((blockno | 0x0F) == blockno);
}
}

View file

@ -79,6 +79,7 @@ uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
uint8_t mfSectorTrailerOfSector(uint8_t sectorNo); uint8_t mfSectorTrailerOfSector(uint8_t sectorNo);
uint8_t mfSectorTrailer(uint16_t blockNo); uint8_t mfSectorTrailer(uint16_t blockNo);
bool mfIsSectorTrailer(uint16_t blockNo); bool mfIsSectorTrailer(uint16_t blockNo);
bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno);
uint8_t mfSectorNum(uint16_t blockNo); uint8_t mfSectorNum(uint16_t blockNo);

View file

@ -21,6 +21,9 @@
#include "common.h" #include "common.h"
#define AES_KEY_LEN 16
#define MAX_AES_KEYS_LIST_LEN 1024
#define MFKEY_SIZE 6 #define MFKEY_SIZE 6
#define MFBLOCK_SIZE 16 #define MFBLOCK_SIZE 16
@ -41,6 +44,12 @@
#define MIFARE_KEY_SIZE 6 #define MIFARE_KEY_SIZE 6
#define MIFARE_MINI_MAX_KEY_SIZE (MIFARE_MINI_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
#define MIFARE_1K_MAX_KEY_SIZE (MIFARE_1K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
#define MIFARE_2K_MAX_KEY_SIZE (MIFARE_2K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
#define MIFARE_4K_MAX_KEY_SIZE (MIFARE_4K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
static const uint64_t g_mifare_default_keys[] = { static const uint64_t g_mifare_default_keys[] = {
0xffffffffffff, // Default key (first key used by program if no user defined key) 0xffffffffffff, // Default key (first key used by program if no user defined key)
0xa0a1a2a3a4a5, // NFCForum MAD key 0xa0a1a2a3a4a5, // NFCForum MAD key

View file

@ -1431,6 +1431,8 @@ int detect_mf_magic(bool is_mfc) {
case MAGIC_NTAG21X: case MAGIC_NTAG21X:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x")); PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x"));
break; break;
case MAGIC_QL88:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("QL88"));
default: default:
break; break;
} }

View file

@ -927,7 +927,7 @@ static int ndefDecodeExternal_record(NDEFHeader_t *ndef) {
print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32); print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32);
// do a character check? // do a character check?
if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:2", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:", ndef->TypeLen - 1)) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode..."); PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode...");
asn1_print(ndef->Payload, ndef->PayloadLen, " "); asn1_print(ndef->Payload, ndef->PayloadLen, " ");

View file

@ -367,17 +367,21 @@ const static vocabulory_t vocabulory[] = {
{ 0, "hf mf ndefread" }, { 0, "hf mf ndefread" },
{ 0, "hf mf ndefwrite" }, { 0, "hf mf ndefwrite" },
{ 1, "hf mfp help" }, { 1, "hf mfp help" },
{ 0, "hf mfp info" }, { 1, "hf mfp list" },
{ 0, "hf mfp wrp" },
{ 0, "hf mfp initp" },
{ 0, "hf mfp commitp" },
{ 0, "hf mfp auth" }, { 0, "hf mfp auth" },
{ 0, "hf mfp chk" },
{ 0, "hf mfp dump" },
{ 0, "hf mfp info" },
{ 0, "hf mfp mad" },
{ 0, "hf mfp rdbl" }, { 0, "hf mfp rdbl" },
{ 0, "hf mfp rdsc" }, { 0, "hf mfp rdsc" },
{ 0, "hf mfp wrbl" }, { 0, "hf mfp wrbl" },
{ 0, "hf mfp chk" }, { 0, "hf mfp commitp" },
{ 0, "hf mfp mad" }, { 0, "hf mfp initp" },
{ 0, "hf mfp wrp" },
{ 0, "hf mfp ndefformat" },
{ 0, "hf mfp ndefread" }, { 0, "hf mfp ndefread" },
{ 0, "hf mfp ndefwrite" },
{ 1, "hf mfu help" }, { 1, "hf mfu help" },
{ 1, "hf mfu keygen" }, { 1, "hf mfu keygen" },
{ 1, "hf mfu pwdgen" }, { 1, "hf mfu pwdgen" },
@ -461,14 +465,14 @@ const static vocabulory_t vocabulory[] = {
{ 1, "hf thinfilm list" }, { 1, "hf thinfilm list" },
{ 0, "hf thinfilm sim" }, { 0, "hf thinfilm sim" },
{ 1, "hf topaz help" }, { 1, "hf topaz help" },
{ 0, "hf topaz dump" },
{ 1, "hf topaz list" }, { 1, "hf topaz list" },
{ 0, "hf topaz dump" },
{ 0, "hf topaz info" }, { 0, "hf topaz info" },
{ 0, "hf topaz raw" },
{ 0, "hf topaz rdbl" },
{ 0, "hf topaz reader" }, { 0, "hf topaz reader" },
{ 0, "hf topaz sim" }, { 0, "hf topaz sim" },
{ 0, "hf topaz sniff" }, { 0, "hf topaz sniff" },
{ 0, "hf topaz raw" },
{ 0, "hf topaz rdbl" },
{ 1, "hf topaz view" }, { 1, "hf topaz view" },
{ 0, "hf topaz wrbl" }, { 0, "hf topaz wrbl" },
{ 1, "hf xerox help" }, { 1, "hf xerox help" },

View file

@ -189,6 +189,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
free(sp); free(sp);
return INVALID_SERIAL_PORT; return INVALID_SERIAL_PORT;
} }
int sfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); int sfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (sfd == -1) { if (sfd == -1) {
PrintAndLogEx(ERR, "Error opening Bluetooth socket"); PrintAndLogEx(ERR, "Error opening Bluetooth socket");
@ -196,6 +197,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
free(sp); free(sp);
return INVALID_SERIAL_PORT; return INVALID_SERIAL_PORT;
} }
if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
PrintAndLogEx(ERR, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr); PrintAndLogEx(ERR, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr);
close(sfd); close(sfd);

View file

@ -730,7 +730,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool pr
static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) { static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
memset(card, 0, sizeof(wiegand_card_t)); memset(card, 0, sizeof(wiegand_card_t));
if (packed->Length != 36) return false; // Wrong length? Stop here.
if (packed->Length != 36)
return false; // Wrong length? Stop here.
card->OEM = get_linear_field(packed, 1, 10); card->OEM = get_linear_field(packed, 1, 10);
card->FacilityCode = get_linear_field(packed, 11, 8); card->FacilityCode = get_linear_field(packed, 11, 8);
@ -976,8 +978,10 @@ static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed, bool pr
packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6))) << 14; packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6))) << 14;
packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C))); packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)));
packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF))) << 15; packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF))) << 15;
if (preamble) if (preamble)
return add_HID_header(packed); return add_HID_header(packed);
return true; return true;
} }

File diff suppressed because it is too large Load diff

View file

@ -538,17 +538,21 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf mfp help `|Y |`This help` |`hf mfp help `|Y |`This help`
|`hf mfp info `|N |`Info about Mifare Plus tag` |`hf mfp list `|Y |`List MIFARE Plus history`
|`hf mfp wrp `|N |`Write Perso command`
|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode`
|`hf mfp commitp `|N |`Move card to SL1 or SL3 mode`
|`hf mfp auth `|N |`Authentication` |`hf mfp auth `|N |`Authentication`
|`hf mfp rdbl `|N |`Read blocks`
|`hf mfp rdsc `|N |`Read sectors`
|`hf mfp wrbl `|N |`Write blocks`
|`hf mfp chk `|N |`Check keys` |`hf mfp chk `|N |`Check keys`
|`hf mfp dump `|N |`Dump MIFARE Plus tag to binary file`
|`hf mfp info `|N |`Info about MIFARE Plus tag`
|`hf mfp mad `|N |`Check and print MAD` |`hf mfp mad `|N |`Check and print MAD`
|`hf mfp rdbl `|N |`Read blocks from card`
|`hf mfp rdsc `|N |`Read sectors from card`
|`hf mfp wrbl `|N |`Write block to card`
|`hf mfp commitp `|N |`Configure security layer (SL1/SL3 mode)`
|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode`
|`hf mfp wrp `|N |`Write Perso command`
|`hf mfp ndefformat `|N |`Format MIFARE Plus Tag as NFC Tag`
|`hf mfp ndefread `|N |`Read and print NDEF records from card` |`hf mfp ndefread `|N |`Read and print NDEF records from card`
|`hf mfp ndefwrite `|N |`Write NDEF records to card`
### hf mfu ### hf mfu
@ -704,14 +708,14 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf topaz help `|Y |`This help` |`hf topaz help `|Y |`This help`
|`hf topaz dump `|N |`Dump TOPAZ family tag to file`
|`hf topaz list `|Y |`List Topaz history` |`hf topaz list `|Y |`List Topaz history`
|`hf topaz dump `|N |`Dump TOPAZ family tag to file`
|`hf topaz info `|N |`Tag information` |`hf topaz info `|N |`Tag information`
|`hf topaz raw `|N |`Send raw hex data to tag`
|`hf topaz rdbl `|N |`Read block`
|`hf topaz reader `|N |`Act like a Topaz reader` |`hf topaz reader `|N |`Act like a Topaz reader`
|`hf topaz sim `|N |`Simulate Topaz tag` |`hf topaz sim `|N |`Simulate Topaz tag`
|`hf topaz sniff `|N |`Sniff Topaz reader-tag communication` |`hf topaz sniff `|N |`Sniff Topaz reader-tag communication`
|`hf topaz raw `|N |`Send raw hex data to tag`
|`hf topaz rdbl `|N |`Read block`
|`hf topaz view `|Y |`Display content from tag dump file` |`hf topaz view `|Y |`Display content from tag dump file`
|`hf topaz wrbl `|N |`Write block` |`hf topaz wrbl `|N |`Write block`

View file

@ -621,6 +621,7 @@ typedef struct {
#define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613 #define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613
#define CMD_HF_MIFARE_ACQ_NONCES 0x0614 #define CMD_HF_MIFARE_ACQ_NONCES 0x0614
#define CMD_HF_MIFARE_STATIC_NESTED 0x0615 #define CMD_HF_MIFARE_STATIC_NESTED 0x0615
#define CMD_HF_MIFARE_STATIC_ENC 0x0616
#define CMD_HF_MIFARE_READBL 0x0620 #define CMD_HF_MIFARE_READBL 0x0620
#define CMD_HF_MIFAREU_READBL 0x0720 #define CMD_HF_MIFAREU_READBL 0x0720

View file

@ -263,6 +263,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MAGIC_GEN_3 9 #define MAGIC_GEN_3 9
#define MAGIC_GEN_4GTU 10 #define MAGIC_GEN_4GTU 10
#define MAGIC_GEN_4GDM 11 #define MAGIC_GEN_4GDM 11
#define MAGIC_QL88 12
// Commands for configuration of Gen4 GTU cards. // Commands for configuration of Gen4 GTU cards.
// see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md // see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md

View file

@ -9,6 +9,9 @@ MYLDLIBS = -lcrypto
cpu_arch = $(shell uname -m) cpu_arch = $(shell uname -m)
ifneq ($(findstring arm64, $(cpu_arch)), ) ifneq ($(findstring arm64, $(cpu_arch)), )
MYCFLAGS += -mcpu=native MYCFLAGS += -mcpu=native
# iOS 'fun'
else ifneq ($(findstring iP, $(cpu_arch)), )
MYCFLAGS += -mcpu=native
else else
MYCFLAGS += -march=native MYCFLAGS += -march=native
endif endif

View file

@ -33,6 +33,7 @@
#include <time.h> #include <time.h>
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <inttypes.h>
#include "util_posix.h" #include "util_posix.h"
#define AEND "\x1b[0m" #define AEND "\x1b[0m"

View file

@ -35,6 +35,7 @@
#include <time.h> #include <time.h>
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>
#include <inttypes.h>
//#include <mbedtls/aes.h> //#include <mbedtls/aes.h>
#include "util_posix.h" #include "util_posix.h"
#include "randoms.h" #include "randoms.h"

View file

@ -437,8 +437,7 @@ while true; do
if ! CheckExecute slow "lf T55 hid_48 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_hid_48.pm3; lf hid demod'" \ if ! CheckExecute slow "lf T55 hid_48 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_hid_48.pm3; lf hid demod'" \
"HID Corporate 1000 48-bit"; then break; fi "HID Corporate 1000 48-bit"; then break; fi
if ! CheckExecute slow "lf T55 indala_hedem test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf search -1'" "Indala ID found"; then break; fi if ! CheckExecute slow "lf T55 indala_hedem test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf search -1'" "Indala ID found"; then break; fi
if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" \ if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" "Heden-2L...... 888"; then break; fi
"Heden-2L \| 888"; then break; fi
if ! CheckExecute slow "lf T55 indala test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf search -1'" "Indala ID found"; then break; fi if ! CheckExecute slow "lf T55 indala test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf search -1'" "Indala ID found"; then break; fi
if ! CheckExecute slow "lf T55 indala test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf indala demod'" \ if ! CheckExecute slow "lf T55 indala test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf indala demod'" \
"Fmt 26 FC: 123 Card: 1337 Parity: 11"; then break; fi "Fmt 26 FC: 123 Card: 1337 Parity: 11"; then break; fi