From 9ebbfd898ca6ce4f9e32b64aca3f3972a3a74e2c Mon Sep 17 00:00:00 2001 From: Iceman Date: Mon, 22 Apr 2019 18:25:52 +0200 Subject: [PATCH 01/29] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09f23a6b..2f7007e2 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ following locations: * [RyscCorp](https://proxmark3.com/) (US) * [Hackerwarehouse](https://hackerwarehouse.com/) (US) * [Elechouse](http://www.elechouse.com/) (HK) -* [Lab401](https://lab401.com/) (FR) +* [Lab401](https://lab401.com/) (HK) * [RFxSecure](http://www.rfxsecure.com/) (SG) -* [IceSQL](http://proxmark3.tictail.com/) (SE) +* [Sneaktechnology](https://www.sneaktechnology.com/) (ASIA/OCEANIA) + Most of the ultra-low-volume contract assemblers could put something like this together with a reasonable yield. A run of around From a39af1cb9cab6298fcf01d7243e9f48db0f45f26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 22 May 2019 19:02:58 +0200 Subject: [PATCH 02/29] Add: new option 'd' in 'hf mf ekeyprn' to create dumpkeys.bin from emulator memory (#822) (and whitespace fixes) --- client/cmdhfmf.c | 572 +++++++++++++++++++++++++---------------------- 1 file changed, 302 insertions(+), 270 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 903e8575..9284d14c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,7 +34,7 @@ #include "mifare/ndef.h" #include "emv/dump.h" -#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up +#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up static int CmdHelp(const char *Cmd); @@ -65,7 +65,7 @@ int CmdHF14AMfWrBl(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf wrbl "); @@ -113,7 +113,7 @@ int CmdHF14AMfRdBl(const char *Cmd) uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { @@ -177,7 +177,7 @@ int CmdHF14AMfRdSc(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t isOK = 0; uint8_t *data = NULL; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf rdsc "); @@ -218,15 +218,15 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("data : %s", sprint_hex(data + i * 16, 16)); } PrintAndLog("trailer: %s", sprint_hex(data + (sectorNo<32?3:15) * 16, 16)); - + PrintAndLogEx(NORMAL, "Trailer decoded:"); - int bln = mfFirstBlockOfSector(sectorNo); - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); + int bln = mfFirstBlockOfSector(sectorNo); + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); } } else { PrintAndLog("Command execute timeout"); @@ -324,7 +324,7 @@ int CmdHF14AMfDump(const char *Cmd) fclose(fin); return 2; } - } + } } fclose(fin); @@ -371,7 +371,7 @@ int CmdHF14AMfDump(const char *Cmd) for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { bool received = false; for (tries = 0; tries < 3; tries++) { - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -387,14 +387,14 @@ int CmdHF14AMfDump(const char *Cmd) // Don't try the other one on success. if (resp.arg[0] & 0xff) break; } - } else { // data block. Check if it can be read with key A or key B + } else { // data block. Check if it can be read with key A or key B uint8_t data_area = sectorNo<32?blockNo:blockNo/5; - if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work + if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}}; memcpy(c.d.asBytes, keys[1][sectorNo], 6); SendCommand(&c); received = WaitForResponseTimeout(CMD_ACK,&resp,1500); - } else if (rights[sectorNo][data_area] == 0x07) { // no key would work + } else if (rights[sectorNo][data_area] == 0x07) { // no key would work PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); if (nullMissingKeys) { memset(resp.d.asBytes, 0, 16); @@ -405,7 +405,7 @@ int CmdHF14AMfDump(const char *Cmd) isOK = false; tries = 2; } - } else { // key A would work + } else { // key A would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -421,13 +421,13 @@ int CmdHF14AMfDump(const char *Cmd) if (received) { isOK = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. memcpy(data, keys[0][sectorNo], 6); memcpy(data + 10, keys[1][sectorNo], 6); } if (isOK) { memcpy(carddata[FirstBlockOfSector(sectorNo) + blockNo], data, 16); - PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); + PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); } else { PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo); break; @@ -530,7 +530,7 @@ int CmdHF14AMfRestore(const char *Cmd) return 2; } - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer bldata[0] = (keyA[sectorNo][0]); bldata[1] = (keyA[sectorNo][1]); bldata[2] = (keyA[sectorNo][2]); @@ -573,7 +573,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo int len = param_getlength(Cmd, indx); if (len > 0 && len < 4){ param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3)); - + *paramT |= (ctmp3[0] == 't' || ctmp3[0] == 'T'); *paramD |= (ctmp3[0] == 'd' || ctmp3[0] == 'D'); bool paramS1 = *paramT || *paramD; @@ -581,7 +581,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo // slow and very slow if (ctmp3[0] == 's' || ctmp3[0] == 'S' || ctmp3[1] == 's' || ctmp3[1] == 'S') { *timeout = 11; // slow - + if (!paramS1 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) { *timeout = 53; // very slow } @@ -606,7 +606,7 @@ int CmdHF14AMfNested(const char *Cmd) uint64_t key64 = 0; // timeout in units. (ms * 106)/10 or us*0.0106 uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default - + bool autosearchKey = false; bool transferToEml = false; @@ -647,14 +647,14 @@ int CmdHF14AMfNested(const char *Cmd) } else { SectorsCnt = ParamCardSizeSectors(cmdp); } - + // . number or autosearch key (*) if (param_getchar(Cmd, 1) == '*') { autosearchKey = true; parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } else { blockNo = param_get8(Cmd, 1); @@ -681,7 +681,7 @@ int CmdHF14AMfNested(const char *Cmd) } // one sector nested - if (cmdp == 'o') { + if (cmdp == 'o') { trgBlockNo = param_get8(Cmd, 4); ctmp = param_getchar(Cmd, 5); @@ -697,7 +697,7 @@ int CmdHF14AMfNested(const char *Cmd) parseParamTDS(Cmd, 4, &transferToEml, &createDumpFile, &btimeout14a); } - PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } @@ -721,9 +721,9 @@ int CmdHF14AMfNested(const char *Cmd) // transfer key to the emulator if (transferToEml) { uint8_t sectortrailer; - if (trgBlockNo < 32*4) { // 4 block sector + if (trgBlockNo < 32*4) { // 4 block sector sectortrailer = trgBlockNo | 0x03; - } else { // 16 block sector + } else { // 16 block sector sectortrailer = trgBlockNo | 0x0f; } mfEmlGetMem(keyBlock, sectortrailer, 1); @@ -753,7 +753,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, MifareDefaultKeysSize, keyBlock, e_sector); - + // get known key from array bool keyFound = false; if (autosearchKey) { @@ -769,7 +769,7 @@ int CmdHF14AMfNested(const char *Cmd) } } if (keyFound) break; - } + } // Can't found a key.... if (!keyFound) { @@ -810,7 +810,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Found valid key:%012" PRIx64, key64); e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = key64; - + // try to check this key as a key to the other sectors mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, 1, keyBlock, e_sector); } @@ -821,7 +821,7 @@ int CmdHF14AMfNested(const char *Cmd) // print nested statistic PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations); PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0); - + // print result PrintAndLog("|---|----------------|---|----------------|---|"); PrintAndLog("|sec|key A |res|key B |res|"); @@ -990,7 +990,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) i++; } } - + SetSIMDInstr(SIMD_AUTO); if (iindx > 0) { while ((ctmp = param_getchar(Cmd, iindx))) { @@ -1020,7 +1020,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) } } iindx++; - } + } } PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d ", @@ -1072,8 +1072,8 @@ int CmdHF14AMfChk(const char *Cmd) uint16_t stKeyBlock = 20; int i, res; - int keycnt = 0; - char ctmp = 0x00; + int keycnt = 0; + char ctmp = 0x00; int clen = 0; uint8_t blockNo = 0; uint8_t SectorsCnt = 0; @@ -1085,7 +1085,7 @@ int CmdHF14AMfChk(const char *Cmd) bool transferToEml = 0; bool createDumpFile = 0; - + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1123,12 +1123,12 @@ int CmdHF14AMfChk(const char *Cmd) } parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - + param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); - PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); - + for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) { if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) { if ( stKeyBlock - keycnt < 2) { @@ -1142,7 +1142,7 @@ int CmdHF14AMfChk(const char *Cmd) } PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); keycnt++; } else { // May be a dic file @@ -1159,7 +1159,7 @@ int CmdHF14AMfChk(const char *Cmd) while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - if( buf[0]=='#' ) continue; //The line start with # is comment, skip + if( buf[0]=='#' ) continue; //The line start with # is comment, skip if (!isxdigit((unsigned char)buf[0])){ PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf); @@ -1200,7 +1200,7 @@ int CmdHF14AMfChk(const char *Cmd) for (;keycnt < defaultKeysSize; keycnt++) PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } // initialize storage for found keys @@ -1245,7 +1245,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint32_t c = 0; c < keycnt; c+=max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; - res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); + res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); if (res != 1) { if (!res) { @@ -1258,7 +1258,7 @@ int CmdHF14AMfChk(const char *Cmd) } } while(--keyAB > 0); } - + // print result if (foundAKey) { if (SectorsCnt) { @@ -1275,8 +1275,8 @@ int CmdHF14AMfChk(const char *Cmd) } else { PrintAndLog(""); PrintAndLog("No valid keys found."); - } - + } + if (transferToEml) { uint8_t block[16]; for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { @@ -1320,7 +1320,7 @@ int CmdHF14AMfChk(const char *Cmd) void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { #define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim() - // cannot be more than 7 or it will overrun c.d.asBytes(512) + // cannot be more than 7 or it will overrun c.d.asBytes(512) uint64_t key = 0; typedef struct { uint64_t keyA; @@ -1329,7 +1329,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack st_t sector_trailer[ATTACK_KEY_COUNT]; memset(sector_trailer, 0x00, sizeof(sector_trailer)); - uint8_t stSector[ATTACK_KEY_COUNT]; + uint8_t stSector[ATTACK_KEY_COUNT]; memset(stSector, 0x00, sizeof(stSector)); uint8_t key_cnt[ATTACK_KEY_COUNT]; memset(key_cnt, 0x00, sizeof(key_cnt)); @@ -1392,7 +1392,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack if (setEmulatorMem) { for (uint8_t i = 0; i0) { - uint8_t memBlock[16]; + uint8_t memBlock[16]; memset(memBlock, 0x00, sizeof(memBlock)); char cmd1[36]; memset(cmd1,0x00,sizeof(cmd1)); @@ -1463,7 +1463,7 @@ int CmdHF14AMfSim(const char *Cmd) { while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) { - case '*': + case '*': cardsize = param_getchar(Cmd + 1, cmdp); switch(cardsize) { case '0': @@ -1580,7 +1580,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1615,7 +1615,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1951,31 +1951,37 @@ int CmdHF14AMfECFill(const char *Cmd) return 0; } + int CmdHF14AMfEKeyPrn(const char *Cmd) { int i; - uint8_t numSectors; + uint8_t numSectors = 16; uint8_t data[16]; uint64_t keyA, keyB; + bool createDumpFile = false; if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It prints the keys loaded in the emulator memory"); - PrintAndLog("Usage: hf mf ekeyprn [card memory]"); + PrintAndLog("Usage: hf mf ekeyprn [card memory] [d]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(" [d] : write keys to binary file dumpkeys.bin"); PrintAndLog(""); PrintAndLog(" sample: hf mf ekeyprn 1"); return 0; } - char cmdp = param_getchar(Cmd, 0); - - switch (cmdp) { - case '0' : numSectors = 5; break; - case '1' : - case '\0': numSectors = 16; break; - case '2' : numSectors = 32; break; - case '4' : numSectors = 40; break; - default: numSectors = 16; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (param_getchar(Cmd, cmdp)) { + case '0' : numSectors = 5; break; + case '1' : + case '\0': numSectors = 16; break; + case '2' : numSectors = 32; break; + case '4' : numSectors = 40; break; + case 'd' : + case 'D' : createDumpFile = true; break; + } + cmdp++; } PrintAndLog("|---|----------------|----------------|"); @@ -1992,9 +1998,35 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) } PrintAndLog("|---|----------------|----------------|"); + // Create dump file + if (createDumpFile) { + FILE *fkeys; + if ((fkeys = fopen("dumpkeys.bin","wb")) == NULL) { + PrintAndLog("Could not create file dumpkeys.bin"); + return 1; + } + PrintAndLog("Printing keys to binary file dumpkeys.bin..."); + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+6, 1, 6, fkeys); + } + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+10, 1, 6, fkeys); + } + fclose(fkeys); + } + return 0; } + int CmdHF14AMfCSetUID(const char *Cmd) { uint8_t uid[8] = {0x00}; @@ -2006,7 +2038,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) uint8_t needHelp = 0; char cmdp = 1; - + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) { PrintAndLog("UID must include 8 HEX symbols"); return 1; @@ -2015,12 +2047,12 @@ int CmdHF14AMfCSetUID(const char *Cmd) if (param_getlength(Cmd, 1) > 1 && param_getlength(Cmd, 2) > 1) { atqaPresent = 1; cmdp = 3; - + if (param_gethex(Cmd, 1, atqa, 4)) { PrintAndLog("ATQA must include 4 HEX symbols"); return 1; } - + if (param_gethex(Cmd, 2, sak, 2)) { PrintAndLog("SAK must include 2 HEX symbols"); return 1; @@ -2074,7 +2106,7 @@ int CmdHF14AMfCWipe(const char *Cmd) int numBlocks = 16 * 4; bool wipeCard = false; bool fillCard = false; - + if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf cwipe [card size] [w] [f]"); PrintAndLog("sample: hf mf cwipe 1 w f"); @@ -2085,9 +2117,9 @@ int CmdHF14AMfCWipe(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; - + numBlocks = ParamCardSizeBlocks(param_getchar(Cmd, 0)); char cmdp = 0; @@ -2107,7 +2139,7 @@ int CmdHF14AMfCWipe(const char *Cmd) cmdp++; } - if (!wipeCard && !fillCard) + if (!wipeCard && !fillCard) wipeCard = true; PrintAndLog("--blocks count:%2d wipe:%c fill:%c", numBlocks, (wipeCard)?'y':'n', (fillCard)?'y':'n'); @@ -2117,10 +2149,10 @@ int CmdHF14AMfCWipe(const char *Cmd) if (wipeCard) { PrintAndLog("WARNING: can't wipe magic card 1b generation"); } - res = mfCWipe(numBlocks, true, false, fillCard); + res = mfCWipe(numBlocks, true, false, fillCard); } else { /* generation 1a magic card by default */ - res = mfCWipe(numBlocks, false, wipeCard, fillCard); + res = mfCWipe(numBlocks, false, wipeCard, fillCard); } if (res) { @@ -2147,7 +2179,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; blockNo = param_get8(Cmd, 0); @@ -2213,9 +2245,9 @@ int CmdHF14AMfCLoad(const char *Cmd) PrintAndLog("Cant get block: %d", blockNum); return 2; } - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2265,9 +2297,9 @@ int CmdHF14AMfCLoad(const char *Cmd) for (i = 0; i < 32; i += 2) sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2326,7 +2358,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLog("block data:%s", sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(blockNo)) { PrintAndLogEx(NORMAL, "Trailer decoded:"); PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); @@ -2339,7 +2371,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); } - + return 0; } @@ -2390,19 +2422,19 @@ int CmdHF14AMfCGetSc(const char *Cmd) { } PrintAndLog("block %3d data:%s", baseblock + i, sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(baseblock + i)) { - PrintAndLogEx(NORMAL, "Trailer decoded:"); - PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); - PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); - int bln = baseblock; - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); - } + PrintAndLogEx(NORMAL, "Trailer decoded:"); + PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); + PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); + int bln = baseblock; + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); + } } return 0; } @@ -2599,17 +2631,17 @@ int CmdHF14AMfSniff(const char *Cmd){ uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; - if (res == 0) { // we are done + if (res == 0) { // we are done break; } - if (res == 1) { // there is (more) data to be transferred - if (pckNum == 0) { // first packet, (re)allocate necessary buffer + if (res == 1) { // there is (more) data to be transferred + if (pckNum == 0) { // first packet, (re)allocate necessary buffer if (traceLen > bufsize || buf == NULL) { uint8_t *p; - if (buf == NULL) { // not yet allocated + if (buf == NULL) { // not yet allocated p = malloc(traceLen); - } else { // need more memory + } else { // need more memory p = realloc(buf, traceLen); } if (p == NULL) { @@ -2628,13 +2660,13 @@ int CmdHF14AMfSniff(const char *Cmd){ pckNum++; } - if (res == 2) { // received all data, start displaying + if (res == 2) { // received all data, start displaying blockLen = bufPtr - buf; bufPtr = buf; printf(">\n"); PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); while (bufPtr - buf < blockLen) { - bufPtr += 6; // skip (void) timing information + bufPtr += 6; // skip (void) timing information len = *((uint16_t *)bufPtr); if(len & 0x8000) { isTag = true; @@ -2662,11 +2694,11 @@ int CmdHF14AMfSniff(const char *Cmd){ mfTraceInit(uid, atqa, sak, wantSaveToEmlFile); } else { oddparitybuf(bufPtr, len, parity); - PrintAndLog("%s(%d):%s [%s] c[%s]%c", - isTag ? "TAG":"RDR", - num, - sprint_hex(bufPtr, len), - printBitsPar(bufPtr + len, len), + PrintAndLog("%s(%d):%s [%s] c[%s]%c", + isTag ? "TAG":"RDR", + num, + sprint_hex(bufPtr, len), + printBitsPar(bufPtr + len, len), printBitsPar(parity, len), memcmp(bufPtr + len, parity, len / 8 + 1) ? '!' : ' '); if (wantLogToFile) @@ -2676,7 +2708,7 @@ int CmdHF14AMfSniff(const char *Cmd){ num++; } bufPtr += len; - bufPtr += parlen; // ignore parity + bufPtr += parlen; // ignore parity } pckNum = 0; } @@ -2684,7 +2716,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } // while (true) free(buf); - + msleep(300); // wait for exiting arm side. PrintAndLog("Done."); return 0; @@ -2704,8 +2736,8 @@ int CmdHF14AMfAuth4(const char *cmd) { uint8_t key[16] = {0}; int keylen = 0; - CLIParserInit("hf mf auth4", - "Executes AES authentication command in ISO14443-4", + CLIParserInit("hf mf auth4", + "Executes AES authentication command in ISO14443-4", "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "\thf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); @@ -2716,16 +2748,16 @@ int CmdHF14AMfAuth4(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + CLIGetHexWithReturn(1, keyn, &keynlen); CLIGetHexWithReturn(2, key, &keylen); CLIParserFree(); - + if (keynlen != 2) { PrintAndLog("ERROR: must be 2 bytes long instead of: %d", keynlen); return 1; } - + if (keylen != 16) { PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); return 1; @@ -2737,196 +2769,196 @@ int CmdHF14AMfAuth4(const char *cmd) { // https://www.nxp.com/docs/en/application-note/AN10787.pdf int CmdHF14AMfMAD(const char *cmd) { - CLIParserInit("hf mf mad", - "Checks and prints Mifare Application Directory (MAD)", - "Usage:\n\thf mf mad -> shows MAD if exists\n" - "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); + CLIParserInit("hf mf mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); - void *argtable[] = { - arg_param_begin, - arg_lit0("vV", "verbose", "show technical data"), - arg_str0("aA", "aid", "print all sectors with aid", NULL), - arg_str0("kK", "key", "key for printing sectors", NULL), - arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - bool verbose = arg_get_lit(1); - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); + void *argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); - CLIParserFree(); + CLIParserFree(); - if (aidlen != 2 && keylen > 0) { - PrintAndLogEx(WARNING, "do not need a key without aid."); - } + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - if (verbose) { - for (int i = 0; i < 4; i ++) - PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); - } + if (verbose) { + for (int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } - bool haveMAD2 = false; - MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - MAD2DecodeAndPrint(sector10, verbose); - } + MAD2DecodeAndPrint(sector10, verbose); + } - if (aidlen == 2) { - uint16_t aaid = (aid[0] << 8) + aid[1]; - PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, sector10, mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } - uint8_t akey[6] = {0}; - memcpy(akey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(akey, key, 6); - } + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } - for (int i = 0; i < madlen; i++) { - if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } - for (int j = 0; j < (verbose ? 4 : 3); j ++) - PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); - } - } - } + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } - return 0; + return 0; } int CmdHFMFNDEF(const char *cmd) { - CLIParserInit("hf mf ndef", - "Prints NFC Data Exchange Format (NDEF)", - "Usage:\n\thf mf ndef -> shows NDEF data\n" - "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); + CLIParserInit("hf mf ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\thf mf ndef -> shows NDEF data\n" + "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); - void *argtable[] = { - arg_param_begin, - arg_litn("vV", "verbose", 0, 2, "show technical data"), - arg_str0("aA", "aid", "replace default aid for NDEF", NULL), - arg_str0("kK", "key", "replace default key for NDEF", NULL), - arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); + void *argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show technical data"), + arg_str0("aA", "aid", "replace default aid for NDEF", NULL), + arg_str0("kK", "key", "replace default key for NDEF", NULL), + arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); - bool verbose = arg_get_lit(1); - bool verbose2 = arg_get_lit(1) > 1; - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); - CLIParserFree(); + CLIParserFree(); - uint16_t ndefAID = 0x03e1; - if (aidlen == 2) - ndefAID = (aid[0] << 8) + aid[1]; + uint16_t ndefAID = 0x03e1; + if (aidlen == 2) + ndefAID = (aid[0] << 8) + aid[1]; - uint8_t ndefkey[6] = {0}; - memcpy(ndefkey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(ndefkey, key, 6); - } + uint8_t ndefkey[6] = {0}; + memcpy(ndefkey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(ndefkey, key, 6); + } - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - uint8_t data[4096] = {0}; - int datalen = 0; + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + uint8_t data[4096] = {0}; + int datalen = 0; - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, ""); - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - bool haveMAD2 = false; - int res = MADCheck(sector0, NULL, verbose, &haveMAD2); - if (res) { - PrintAndLogEx(ERR, "MAD error %d.", res); - return res; - } + bool haveMAD2 = false; + int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + if (res) { + PrintAndLogEx(ERR, "MAD error %d.", res); + return res; + } - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - } + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + } - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } - printf("data reading:"); - for (int i = 0; i < madlen; i++) { - if (ndefAID == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } + printf("data reading:"); + for (int i = 0; i < madlen; i++) { + if (ndefAID == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } - memcpy(&data[datalen], vsector, 16 * 3); - datalen += 16 * 3; + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; - printf("."); - } - } - printf(" OK\n"); + printf("."); + } + } + printf(" OK\n"); - if (!datalen) { - PrintAndLogEx(ERR, "no NDEF data."); - return 11; - } + if (!datalen) { + PrintAndLogEx(ERR, "no NDEF data."); + return 11; + } - if (verbose2) { - PrintAndLogEx(NORMAL, "NDEF data:"); - dump_buffer(data, datalen, stdout, 1); - } + if (verbose2) { + PrintAndLogEx(NORMAL, "NDEF data:"); + dump_buffer(data, datalen, stdout, 1); + } - NDEFDecodeAndPrint(data, datalen, verbose); + NDEFDecodeAndPrint(data, datalen, verbose); - return 0; + return 0; } static command_t CommandTable[] = @@ -2936,7 +2968,7 @@ static command_t CommandTable[] = {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, - {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, + {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, {"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"}, {"chk", CmdHF14AMfChk, 0, "Test block keys"}, From 2378bb24c3d4ce21d71b4ab5739c58a9979b8b69 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:57:40 +0200 Subject: [PATCH 03/29] fix compiler warning in cmdhflegic.c (and whitespace fixes) (#826) --- client/cmdhflegic.c | 570 ++++++++++++++++++++++---------------------- 1 file changed, 286 insertions(+), 284 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 66e8ebb1..14942017 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -22,29 +22,29 @@ static int CmdHelp(const char *Cmd); -static command_t CommandTable[] = +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, - {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, - {"save", CmdLegicSave, 0, " [] -- Store samples"}, - {"load", CmdLegicLoad, 0, " -- Restore samples"}, - {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, - {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, - {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, + {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, + {"save", CmdLegicSave, 0, " [] -- Store samples"}, + {"load", CmdLegicLoad, 0, " -- Restore samples"}, + {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, + {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, + {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, + {NULL, NULL, 0, NULL} }; int CmdHFLegic(const char *Cmd) { - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable); + return 0; } /* @@ -54,189 +54,191 @@ int CmdHelp(const char *Cmd) */ int CmdLegicDecode(const char *Cmd) { - int i, j, k, n; - int segment_len = 0; - int segment_flag = 0; - int stamp_len = 0; - int crc = 0; - int wrp = 0; - int wrc = 0; - uint8_t data_buf[1053]; // receiver buffer - char out_string[3076]; // just use big buffer - bad practice - char token_type[4]; - - // copy data from proxmark into buffer - GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); - - // Output CDF System area (9 bytes) plus remaining header area (12 bytes) - - PrintAndLog("\nCDF: System Area"); - - PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", - data_buf[0], - data_buf[1], - data_buf[2], - data_buf[3], - data_buf[4] - ); - - crc = data_buf[4]; - - switch (data_buf[5]&0x7f) { - case 0x00 ... 0x2f: - strncpy(token_type, "IAM",sizeof(token_type)); - break; - case 0x30 ... 0x6f: - strcpy(token_type, "SAM"); - break; - case 0x70 ... 0x7f: - strcpy(token_type, "GAM"); - break; - default: - strcpy(token_type, "???"); - break; - } - - stamp_len = 0xfc - data_buf[6]; - - PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", - data_buf[5], - data_buf[6], - token_type, - (data_buf[5]&0x80)>>7, - stamp_len - ); - - PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", - data_buf[7]&0x0f, - (data_buf[7]&0x70)>>4, - (data_buf[7]&0x80)>>7, - data_buf[7], - data_buf[8] - ); - - PrintAndLog("Remaining Header Area"); - - PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - data_buf[9], - data_buf[10], - data_buf[11], - data_buf[12], - data_buf[13], - data_buf[14], - data_buf[15], - data_buf[16], - data_buf[17], - data_buf[18], - data_buf[19], - data_buf[20], - data_buf[21] - ); - - PrintAndLog("\nADF: User Area"); - - i = 22; - for (n=0; n<64; n++) { - segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); - segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; - - wrp = (data_buf[i+2]^crc); - wrc = ((data_buf[i+3]^crc)&0x70)>>4; - - PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", - n, - data_buf[i]^crc, - data_buf[i+1]^crc, - data_buf[i+2]^crc, - data_buf[i+3]^crc, - segment_flag, - (segment_flag&0x4)>>2, - (segment_flag&0x8)>>3, - segment_len, - wrp, - wrc, - ((data_buf[i+3]^crc)&0x80)>>7, - (data_buf[i+4]^crc) - ); - - i+=5; - - if (wrc>0) { - PrintAndLog("WRC protected area:"); - for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - } - - if (wrp>wrc) { - PrintAndLog("Remaining write protected area:"); - - for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - if((wrp-wrc) == 8) { - sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); - PrintAndLog("%s", out_string); - } - } - - PrintAndLog("Remaining segment payload:"); - for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - - // end with last segment - if (segment_flag & 0x8) - return 0; - }; - return 0; + int i, j, k, n; + int segment_len = 0; + int segment_flag = 0; + int stamp_len = 0; + int crc = 0; + int wrp = 0; + int wrc = 0; + uint8_t data_buf[1053]; // receiver buffer + char out_string[3076]; // just use big buffer - bad practice + char token_type[4]; + + // copy data from proxmark into buffer + GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); + + // Output CDF System area (9 bytes) plus remaining header area (12 bytes) + + PrintAndLog("\nCDF: System Area"); + + PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", + data_buf[0], + data_buf[1], + data_buf[2], + data_buf[3], + data_buf[4] + ); + + crc = data_buf[4]; + + switch (data_buf[5]&0x7f) { + case 0x00 ... 0x2f: + strncpy(token_type, "IAM",sizeof(token_type)); + break; + case 0x30 ... 0x6f: + strcpy(token_type, "SAM"); + break; + case 0x70 ... 0x7f: + strcpy(token_type, "GAM"); + break; + default: + strcpy(token_type, "???"); + break; + } + + stamp_len = 0xfc - data_buf[6]; + + PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", + data_buf[5], + data_buf[6], + token_type, + (data_buf[5]&0x80)>>7, + stamp_len + ); + + PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", + data_buf[7]&0x0f, + (data_buf[7]&0x70)>>4, + (data_buf[7]&0x80)>>7, + data_buf[7], + data_buf[8] + ); + + PrintAndLog("Remaining Header Area"); + + PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + data_buf[9], + data_buf[10], + data_buf[11], + data_buf[12], + data_buf[13], + data_buf[14], + data_buf[15], + data_buf[16], + data_buf[17], + data_buf[18], + data_buf[19], + data_buf[20], + data_buf[21] + ); + + PrintAndLog("\nADF: User Area"); + + i = 22; + for (n=0; n<64; n++) { + segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); + segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; + + wrp = (data_buf[i+2]^crc); + wrc = ((data_buf[i+3]^crc)&0x70)>>4; + + PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", + n, + data_buf[i]^crc, + data_buf[i+1]^crc, + data_buf[i+2]^crc, + data_buf[i+3]^crc, + segment_flag, + (segment_flag&0x4)>>2, + (segment_flag&0x8)>>3, + segment_len, + wrp, + wrc, + ((data_buf[i+3]^crc)&0x80)>>7, + (data_buf[i+4]^crc) + ); + + i+=5; + + if (wrc>0) { + PrintAndLog("WRC protected area:"); + for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + } + + if (wrp>wrc) { + PrintAndLog("Remaining write protected area:"); + + for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + if((wrp-wrc) == 8) { + sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); + PrintAndLog("%s", out_string); + } + } + + PrintAndLog("Remaining segment payload:"); + for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + + // end with last segment + if (segment_flag & 0x8) + return 0; + }; + return 0; } int CmdLegicRFRead(const char *Cmd) { - int byte_count=0,offset=0; - sscanf(Cmd, "%i %i", &offset, &byte_count); - if(byte_count == 0) byte_count = -1; - if(byte_count + offset > 1024) byte_count = 1024 - offset; - UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - switch (resp.arg[0]) { - case 0: - PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", ((legic_card_select_t*)resp.d.asBytes)->cardsize); - PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); - break; - case 1: - PrintAndLog("No or unknown card found, aborting"); - break; - case 2: - PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); - break; - } - return resp.arg[0]; + int byte_count=0,offset=0; + sscanf(Cmd, "%i %i", &offset, &byte_count); + if(byte_count == 0) byte_count = -1; + if(byte_count + offset > 1024) byte_count = 1024 - offset; + UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; + SendCommand(&c); + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + switch (resp.arg[0]) { + legic_card_select_t card; + case 0: + memcpy(&card, resp.d.asBytes, sizeof(card)); + PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); + PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); + break; + case 1: + PrintAndLog("No or unknown card found, aborting"); + break; + case 2: + PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); + break; + } + return resp.arg[0]; } int CmdLegicLoad(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0x00}; int len = 0; - + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { PrintAndLog("It loads datasamples from the file `filename`"); PrintAndLog("Usage: hf legic load "); @@ -244,92 +246,92 @@ int CmdLegicLoad(const char *Cmd) return 0; } - len = strlen(Cmd); + len = strlen(Cmd); if (len > FILE_PATH_SIZE) { PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE); return 0; } memcpy(filename, Cmd, len); - FILE *f = fopen(filename, "r"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd); - return -1; - } - char line[80]; int offset = 0; unsigned int data[8]; - while(fgets(line, sizeof(line), f)) { - int res = sscanf(line, "%x %x %x %x %x %x %x %x", - &data[0], &data[1], &data[2], &data[3], - &data[4], &data[5], &data[6], &data[7]); - if(res != 8) { - PrintAndLog("Error: could not read samples"); - fclose(f); - return -1; - } - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; - int j; for(j = 0; j < 8; j++) { - c.d.asBytes[j] = data[j]; - } - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - offset += 8; - } - fclose(f); - PrintAndLog("loaded %u samples", offset); - return 0; + FILE *f = fopen(filename, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return -1; + } + char line[80]; int offset = 0; unsigned int data[8]; + while (fgets(line, sizeof(line), f)) { + int res = sscanf(line, "%x %x %x %x %x %x %x %x", + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7]); + if (res != 8) { + PrintAndLog("Error: could not read samples"); + fclose(f); + return -1; + } + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; + int j; for(j = 0; j < 8; j++) { + c.d.asBytes[j] = data[j]; + } + SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + offset += 8; + } + fclose(f); + PrintAndLog("loaded %u samples", offset); + return 0; } int CmdLegicSave(const char *Cmd) { - int requested = 1024; - int offset = 0; - int delivered = 0; - char filename[FILE_PATH_SIZE]; - uint8_t got[1024]; - - sscanf(Cmd, " %s %i %i", filename, &requested, &offset); + int requested = 1024; + int offset = 0; + int delivered = 0; + char filename[FILE_PATH_SIZE]; + uint8_t got[1024]; - /* If no length given save entire legic read buffer */ - /* round up to nearest 8 bytes so the saved data can be used with legicload */ - if (requested == 0) { - requested = 1024; - } - if (requested % 8 != 0) { - int remainder = requested % 8; - requested = requested + 8 - remainder; - } - if (offset + requested > sizeof(got)) { - PrintAndLog("Tried to read past end of buffer, + > 1024"); - return 0; - } - - FILE *f = fopen(filename, "w"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd+1); - return -1; - } + sscanf(Cmd, " %s %i %i", filename, &requested, &offset); - GetFromBigBuf(got, requested, offset, NULL, -1, false); + /* If no length given save entire legic read buffer */ + /* round up to nearest 8 bytes so the saved data can be used with legicload */ + if (requested == 0) { + requested = 1024; + } + if (requested % 8 != 0) { + int remainder = requested % 8; + requested = requested + 8 - remainder; + } + if (offset + requested > sizeof(got)) { + PrintAndLog("Tried to read past end of buffer, + > 1024"); + return 0; + } - for (int j = 0; j < requested; j += 8) { - fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", - got[j+0], - got[j+1], - got[j+2], - got[j+3], - got[j+4], - got[j+5], - got[j+6], - got[j+7] - ); - delivered += 8; - if (delivered >= requested) - break; - } + FILE *f = fopen(filename, "w"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd+1); + return -1; + } - fclose(f); - PrintAndLog("saved %u samples", delivered); - return 0; + GetFromBigBuf(got, requested, offset, NULL, -1, false); + + for (int j = 0; j < requested; j += 8) { + fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", + got[j+0], + got[j+1], + got[j+2], + got[j+3], + got[j+4], + got[j+5], + got[j+6], + got[j+7] + ); + delivered += 8; + if (delivered >= requested) + break; + } + + fclose(f); + PrintAndLog("saved %u samples", delivered); + return 0; } int CmdLegicRfSim(const char *Cmd) @@ -343,36 +345,36 @@ int CmdLegicRfSim(const char *Cmd) int CmdLegicRfWrite(const char *Cmd) { - UsbCommand c={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); - if(res != 2) { + UsbCommand c={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); + if (res != 2) { PrintAndLog("Please specify the offset and length as two hex strings"); - return -1; - } - SendCommand(&c); - return 0; + return -1; + } + SendCommand(&c); + return 0; } int CmdLegicRfFill(const char *Cmd) { - UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); - if(res != 3) { - PrintAndLog("Please specify the offset, length and value as two hex strings"); - return -1; - } + UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); + if (res != 3) { + PrintAndLog("Please specify the offset, length and value as two hex strings"); + return -1; + } - int i; - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; - for(i = 0; i < 48; i++) { - c.d.asBytes[i] = cmd.arg[2]; - } - for(i = 0; i < 22; i++) { - c.arg[0] = i*48; - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - } - SendCommand(&cmd); - return 0; + int i; + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; + for (i = 0; i < 48; i++) { + c.d.asBytes[i] = cmd.arg[2]; + } + for (i = 0; i < 22; i++) { + c.arg[0] = i*48; + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + } + SendCommand(&cmd); + return 0; } From 5f18b0c45dba436e05df637b1b91137ab68cbefb Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:58:09 +0200 Subject: [PATCH 04/29] add: Home (Pos1) and End key bindings in graph GUI (based on @mcd1992 change on RRG repo) (#823) --- CHANGELOG.md | 1 + client/proxguiqt.cpp | 37 ++++++++++++++++++++++++------------- client/proxguiqt.h | 14 +++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8ee1fe..399f87f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) +- Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) ## [v3.1.0][2018-10-10] diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index 30e4c8de..cda90cc0 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -34,8 +34,8 @@ extern "C" { bool g_useOverlays = false; int g_absVMax = 0; -int startMax; -int PageWidth; +int startMax; // Maximum offset in the graph (right side of graph) +int PageWidth; // How many samples are currently visible on this 'page' / graph int unlockStart = 0; void ProxGuiQT::ShowGraphWindow(void) @@ -134,8 +134,8 @@ ProxGuiQT::~ProxGuiQT(void) { //if (plotwidget) { //plotwidget->destroy(true,true); - // delete plotwidget; - // plotwidget = NULL; + // delete plotwidget; + // plotwidget = NULL; //} if (plotapp) { plotapp->quit(); @@ -474,7 +474,7 @@ void Plot::plotGridLines(QPainter* painter,QRect r) if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) { for(i = (offset * GraphPixelsPerPoint); i < r.right(); i += grid_delta_x) { painter->drawLine(r.left()+i, r.top(), r.left()+i, r.bottom()); - } + } } if (PlotGridY > 0) { for(i = 0; yCoordOf(i,r,g_absVMax) > r.top(); i += grid_delta_y) { @@ -509,8 +509,9 @@ void Plot::paintEvent(QPaintEvent *event) if(CursorDPos > GraphTraceLen) CursorDPos= 0; - QRect plotRect(WIDTH_AXES, 0, width()-WIDTH_AXES, height()-HEIGHT_INFO); - QRect infoRect(0, height()-HEIGHT_INFO, width(), HEIGHT_INFO); + QRect plotRect(WIDTH_AXES, 0, width() - WIDTH_AXES, height() - HEIGHT_INFO); + QRect infoRect(0, height() - HEIGHT_INFO, width(), HEIGHT_INFO); + PageWidth = plotRect.width() / GraphPixelsPerPoint; //Grey background painter.fillRect(rect(), QColor(60, 60, 60)); @@ -529,7 +530,7 @@ void Plot::paintEvent(QPaintEvent *event) //Start painting graph PlotGraph(GraphBuffer, GraphTraceLen,plotRect,infoRect,&painter,0); - if (showDemod && DemodBufferLen > 8) { + if (showDemod && DemodBufferLen > 8) { PlotDemod(DemodBuffer, DemodBufferLen,plotRect,infoRect,&painter,2,g_DemodStartIdx); } if (g_useOverlays) { @@ -564,7 +565,7 @@ void Plot::paintEvent(QPaintEvent *event) //Draw annotations char str[200]; sprintf(str, "@%d dt=%d [%2.2f] zoom=%2.2f CursorAPos=%d CursorBPos=%d GridX=%d GridY=%d (%s) GridXoffset=%d", - GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, + GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, GraphPixelsPerPoint,CursorAPos,CursorBPos,PlotGridXdefault,PlotGridYdefault,GridLocked?"Locked":"Unlocked",GridOffset); painter.setPen(QColor(255, 255, 255)); painter.drawText(20, infoRect.bottom() - 3, str); @@ -616,14 +617,14 @@ void Plot::mouseMoveEvent(QMouseEvent *event) void Plot::keyPressEvent(QKeyEvent *event) { - int offset; + int offset; // Left/right movement offset (in sample size) if(event->modifiers() & Qt::ShiftModifier) { if (PlotGridX) offset= PageWidth - (PageWidth % PlotGridX); else offset= PageWidth; - } else + } else if(event->modifiers() & Qt::ControlModifier) offset= 1; else @@ -671,20 +672,22 @@ void Plot::keyPressEvent(QKeyEvent *event) case Qt::Key_H: puts("Plot Window Keystrokes:\n"); puts(" Key Action\n"); + puts(" UP Zoom out"); puts(" DOWN Zoom in"); puts(" G Toggle grid display"); puts(" H Show help"); puts(" L Toggle lock grid relative to samples"); + puts(" Q Hide window"); + puts(" HOME Move to the start of the graph"); + puts(" END Move to the end of the graph"); puts(" LEFT Move left"); puts(" LEFT Move left 1 sample"); puts(" LEFT Page left"); puts(" LEFT-MOUSE-CLICK Set yellow cursor"); - puts(" Q Hide window"); puts(" RIGHT Move right"); puts(" RIGHT Move right 1 sample"); puts(" RIGHT Page right"); puts(" RIGHT-MOUSE-CLICK Set purple cursor"); - puts(" UP Zoom out"); puts(""); puts("Use client window 'data help' for more plot commands\n"); break; @@ -701,6 +704,14 @@ void Plot::keyPressEvent(QKeyEvent *event) master->hide(); break; + case Qt::Key_Home: + GraphStart = 0; + break; + + case Qt::Key_End: + GraphStart = startMax; + break; + default: QWidget::keyPressEvent(event); return; diff --git a/client/proxguiqt.h b/client/proxguiqt.h index 5f7199fc..9677b49c 100644 --- a/client/proxguiqt.h +++ b/client/proxguiqt.h @@ -29,8 +29,8 @@ class Plot: public QWidget { private: QWidget *master; - int GraphStart; - double GraphPixelsPerPoint; + int GraphStart; // Starting point/offset for the left side of the graph + double GraphPixelsPerPoint; // How many visual pixels are between each sample point (x axis) int CursorAPos; int CursorBPos; void PlotGraph(int *buffer, int len, QRect r,QRect r2, QPainter* painter, int graphNum); @@ -73,13 +73,13 @@ class ProxWidget : public QWidget //OpsShow(void); protected: - // void paintEvent(QPaintEvent *event); + // void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); - // void mouseMoveEvent(QMouseEvent *event); - // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } - // void keyPressEvent(QKeyEvent *event); + // void mouseMoveEvent(QMouseEvent *event); + // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } + // void keyPressEvent(QKeyEvent *event); public slots: void applyOperation(); void stickOperation(); @@ -111,7 +111,7 @@ class ProxGuiQT : public QObject int argc; char **argv; WorkerThread *proxmarkThread; - + public: ProxGuiQT(int argc, char **argv, WorkerThread *wthread); ~ProxGuiQT(void); From 4be9f36ebe31c2ade9754518f848db754a5d0e26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:48:55 +0200 Subject: [PATCH 05/29] start updating 'hf mfu' commands (#818) * use PrintAndLogEx() * fix some printouts * some #include refactoring * whitespace --- client/cmdhf14a.h | 13 +- client/cmdhficlass.c | 1 + client/cmdhfmf.c | 1 + client/cmdhfmf.h | 32 -- client/cmdhfmfu.c | 839 +++++++++++++++++++++++-------------------- client/cmdhfmfu.h | 52 +-- client/util.c | 6 +- client/util.h | 1 + 8 files changed, 464 insertions(+), 481 deletions(-) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index c4294b4c..d1669f3a 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -16,13 +16,14 @@ #include #include "mifare.h" -int CmdHF14A(const char *Cmd); -int CmdHF14AList(const char *Cmd); -int CmdHF14AMifare(const char *Cmd); -int CmdHF14AReader(const char *Cmd); +extern int CmdHF14A(const char *Cmd); +extern int CmdHF14AMfDbg(const char* cmd); +extern int CmdHF14AList(const char *Cmd); +extern int CmdHF14AMifare(const char *Cmd); +extern int CmdHF14AReader(const char *Cmd); extern int CmdHF14AInfo(const char *Cmd); -int CmdHF14ASim(const char *Cmd); -int CmdHF14ASnoop(const char *Cmd); +extern int CmdHF14ASim(const char *Cmd); +extern int CmdHF14ASnoop(const char *Cmd); extern void DropField(); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 55804cf8..a2e31754 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -33,6 +33,7 @@ #include "usb_cmd.h" #include "cmdhfmfu.h" #include "util_posix.h" +#include "cmdhf14a.h" // DropField() static int CmdHelp(const char *Cmd); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 9284d14c..38b7f988 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -29,6 +29,7 @@ #include "hardnested/hardnested_bf_core.h" #include "cliparser/cliparser.h" #include "cmdhf14a.h" +#include "mifare/mifaredefault.h" #include "mifare/mifare4.h" #include "mifare/mad.h" #include "mifare/ndef.h" diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 746fcbc1..d7c981f4 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -11,38 +11,6 @@ #ifndef CMDHFMF_H__ #define CMDHFMF_H__ -#include "mifare/mifaredefault.h" - extern int CmdHFMF(const char *Cmd); -extern int CmdHFMF(const char *Cmd); - -extern int CmdHF14AMfDbg(const char* cmd); -extern int CmdHF14AMfRdBl(const char* cmd); -extern int CmdHF14AMfURdBl(const char* cmd); -extern int CmdHF14AMfRdSc(const char* cmd); -extern int CmdHF14SMfURdCard(const char* cmd); -extern int CmdHF14AMfDump(const char* cmd); -extern int CmdHF14AMfRestore(const char* cmd); -extern int CmdHF14AMfWrBl(const char* cmd); -extern int CmdHF14AMfUWrBl(const char* cmd); -extern int CmdHF14AMfChk(const char* cmd); -extern int CmdHF14AMifare(const char* cmd); -extern int CmdHF14AMfNested(const char* cmd); -extern int CmdHF14AMfSniff(const char* cmd); -extern int CmdHF14AMf1kSim(const char* cmd); -extern int CmdHF14AMfEClear(const char* cmd); -extern int CmdHF14AMfEGet(const char* cmd); -extern int CmdHF14AMfESet(const char* cmd); -extern int CmdHF14AMfELoad(const char* cmd); -extern int CmdHF14AMfESave(const char* cmd); -extern int CmdHF14AMfECFill(const char* cmd); -extern int CmdHF14AMfEKeyPrn(const char* cmd); -extern int CmdHF14AMfCWipe(const char* cmd); -extern int CmdHF14AMfCSetUID(const char* cmd); -extern int CmdHF14AMfCSetBlk(const char* cmd); -extern int CmdHF14AMfCGetBlk(const char* cmd); -extern int CmdHF14AMfCGetSc(const char* cmd); -extern int CmdHF14AMfCLoad(const char* cmd); -extern int CmdHF14AMfCSave(const char* cmd); #endif diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 9bdc6ce3..dac51be3 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -18,11 +18,39 @@ #include "ui.h" #include "mbedtls/des.h" #include "cmdhfmf.h" +#include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" #include "protocols.h" #include "taginfo.h" +typedef enum TAGTYPE_UL { + UNKNOWN = 0x000000, + UL = 0x000001, + UL_C = 0x000002, + UL_EV1_48 = 0x000004, + UL_EV1_128 = 0x000008, + NTAG = 0x000010, + NTAG_203 = 0x000020, + NTAG_210 = 0x000040, + NTAG_212 = 0x000080, + NTAG_213 = 0x000100, + NTAG_215 = 0x000200, + NTAG_216 = 0x000400, + MY_D = 0x000800, + MY_D_NFC = 0x001000, + MY_D_MOVE = 0x002000, + MY_D_MOVE_NFC = 0x004000, + MY_D_MOVE_LEAN= 0x008000, + NTAG_I2C_1K = 0x010000, + NTAG_I2C_2K = 0x020000, + FUDAN_UL = 0x040000, + MAGIC = 0x080000, + UL_MAGIC = UL | MAGIC, + UL_C_MAGIC = UL_C | MAGIC, + UL_ERROR = 0xFFFFFF, +} TagTypeUL_t; + #define MAX_UL_BLOCKS 0x0f #define MAX_ULC_BLOCKS 0x2b #define MAX_ULEV1a_BLOCKS 0x13 @@ -37,57 +65,63 @@ #define MAX_MY_D_MOVE 0x25 #define MAX_MY_D_MOVE_LEAN 0x0f +#define PUBLIC_ECDA_KEYLEN 33 +static uint8_t public_ecda_key[PUBLIC_ECDA_KEYLEN] = { + 0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c, + 0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49, + 0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39, + 0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, + 0x61 +}; + #define KEYS_3DES_COUNT 7 -uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { - { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F - { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key - { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF - { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 +static uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { + { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes + { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F + { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones + { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF + { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 }; #define KEYS_PWD_COUNT 6 -uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { +static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0xFF,0xFF,0xFF,0xFF}, // PACK 0x00,0x00 -- factory default - {0x4A,0xF8,0x4B,0x19}, // PACK 0xE5,0xBE -- italian bus (sniffed) {0x33,0x6B,0xA1,0x19}, // PACK 0x9c,0x2d -- italian bus (sniffed) - {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) + {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) {0x46,0x1c,0xA3,0x19}, // PACK 0xE9,0x5A -- italian bus (sniffed) {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; #define MAX_UL_TYPES 18 -uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; +static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; -uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, - MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; +static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, + MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; -static int CmdHelp(const char *Cmd); - -// get version nxp product type -char *getProductTypeStr( uint8_t id){ +// get version nxp product type +static char *getProductTypeStr( uint8_t id){ static char buf[20]; char *retStr = buf; switch(id) { case 3: sprintf(retStr, "%02X, Ultralight", id); break; - case 4: sprintf(retStr, "%02X, NTAG", id); break; + case 4: sprintf(retStr, "%02X, NTAG", id); break; default: sprintf(retStr, "%02X, unknown", id); break; } return buf; } /* - The 7 MSBits (=n) code the storage size itself based on 2^n, + The 7 MSBits (=n) code the storage size itself based on 2^n, the LSBit is set to '0' if the size is exactly 2^n - and set to '1' if the storage size is between 2^n and 2^(n+1). + and set to '1' if the storage size is between 2^n and 2^(n+1). */ char *getUlev1CardSizeStr( uint8_t fsize ){ @@ -101,8 +135,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ // is LSB set? if ( fsize & 1 ) sprintf(retStr, "%02X, (%u <-> %u bytes)",fsize, usize, lsize); - else - sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); + else + sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); return buf; } @@ -131,7 +165,7 @@ static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, if (append_crc) c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); + memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -151,7 +185,7 @@ static int ul_select( iso14a_card_select_t *card ){ bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); if (!ans || resp.arg[0] < 1) { - PrintAndLog("iso14443a card select failed"); + PrintAndLogEx(WARNING, "iso14443a card select failed"); DropField(); return 0; } @@ -217,7 +251,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if ( hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLog("Error: Authentication Failed UL-C"); + PrintAndLogEx(WARNING, "Authentication Failed UL-C"); return 0; } } else { @@ -226,7 +260,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { DropField(); - PrintAndLog("Error: Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -236,15 +270,15 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; + uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } // static int ulev1_fastRead( uint8_t startblock, uint8_t endblock, uint8_t *response ){ - + // uint8_t cmd[] = {MIFARE_ULEV1_FASTREAD, startblock, endblock}; - + // if ( !ul_send_cmd_raw(cmd, sizeof(cmd), response)){ // return -1; // } @@ -276,7 +310,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // Fudan check checks for which error is given for a command with incorrect crc // NXP UL chip responds with 01, fudan 00. // other possible checks: -// send a0 + crc +// send a0 + crc // UL responds with 00, fudan doesn't respond // or // send a200 + crc @@ -288,7 +322,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // make sure field is off before calling this function static int ul_fudan_check( void ){ iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -315,39 +349,43 @@ static int ul_print_default( uint8_t *data){ uid[5] = data[6]; uid[6] = data[7]; - PrintAndLog(" UID : %s ", sprint_hex(uid, 7)); - PrintAndLog(" UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); + PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ - case 0xc2: PrintAndLog(" IC type : SLE 66R04P 770 Bytes"); break; //77 pages - case 0xc4: PrintAndLog(" IC type : SLE 66R16P 2560 Bytes"); break; //256 pages - case 0xc6: PrintAndLog(" IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors + case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages + case 0xc4: PrintAndLogEx(NORMAL, " IC type : SLE 66R16P 2560 Bytes"); break; //256 pages + case 0xc6: PrintAndLogEx(NORMAL, " IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors } } - // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; if ( data[3] == crc0 ) - PrintAndLog(" BCC0 : %02X, Ok", data[3]); + PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else - PrintAndLog(" BCC0 : %02X, crc should be %02X", data[3], crc0); + PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; if ( data[8] == crc1 ) - PrintAndLog(" BCC1 : %02X, Ok", data[8]); + PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else - PrintAndLog(" BCC1 : %02X, crc should be %02X", data[8], crc1 ); + PrintAndLogEx(NORMAL, " BCC1 : %02X, crc should be %02X", data[8], crc1 ); - PrintAndLog(" Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); + PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLog(" Lock : %s - %s", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), - printBits(2, data+10) + printBits(1, data+10), + printBits(1, data+11) ); - PrintAndLog("OneTimePad : %s - %s\n", + PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", sprint_hex(data + 12, 4), - printBits(4, data+12) + printBits(1, data+12), + printBits(1, data+13), + printBits(1, data+14), + printBits(1, data+15) ); return 0; @@ -358,20 +396,20 @@ static int ndef_print_CC(uint8_t *data) { if(data[0] != 0xe1) return -1; - PrintAndLog("--- NDEF Message"); - PrintAndLog("Capability Container: %s", sprint_hex(data,4) ); - PrintAndLog(" %02X : NDEF Magic Number", data[0]); - PrintAndLog(" %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); - PrintAndLog(" %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); + PrintAndLogEx(NORMAL, "--- NDEF Message"); + PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data,4) ); + PrintAndLogEx(NORMAL, " %02X : NDEF Magic Number", data[0]); + PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLogEx(NORMAL, " %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); if ( data[2] == 0x12 ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 144); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 144); else if ( data[2] == 0x3e ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 496); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 496); else if ( data[2] == 0x6d ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 872); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 872); - PrintAndLog(" %02X : %s / %s", data[3], - (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", + PrintAndLogEx(NORMAL, " %02X : %s / %s", data[3], + (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)"); return 0; } @@ -381,75 +419,85 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){ spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) - PrintAndLog("%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + if ( tagtype & UL ) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_C) - PrintAndLog("%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_EV1_48) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); + else if ( tagtype & UL_EV1_128) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); else if ( tagtype & NTAG ) - PrintAndLog("%sTYPE : NTAG UNKNOWN", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); else if ( tagtype & NTAG_203 ) - PrintAndLog("%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); else if ( tagtype & NTAG_210 ) - PrintAndLog("%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); else if ( tagtype & NTAG_212 ) - PrintAndLog("%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); else if ( tagtype & NTAG_213 ) - PrintAndLog("%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); else if ( tagtype & NTAG_215 ) - PrintAndLog("%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); else if ( tagtype & NTAG_216 ) - PrintAndLog("%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); else if ( tagtype & NTAG_I2C_1K ) - PrintAndLog("%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) - PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); + else if ( tagtype & NTAG_I2C_2K ) + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); else if ( tagtype & MY_D ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); else if ( tagtype & MY_D_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); else if ( tagtype & MY_D_MOVE ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_LEAN ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); else if ( tagtype & FUDAN_UL ) - PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else - PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype); + PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } static int ulc_print_3deskey( uint8_t *data){ - PrintAndLog(" deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); - PrintAndLog(" deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); - PrintAndLog(" deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); - PrintAndLog(" deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); - PrintAndLog("\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); + PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); + PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); + PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); + PrintAndLogEx(NORMAL, " deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); + PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); return 0; } static int ulc_print_configuration( uint8_t *data){ - PrintAndLog("--- UL-C Configuration"); - PrintAndLog(" Higher Lockbits [40/0x28] : %s - %s", sprint_hex(data, 4), printBits(2, data)); - PrintAndLog(" Counter [41/0x29] : %s - %s", sprint_hex(data+4, 4), printBits(2, data+4)); + PrintAndLogEx(NORMAL, "--- UL-C Configuration"); + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + sprint_hex(data, 2), + printBits(1, data), + printBits(1, data+1) + ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", + sprint_hex(data+4, 4), + printBits(1, data+4), + printBits(1, data+5), + printBits(1, data+6), + printBits(1, data+7) + ); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); if ( validAuth ) - PrintAndLog(" Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8],data[8] ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ if ( data[8] == 0){ - PrintAndLog(" Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { - PrintAndLog(" Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); } } - PrintAndLog(" Auth1 [43/0x2B] : %s %s", + PrintAndLogEx(NORMAL, " Auth1 [43/0x2B] : %s %s", sprint_hex(data+12, 4), (data[12] & 1) ? "write access restricted": "read and write access restricted" ); @@ -458,7 +506,7 @@ static int ulc_print_configuration( uint8_t *data){ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ - PrintAndLog("\n--- Tag Configuration"); + PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); bool strg_mod_en = (data[0] & 2); uint8_t authlim = (data[4] & 0x07); @@ -466,28 +514,28 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ bool prot = (data[4] & 0x80); uint8_t vctid = data[5]; - PrintAndLog(" cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); + PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); if ( data[3] < 0xff ) - PrintAndLog(" - page %d and above need authentication",data[3]); - else - PrintAndLog(" - pages don't need authentication"); - PrintAndLog(" - strong modulation mode %s", (strg_mod_en) ? "enabled":"disabled"); - PrintAndLog(" cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); - if ( authlim == 0) - PrintAndLog(" - Unlimited password attempts"); + PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); else - PrintAndLog(" - Max number of password attempts is %d", authlim); - PrintAndLog(" - user configuration %s", cfglck ? "permanently locked":"writeable"); - PrintAndLog(" - %s access is protected with password", prot ? "read and write":"write"); - PrintAndLog(" - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLog(" PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLog(" PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLog(" RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " - pages don't need authentication"); + PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); + PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); + if ( authlim == 0) + PrintAndLogEx(NORMAL, " - Unlimited password attempts"); + else + PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); + PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); + PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); + PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } static int ulev1_print_counters(){ - PrintAndLog("--- Tag Counters"); + PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; @@ -495,34 +543,34 @@ static int ulev1_print_counters(){ ulev1_readTearing(i,tear,sizeof(tear)); len = ulev1_readCounter(i,counter, sizeof(counter) ); if (len == 3) { - PrintAndLog(" [%0d] : %s", i, sprint_hex(counter,3)); - PrintAndLog(" - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); + PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); + PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); } } return len; } static int ulev1_print_signature( uint8_t *data, uint8_t len){ - PrintAndLog("\n--- Tag Signature"); - //PrintAndLog("IC signature public key name : NXP NTAG21x 2013"); // don't know if there is other NXP public keys.. :( - PrintAndLog("IC signature public key value : 04494e1a386d3d3cfe3dc10e5de68a499b1c202db5b132393e89ed19fe5be8bc61"); - PrintAndLog(" Elliptic curve parameters : secp128r1"); - PrintAndLog(" Tag ECC Signature : %s", sprint_hex(data, len)); + PrintAndLogEx(NORMAL, "\n--- Tag Signature"); + PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); + PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN)); + PrintAndLogEx(NORMAL, " Elliptic curve parameters : secp128r1"); + PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(data, len)); //to do: verify if signature is valid - //PrintAndLog("IC signature status: %s valid", (iseccvalid() )?"":"not"); + //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not"); return 0; } static int ulev1_print_version(uint8_t *data){ - PrintAndLog("\n--- Tag Version"); - PrintAndLog(" Raw bytes : %s",sprint_hex(data, 8) ); - PrintAndLog(" Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); - PrintAndLog(" Product type : %s", getProductTypeStr(data[2])); - PrintAndLog(" Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); - PrintAndLog(" Major version : %02X", data[4]); - PrintAndLog(" Minor version : %02X", data[5]); - PrintAndLog(" Size : %s", getUlev1CardSizeStr(data[6])); - PrintAndLog(" Protocol type : %02X", data[7]); + PrintAndLogEx(NORMAL, "\n--- Tag Version"); + PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); + PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); + PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); + PrintAndLogEx(NORMAL, " Major version : %02X", data[4]); + PrintAndLogEx(NORMAL, " Minor version : %02X", data[5]); + PrintAndLogEx(NORMAL, " Size : %s", getUlev1CardSizeStr(data[6])); + PrintAndLogEx(NORMAL, " Protocol type : %02X", data[7]); return 0; } @@ -548,7 +596,7 @@ static int ulc_magic_test(){ returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; } else { returnValue = UL; - } + } DropField(); return returnValue; } @@ -556,14 +604,14 @@ static int ulc_magic_test(){ static int ul_magic_test(){ // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE + // 1) take present UID, and try to write it back. OBSOLETE // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; int status = ul_comp_write(0, NULL, 0); DropField(); - if ( status == 0 ) + if ( status == 0 ) return MAGIC; return 0; } @@ -578,9 +626,9 @@ uint32_t GetHF14AMfU_Type(void){ if (!ul_select(&card)) return UL_ERROR; - // Ultralight - ATQA / SAK + // Ultralight - ATQA / SAK if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLog("Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); DropField(); return UL_ERROR; } @@ -631,7 +679,7 @@ uint32_t GetHF14AMfU_Type(void){ DropField(); if (status > 1) { tagtype = UL_C; - } else { + } else { // need to re-select after authentication error if ( !ul_select(&card) ) return UL_ERROR; @@ -653,18 +701,18 @@ uint32_t GetHF14AMfU_Type(void){ } } if (tagtype & UL) { - tagtype = ul_fudan_check(); + tagtype = ul_fudan_check(); DropField(); } } else { DropField(); - // Infinition MY-D tests Exam high nibble + // Infinition MY-D tests Exam high nibble uint8_t nib = (card.uid[1] & 0xf0) >> 4; switch ( nib ){ // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } @@ -674,7 +722,25 @@ uint32_t GetHF14AMfU_Type(void){ return tagtype; } -int CmdHF14AMfUInfo(const char *Cmd){ +static int usage_hf_mfu_info(void) { + PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); + PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); + PrintAndLogEx(NORMAL, "The following tags can be identified:\n"); + PrintAndLogEx(NORMAL, "Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); + PrintAndLogEx(NORMAL, "NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); + PrintAndLogEx(NORMAL, "my-d, my-d NFC, my-d move, my-d move NFC\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu info k l"); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu info"); + PrintAndLogEx(NORMAL, " : hf mfu info k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu info k AABBCCDDD"); + return 0; +} + +static int CmdHF14AMfUInfo(const char *Cmd){ uint8_t authlim = 0xff; uint8_t data[16] = {0x00}; @@ -688,7 +754,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t dataLen = 0; uint8_t authenticationkey[16] = {0x00}; uint8_t *authkeyptr = authenticationkey; - uint8_t *key; + uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; char tempStr[50]; @@ -707,7 +773,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; // handled as bytes from now on } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -719,7 +785,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -732,11 +798,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ TagTypeUL_t tagtype = GetHF14AMfU_Type(); if (tagtype == UL_ERROR) return -1; - PrintAndLog("\n--- Tag Information ---------"); - PrintAndLog("-------------------------------------------------------------"); + PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); + PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; @@ -745,7 +811,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0, data, sizeof(data)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); return status; } else if (status == 16) { ul_print_default(data); @@ -761,10 +827,10 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t ulc_conf[16] = {0x00}; status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); if ( status == -1 ){ - PrintAndLog("Error: tag didn't answer to READ UL-C"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); DropField(); return status; - } + } if (status == 16) ulc_print_configuration(ulc_conf); else locked = true; @@ -774,33 +840,33 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ magic"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); return status; } if (status == 16) ulc_print_3deskey(ulc_deskey); } else { DropField(); - // if we called info with key, just return + // if we called info with key, just return if ( hasAuthKey ) return 1; // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys - PrintAndLog("Trying some default 3des keys"); + PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { key = default_3des_keys[i]; if (ulc_authentication(key, true)) { - PrintAndLog("Found default 3des key: "); + PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); ulc_print_3deskey(keySwap); return 1; - } + } } return 1; } } - // do counters and signature first (don't neet auth) + // do counters and signature first (don't neet auth) // ul counters are different than ntag counters if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { @@ -810,11 +876,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ } } - if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { + if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ SIGNATURE"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); DropField(); return status; } @@ -829,7 +895,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t version[10] = {0x00}; status = ulev1_getVersion(version, sizeof(version)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to GETVERSION"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); DropField(); return status; } else if (status == 10) { @@ -849,7 +915,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ if (startconfigblock){ // if we know where the config block is... status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ EV1"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); DropField(); return status; } else if (status == 16) { @@ -864,32 +930,46 @@ int CmdHF14AMfUInfo(const char *Cmd){ // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. if ( !authlim && !hasAuthKey ) { - PrintAndLog("\n--- Known EV1/NTAG passwords."); + PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLog("Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); break; } else { if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; } } - if (len < 1) PrintAndLog("password not known"); + if (len < 1) PrintAndLogEx(WARNING, "password not known"); } } DropField(); - if (locked) PrintAndLog("\nTag appears to be locked, try using the key to get more info"); - PrintAndLog(""); + if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + PrintAndLogEx(NORMAL, ""); return 1; } // // Write Single Block // -int CmdHF14AMfUWrBl(const char *Cmd){ +static int usage_hf_mfu_wrbl(void) { + PrintAndLogEx(NORMAL, "Write a block. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b d k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to write"); + PrintAndLogEx(NORMAL, " d : block data - (8 hex symbols)"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu wrbl b 0 d 01234567"); + PrintAndLogEx(NORMAL, " : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; @@ -921,7 +1001,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -929,14 +1009,14 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -944,19 +1024,19 @@ int CmdHF14AMfUWrBl(const char *Cmd){ case 'l': case 'L': swapEndian = true; - cmdp++; + cmdp++; break; case 'd': case 'D': if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) { - PrintAndLog("Block data must include 8 HEX symbols"); + PrintAndLogEx(ERR, "Block data must include 8 HEX symbols"); errors = true; break; } cmdp += 2; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -975,18 +1055,18 @@ int CmdHF14AMfUWrBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); if ( blockNo <= 3) - PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); else - PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; @@ -1006,19 +1086,35 @@ int CmdHF14AMfUWrBl(const char *Cmd){ UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); + PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(ERR, "Command execute timeout"); } return 0; } + + // // Read Single Block // -int CmdHF14AMfURdBl(const char *Cmd){ +static int usage_hf_mfu_rdbl(void) { + PrintAndLogEx(NORMAL, "Read a block and print. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu rdbl b k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to read"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu rdbl b 0"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k AABBCCDDD\n"); + return 0; +} - int blockNo = -1; +static int CmdHF14AMfURdBl(const char *Cmd){ + + int blockNo = -1; bool errors = false; bool hasAuthKey = false; bool hasPwdKey = false; @@ -1046,7 +1142,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -1054,14 +1150,14 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -1072,7 +1168,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1091,11 +1187,11 @@ int CmdHF14AMfURdBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); @@ -1117,90 +1213,44 @@ int CmdHF14AMfURdBl(const char *Cmd){ uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; - PrintAndLog("\n Block# | Data | Ascii"); - PrintAndLog("---------+-------------+------"); - PrintAndLog(" %02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data); - } - else { - PrintAndLog("Failed reading block: (%02x)", isOK); + PrintAndLogEx(NORMAL, "\n Block# | Data | Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+------"); + PrintAndLogEx(NORMAL, " %02d/0x%02X | %s| %s\n", blockNo, blockNo, sprint_hex(data, 4), sprint_ascii(data, 4)); + } else { + PrintAndLogEx(ERR, "Failed reading block: (%02x)", isOK); } } else { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); } return 0; } -int usage_hf_mfu_info(void) { - PrintAndLog("It gathers information about the tag and tries to detect what kind it is."); - PrintAndLog("Sometimes the tags are locked down, and you may need a key to be able to read the information"); - PrintAndLog("The following tags can be identified:\n"); - PrintAndLog("Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); - PrintAndLog("NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); - PrintAndLog("my-d, my-d NFC, my-d move, my-d move NFC\n"); - PrintAndLog("Usage: hf mfu info k l"); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu info"); - PrintAndLog(" : hf mfu info k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu info k AABBCCDDD"); - return 0; -} - -int usage_hf_mfu_dump(void) { - PrintAndLog("Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLog("NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLog("and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLog("It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu dump k l n "); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(" n : filename w/o .bin to save the dump as"); - PrintAndLog(" p : starting Page number to manually set a page to start the dump at"); - PrintAndLog(" q : number of Pages to manually set how many pages to dump"); - - PrintAndLog(""); - PrintAndLog(" sample : hf mfu dump"); - PrintAndLog(" : hf mfu dump n myfile"); - PrintAndLog(" : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu dump k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_rdbl(void) { - PrintAndLog("Read a block and print. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu rdbl b k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to read"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu rdbl b 0"); - PrintAndLog(" : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu rdbl b 0 k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_wrbl(void) { - PrintAndLog("Write a block. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu wrbl b d k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to write"); - PrintAndLog(" d : block data - (8 hex symbols)"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu wrbl b 0 d 01234567"); - PrintAndLog(" : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); - return 0; -} // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. -int CmdHF14AMfUDump(const char *Cmd){ +static int usage_hf_mfu_dump(void) { + PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); + PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); + PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLogEx(NORMAL, "It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); + PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu dump"); + PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); + PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUDump(const char *Cmd){ FILE *fout; char filename[FILE_PATH_SIZE] = {0x00}; @@ -1219,7 +1269,7 @@ int CmdHF14AMfUDump(const char *Cmd){ uint8_t dataLen = 0; uint8_t cmdp = 0; uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; + uint8_t *authKeyPtr = authenticationkey; size_t fileNlen = 0; bool errors = false; bool swapEndian = false; @@ -1242,7 +1292,7 @@ int CmdHF14AMfUDump(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -1256,7 +1306,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 'n': case 'N': fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; + if (!fileNlen) errors = true; if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; cmdp += 2; break; @@ -1273,7 +1323,7 @@ int CmdHF14AMfUDump(const char *Cmd){ manualPages = true; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1283,7 +1333,7 @@ int CmdHF14AMfUDump(const char *Cmd){ //Validations if(errors) return usage_hf_mfu_dump(); - if (swapEndian && hasAuthKey) + if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); TagTypeUL_t tagtype = GetHF14AMfU_Type(); @@ -1295,7 +1345,7 @@ int CmdHF14AMfUDump(const char *Cmd){ Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 ul_print_type(tagtype, 0); - PrintAndLog("Reading tag memory..."); + PrintAndLogEx(NORMAL, "Reading tag memory..."); UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; if ( hasAuthKey ) { if (tagtype & UL_C) @@ -1310,18 +1360,18 @@ int CmdHF14AMfUDump(const char *Cmd){ SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); return 1; } if (resp.arg[0] != 1) { - PrintAndLog("Failed reading block: (%02x)", i); + PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); return 1; } uint32_t startindex = resp.arg[2]; uint32_t bufferSize = resp.arg[1]; if (bufferSize > sizeof(data)) { - PrintAndLog("Data exceeded Buffer size!"); + PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); bufferSize = sizeof(data); } GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); @@ -1358,17 +1408,17 @@ int CmdHF14AMfUDump(const char *Cmd){ if (tagtype & UL_C){ //add 4 pages memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; + Pages += dataLen/4; } else { // 2nd page from end memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); } } - PrintAndLog("\n Block# | Data |lck| Ascii"); - PrintAndLog("---------+-------------+---+------"); + PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+---+------"); for (i = 0; i < Pages; ++i) { if ( i < 3 ) { - PrintAndLog("%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); continue; } switch(i){ @@ -1392,7 +1442,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 20: case 21: case 22: - case 23: tmplockbit = bit2[5]; break; + case 23: tmplockbit = bit2[5]; break; case 24: case 25: case 26: @@ -1404,11 +1454,11 @@ int CmdHF14AMfUDump(const char *Cmd){ case 32: case 33: case 34: - case 35: tmplockbit = bit2[1]; break; + case 35: tmplockbit = bit2[1]; break; case 36: case 37: case 38: - case 39: tmplockbit = bit2[0]; break; + case 39: tmplockbit = bit2[0]; break; case 40: tmplockbit = bit2[12]; break; case 41: tmplockbit = bit2[11]; break; case 42: tmplockbit = bit2[10]; break; //auth0 @@ -1420,9 +1470,9 @@ int CmdHF14AMfUDump(const char *Cmd){ memcpy(cleanASCII, data+i*4, 4); clean_ascii(cleanASCII, 4); - PrintAndLog("%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); } - PrintAndLog("---------------------------------"); + PrintAndLogEx(NORMAL, "---------------------------------"); // user supplied filename? if (fileNlen < 1) { @@ -1433,14 +1483,14 @@ int CmdHF14AMfUDump(const char *Cmd){ sprintf(fnameptr + fileNlen,".bin"); } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLog("Could not create file name %s", filename); + if ((fout = fopen(filename,"wb")) == NULL) { + PrintAndLogEx(NORMAL, "Could not create file name %s", filename); return 1; } fwrite( data, 1, Pages*4, fout ); fclose(fout); - - PrintAndLog("Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); return 0; } @@ -1451,7 +1501,7 @@ int CmdHF14AMfUDump(const char *Cmd){ // // Ultralight C Authentication Demo {currently uses hard-coded key} // -int CmdHF14AMfucAuth(const char *Cmd){ +static int CmdHF14AMfucAuth(const char *Cmd){ uint8_t keyNo = 3; bool errors = false; @@ -1461,49 +1511,49 @@ int CmdHF14AMfucAuth(const char *Cmd){ //Change key to user defined one if (cmdp == 'k' || cmdp == 'K'){ keyNo = param_get8(Cmd, 1); - if(keyNo > KEYS_3DES_COUNT-1) + if(keyNo > KEYS_3DES_COUNT-1) errors = true; } if (cmdp == 'h' || cmdp == 'H') errors = true; - + if (errors) { - PrintAndLog("Usage: hf mfu cauth k "); - PrintAndLog(" 0 (default): 3DES standard key"); - PrintAndLog(" 1 : all 0x00 key"); - PrintAndLog(" 2 : 0x00-0x0F key"); - PrintAndLog(" 3 : nfc key"); - PrintAndLog(" 4 : all 0x01 key"); - PrintAndLog(" 5 : all 0xff key"); - PrintAndLog(" 6 : 0x00-0xFF key"); - PrintAndLog("\n sample : hf mfu cauth k"); - PrintAndLog(" : hf mfu cauth k 3"); + PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k "); + PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key"); + PrintAndLogEx(NORMAL, " 1 : all 0x00 key"); + PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key"); + PrintAndLogEx(NORMAL, " 3 : nfc key"); + PrintAndLogEx(NORMAL, " 4 : all 0x01 key"); + PrintAndLogEx(NORMAL, " 5 : all 0xff key"); + PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key"); + PrintAndLogEx(NORMAL, "\n sample : hf mfu cauth k"); + PrintAndLogEx(NORMAL, " : hf mfu cauth k 3"); return 0; - } + } uint8_t *key = default_3des_keys[keyNo]; if (ulc_authentication(key, true)) - PrintAndLog("Authentication successful. 3des key: %s",sprint_hex(key, 16)); + PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); else - PrintAndLog("Authentication failed"); - + PrintAndLogEx(WARNING, "Authentication failed"); + return 0; } /** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl +A test function to validate that the polarssl-function works the same +was as the openssl-implementation. +Commented out, since it requires openssl int CmdTestDES(const char * cmd) { - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); + uint8_t key[16] = {0x00}; + + memcpy(key,key3_3des_data,16); DES_cblock RndA, RndB; - PrintAndLog("----------OpenSSL DES implementation----------"); + PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); { uint8_t e_RndB[8] = {0x00}; unsigned char RndARndB[16] = {0x00}; @@ -1512,7 +1562,7 @@ int CmdTestDES(const char * cmd) DES_key_schedule ks1,ks2; DES_cblock key1,key2; - memcpy(key,key3_3des_data,16); + memcpy(key,key3_3des_data,16); memcpy(key1,key,8); memcpy(key2,key+8,8); @@ -1521,23 +1571,23 @@ int CmdTestDES(const char * cmd) DES_set_key((DES_cblock *)key2,&ks2); DES_random_key(&RndA); - PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(e_RndB, 8)); + PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); //void DES_ede2_cbc_encrypt(const unsigned char *input, // unsigned char *output, long length, DES_key_schedule *ks1, // DES_key_schedule *ks2, DES_cblock *ivec, int enc); DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); rol(RndB,8); memcpy(RndARndB,RndA,8); memcpy(RndARndB+8,RndB,8); - PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); } - PrintAndLog("----------PolarSSL implementation----------"); + PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); { uint8_t random_a[8] = { 0 }; uint8_t enc_random_a[8] = { 0 }; @@ -1551,8 +1601,8 @@ int CmdTestDES(const char * cmd) uint8_t output[8] = { 0 }; uint8_t iv[8] = { 0 }; - PrintAndLog(" RndA :%s",sprint_hex(random_a, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(enc_random_b, 8)); + PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); des3_set2key_dec(&ctx, key); @@ -1564,13 +1614,13 @@ int CmdTestDES(const char * cmd) , random_b // unsigned char *output ); - PrintAndLog(" RndB:%s",sprint_hex(random_b, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); rol(random_b,8); memcpy(random_a_and_b ,random_a,8); memcpy(random_a_and_b+8,random_b,8); - - PrintAndLog(" RA+B:%s",sprint_hex(random_a_and_b, 16)); + + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); des3_set2key_enc(&ctx, key); @@ -1582,97 +1632,97 @@ int CmdTestDES(const char * cmd) , random_a_and_b // unsigned char *output ); - PrintAndLog("enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } - return 0; + return 0; } **/ -// +// // Mifare Ultralight C - Set password // -int CmdHF14AMfucSetPwd(const char *Cmd){ +static int CmdHF14AMfucSetPwd(const char *Cmd){ uint8_t pwd[16] = {0x00}; - + char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setpwd "); - PrintAndLog(" [password] - (32 hex symbols)"); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd "); + PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, pwd, 32)) { - PrintAndLog("Password must include 32 HEX symbols"); + PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); return 1; } - - UsbCommand c = {CMD_MIFAREUC_SETPWD}; + + UsbCommand c = {CMD_MIFAREUC_SETPWD}; memcpy( c.d.asBytes, pwd, 16); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - + if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { if ( (resp.arg[0] & 0xff) == 1) - PrintAndLog("Ultralight-C new password: %s", sprint_hex(pwd,16)); + PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); else{ - PrintAndLog("Failed writing at block %d", resp.arg[1] & 0xff); + PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } } else { - PrintAndLog("command execution time out"); + PrintAndLogEx(ERR, "command execution time out"); return 1; } - + return 0; } // // Magic UL / UL-C tags - Set UID // -int CmdHF14AMfucSetUid(const char *Cmd){ +static int CmdHF14AMfucSetUid(const char *Cmd){ UsbCommand c; UsbCommand resp; uint8_t uid[7] = {0x00}; char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setuid "); - PrintAndLog(" [uid] - (14 hex symbols)"); - PrintAndLog("\nThis only works for Magic Ultralight tags."); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setuid 11223344556677"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setuid "); + PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)"); + PrintAndLogEx(NORMAL, "\nThis only works for Magic Ultralight tags."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setuid 11223344556677"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, uid, 14)) { - PrintAndLog("UID must include 14 HEX symbols"); + PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); return 1; } - // read block2. + // read block2. c.cmd = CMD_MIFAREU_READBL; c.arg[0] = 2; clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } - + // save old block2. uint8_t oldblock2[4] = {0x00}; memcpy(resp.d.asBytes, oldblock2, 4); - + // block 0. c.cmd = CMD_MIFAREU_WRITEBL; c.arg[0] = 0; @@ -1683,10 +1733,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } - + // block 1. c.arg[0] = 1; c.d.asBytes[0] = uid[3]; @@ -1696,7 +1746,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1709,14 +1759,14 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } - + return 0; } -int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ +static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; uint8_t block = 0x07; @@ -1729,9 +1779,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t mifarekeyB[] = { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5 }; uint8_t dkeyA[8] = { 0x00 }; uint8_t dkeyB[8] = { 0x00 }; - + uint8_t masterkey[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff }; - + uint8_t mix[8] = { 0x00 }; uint8_t divkey[8] = { 0x00 }; @@ -1753,26 +1803,24 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , divkey // output ); - PrintAndLog("3DES version"); - PrintAndLog("Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); - PrintAndLog("UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLog("Sector :\t %0d", block); - PrintAndLog("Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLog("Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6)); - - PrintAndLog("\n DES version"); + PrintAndLogEx(NORMAL, "-- 3DES version"); + PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); + PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(NORMAL, "Block :\t %0d", block); + PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6)); for (int i=0; i < sizeof(mifarekeyA); ++i){ dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); } - + for (int i=0; i < sizeof(mifarekeyB); ++i){ dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1); dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff; } - + uint8_t zeros[8] = {0x00}; uint8_t newpwd[8] = {0x00}; uint8_t dmkey[24] = {0x00}; @@ -1790,17 +1838,18 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , zeros // input , newpwd // output ); - - PrintAndLog("Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLog("Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLog("Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLog("Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); - + + PrintAndLogEx(NORMAL, "\n-- DES version"); + PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + return 0; } // static uint8_t * diversify_key(uint8_t * key){ - + // for(int i=0; i<16; i++){ // if(i<=6) key[i]^=cuid[i]; // if(i>6) key[i]^=cuid[i%7]; @@ -1810,7 +1859,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ // static void GenerateUIDe( uint8_t *uid, uint8_t len){ // for (int i=0; i -//Crypto Cards -int CmdHF14AMfucAuth(const char *Cmd); - -//general stuff -int CmdHF14AMfUDump(const char *Cmd); -int CmdHF14AMfUInfo(const char *Cmd); - -uint32_t GetHF14AMfU_Type(void); -int ul_print_type(uint32_t tagtype, uint8_t spacer); - -int usage_hf_mfu_dump(void); -int usage_hf_mfu_info(void); -int usage_hf_mfu_rdbl(void); -int usage_hf_mfu_wrbl(void); - -int CmdHFMFUltra(const char *Cmd); - -typedef enum TAGTYPE_UL { - UNKNOWN = 0x000000, - UL = 0x000001, - UL_C = 0x000002, - UL_EV1_48 = 0x000004, - UL_EV1_128 = 0x000008, - NTAG = 0x000010, - NTAG_203 = 0x000020, - NTAG_210 = 0x000040, - NTAG_212 = 0x000080, - NTAG_213 = 0x000100, - NTAG_215 = 0x000200, - NTAG_216 = 0x000400, - MY_D = 0x000800, - MY_D_NFC = 0x001000, - MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, - UL_MAGIC = UL | MAGIC, - UL_C_MAGIC = UL_C | MAGIC, - UL_ERROR = 0xFFFFFF, -} TagTypeUL_t; +extern int CmdHFMFUltra(const char *Cmd); +extern uint32_t GetHF14AMfU_Type(void); +extern int ul_print_type(uint32_t tagtype, uint8_t spacer); #endif diff --git a/client/util.c b/client/util.c index f13d730c..eef97e2a 100644 --- a/client/util.c +++ b/client/util.c @@ -268,6 +268,10 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st return buf; } +char *sprint_ascii(const uint8_t *data, const size_t len) { + return sprint_ascii_ex(data, len, 0); +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -329,7 +333,7 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS } //assumes little endian -char * printBits(size_t const size, void const * const ptr) +char *printBits(size_t const size, void const * const ptr) { unsigned char *b = (unsigned char*) ptr; unsigned char byte; diff --git a/client/util.h b/client/util.h index 29dd7d5c..18482dfe 100644 --- a/client/util.h +++ b/client/util.h @@ -101,6 +101,7 @@ extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const si extern char *sprint_bin(const uint8_t * data, const size_t len); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len); +extern char *sprint_ascii(const uint8_t *data, const size_t len); extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); extern uint64_t bytes_to_num(uint8_t* src, size_t len); From caaa4293ad077ba5cf2205288984a3f470464286 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:50:58 +0200 Subject: [PATCH 06/29] fix 'lf pcf7931 bruteforce' (bug reported in http://www.proxmark.org/forum/viewtopic.php?id=6490) (#824) (and whitespace fixes) --- armsrc/pcf7931.c | 116 ++++++++++++++++++++---------------------- client/cmdlfpcf7931.c | 56 ++++++++++---------- 2 files changed, 83 insertions(+), 89 deletions(-) diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 9aa0d9be..e3bac386 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -13,11 +13,11 @@ size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; uint8_t *dest = BigBuf_get_addr(); - + int GraphTraceLen = BigBuf_max_traceLen(); if (GraphTraceLen > 18000) GraphTraceLen = 18000; - + int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; @@ -107,7 +107,7 @@ size_t DemodPCF7931(uint8_t **outBlocks) { for(j = 0; j < 16; ++j) { blocks[num_blocks][j] = 128 * bits[j*8 + 7]+ - 64 * bits[j*8 + 6] + + 64 * bits[j*8 + 6] + 32 * bits[j*8 + 5] + 16 * bits[j*8 + 4] + 8 * bits[j*8 + 3] + @@ -161,44 +161,44 @@ bool IsBlock1PCF7931(uint8_t *block) { void ReadPCF7931() { int found_blocks = 0; // successfully read blocks - int max_blocks = 8; // readable blocks + int max_blocks = 8; // readable blocks uint8_t memory_blocks[8][17]; // PCF content - + uint8_t single_blocks[8][17]; // PFC blocks with unknown position int single_blocks_cnt = 0; - size_t n = 0; // transmitted blocks + size_t n = 0; // transmitted blocks uint8_t tmp_blocks[4][16]; // temporary read buffer - + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found int errors = 0; // error counter int tries = 0; // tries counter - + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); memset(single_blocks, 0, 8*17*sizeof(uint8_t)); - + int i = 0, j = 0; do { i = 0; - + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) ++errors; - - // exit if no block is received + + // exit if no block is received if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - // exit if too many errors during reading + // exit if too many errors during reading if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - + // our logic breaks if we don't get at least two blocks if (n < 2) { if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) @@ -219,12 +219,12 @@ void ReadPCF7931() { } ++tries; continue; - } - - Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); i = 0; - if(!found_0_1) { + if(!found_0_1) { while (i < n - 1) { if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { found_0_1 = 1; @@ -234,9 +234,9 @@ void ReadPCF7931() { // block 1 tells how many blocks are going to be sent max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; found_blocks = 2; - + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); - + // handle the following blocks for (j = i + 2; j < n; ++j) { memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); @@ -297,14 +297,14 @@ void ReadPCF7931() { Dbprintf("", i); } Dbprintf("-----------------------------------------"); - + if (found_blocks < max_blocks) { Dbprintf("-----------------------------------------"); Dbprintf("Blocks with unknown position:"); Dbprintf("-----------------------------------------"); for (i = 0; i < single_blocks_cnt; ++i) print_result("Block", single_blocks[i], 16); - + Dbprintf("-----------------------------------------"); } cmd_send(CMD_ACK,0,0,0,0,0); @@ -332,42 +332,42 @@ static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int3 AddBytePCF7931(pass[6], tab, l, p); //programming mode (0 or 1) AddBitPCF7931(0, tab, l, p); - + //block adress on 6 bits for (u = 0; u < 6; ++u) { - if (address & (1 << u)) { // bit 1 + if (address & (1 << u)) { // bit 1 ++parity; AddBitPCF7931(1, tab, l, p); - } else { // bit 0 + } else { // bit 0 AddBitPCF7931(0, tab, l, p); } } - + //byte address on 4 bits for (u = 0; u < 4; ++u) { - if (byte & (1 << u)) { // bit 1 + if (byte & (1 << u)) { // bit 1 parity++; AddBitPCF7931(1, tab, l, p); } - else // bit 0 + else // bit 0 AddBitPCF7931(0, tab, l, p); } - + //data on 8 bits for (u=0; u<8; u++) { - if (data&(1<> 8) & 0xFF; - pass_array[2] = (password >> 16) & 0xFF; - pass_array[3] = (password >> 24) & 0xFF; - pass_array[4] = (password >> 32) & 0xFF; - pass_array[5] = (password >> 40) & 0xFF; - pass_array[6] = (password >> 48) & 0xFF; + + num_to_bytes(password, 7, pass_array); Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", pass_array[0], @@ -417,7 +411,7 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in pass_array[4], pass_array[5], pass_array[6]); - + for (i = 0; i < tries; ++i) RealWritePCF7931 ( @@ -429,15 +423,15 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in 7, 0x01 ); - - ++password; + + ++password; } } /* Write on a byte of a PCF7931 tag * @param address : address of the block to write @param byte : address of the byte to write - @param data : data to write + @param data : data to write */ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { Dbprintf("Initialization delay : %d us", init_delay); @@ -446,9 +440,9 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui Dbprintf("Block address : %02x", address); Dbprintf("Byte address : %02x", byte); Dbprintf("Data : %02x", data); - + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; - + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); } @@ -488,7 +482,7 @@ void SendCmdPCF7931(uint32_t * tab) { HIGH(GPIO_SSC_DOUT); while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - + // stop modulating antenna LOW(GPIO_SSC_DOUT); while(tempo != tab[u+1]) @@ -510,7 +504,7 @@ void SendCmdPCF7931(uint32_t * tab) { } -/* Add a byte for building the data frame of PCF7931 tags +/* Add a byte for building the data frame of PCF7931 tags * @param b : byte to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -519,7 +513,7 @@ void SendCmdPCF7931(uint32_t * tab) { bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { uint32_t u; for (u = 0; u < 8; ++u) { - if (byte & (1 << u)) { //bit is 1 + if (byte & (1 << u)) { //bit is 1 if(AddBitPCF7931(1, tab, l, p)==1)return 1; } else { //bit is 0 if(AddBitPCF7931(0, tab, l, p)==1)return 1; @@ -529,7 +523,7 @@ bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { return 0; } -/* Add a bits for building the data frame of PCF7931 tags +/* Add a bits for building the data frame of PCF7931 tags * @param b : bit to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -540,23 +534,23 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p) { for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (b == 1) { //add a bit 1 - if (u == 0) tab[u] = 34 * T0_PCF + p; - else tab[u] = 34 * T0_PCF + tab[u-1] + p; + if (b == 1) { //add a bit 1 + if (u == 0) tab[u] = 34 * T0_PCF + p; + else tab[u] = 34 * T0_PCF + tab[u-1] + p; tab[u+1] = 6 * T0_PCF+tab[u] + l; tab[u+2] = 88 * T0_PCF+tab[u + 1] - l - p; return 0; - } else { //add a bit 0 + } else { //add a bit 0 - if (u == 0) tab[u] = 98 * T0_PCF + p; - else tab[u] = 98 * T0_PCF + tab[u-1] + p; + if (u == 0) tab[u] = 98 * T0_PCF + p; + else tab[u] = 98 * T0_PCF + tab[u-1] + p; tab[u + 1] = 6 * T0_PCF + tab[u] + l; tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p; return 0; } - + return 1; } @@ -570,8 +564,8 @@ bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab) { uint32_t u = 0; for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (u == 0) tab[u] = a; - else tab[u] = a + tab[u - 1]; + if (u == 0) tab[u] = a; + else tab[u] = a + tab[u - 1]; tab[u + 1] = b + tab[u]; tab[u + 2] = c + tab[u + 1]; diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 9882da5f..74bc3b3e 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake -// 2018 sguerrini97 +// 2018 sguerrini97 // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -33,7 +33,7 @@ static int CmdHelp(const char *Cmd); struct pcf7931_config configPcf = { {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, PCF7931_DEFAULT_INITDELAY, - PCF7931_DEFAULT_OFFSET_WIDTH, + PCF7931_DEFAULT_OFFSET_WIDTH, PCF7931_DEFAULT_OFFSET_POSITION }; @@ -41,8 +41,8 @@ struct pcf7931_config configPcf = { int pcf7931_resetConfig(){ memset(configPcf.Pwd, 0xFF, sizeof(configPcf.Pwd) ); configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY; - configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; - configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; + configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; + configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; return 0; } @@ -103,7 +103,7 @@ int usage_pcf7931_config(){ PrintAndLog(" pwd Password, hex, 7bytes, LSB-order"); PrintAndLog(" delay Tag initialization delay (in us) decimal"); PrintAndLog(" offset Low pulses width (in us) decimal"); - PrintAndLog(" offset Low pulses position (in us) decimal"); + PrintAndLog(" offset Low pulses position (in us) decimal"); PrintAndLog("Examples:"); PrintAndLog(" lf pcf7931 config"); PrintAndLog(" lf pcf7931 config r"); @@ -112,7 +112,7 @@ int usage_pcf7931_config(){ return 0; } -int CmdLFPCF7931Read(const char *Cmd){ +int CmdLFPCF7931Read(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_read(); @@ -128,12 +128,12 @@ int CmdLFPCF7931Read(const char *Cmd){ return 0; } -int CmdLFPCF7931Config(const char *Cmd){ +int CmdLFPCF7931Config(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 0) return pcf7931_printConfig(); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_config(); - if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); + if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); if ( param_gethex(Cmd, 0, configPcf.Pwd, 14) ) return usage_pcf7931_config(); @@ -148,17 +148,17 @@ int CmdLFPCF7931Config(const char *Cmd){ int CmdLFPCF7931Write(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); uint8_t block = 0, bytepos = 0, data = 0; - + if ( param_getdec(Cmd, 0, &block) ) return usage_pcf7931_write(); if ( param_getdec(Cmd, 1, &bytepos) ) return usage_pcf7931_write(); - + if ( (block > 7) || (bytepos > 15) ) return usage_pcf7931_write(); data = param_get8ex(Cmd, 2, 0, 16); - + PrintAndLog("Writing block: %d", block); PrintAndLog(" pos: %d", bytepos); PrintAndLog(" data: 0x%02X", data); @@ -178,27 +178,27 @@ int CmdLFPCF7931Write(const char *Cmd){ int CmdLFPCF7931BruteForce(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); - uint64_t start_password = 0; + uint8_t start_password[7] = {0}; uint8_t tries = 3; - - if (param_gethex(Cmd, 0, (uint8_t*)(&start_password), 14)) return usage_pcf7931_bruteforce(); + + if (param_gethex(Cmd, 0, start_password, 14)) return usage_pcf7931_bruteforce(); if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce(); - + PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x", - start_password & 0xFF, - (start_password >> 8) & 0xFF, - (start_password >> 16) & 0xFF, - (start_password >> 24) & 0xFF, - (start_password >> 32) & 0xFF, - (start_password >> 48) & 0xFF, - (start_password >> 56) & 0xFF); - + start_password[0], + start_password[1], + start_password[2], + start_password[3], + start_password[4], + start_password[5], + start_password[6]); + PrintAndLog("Trying each password %d times", tries); - UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {start_password, tries} }; - + UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {bytes_to_num(start_password, 7), tries} }; + c.d.asDwords[7] = (configPcf.OffsetWidth + 128); c.d.asDwords[8] = (configPcf.OffsetPosition + 128); c.d.asDwords[9] = configPcf.InitDelay; @@ -209,7 +209,7 @@ int CmdLFPCF7931BruteForce(const char *Cmd){ return 0; } -static command_t CommandTable[] = +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"}, From d38bb3acc3957efdac0204f147de1d8494a03966 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Wed, 29 May 2019 18:57:17 +0200 Subject: [PATCH 07/29] Specify that we need TCP and not UDP connection (#828) --- uart/uart_posix.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 214cb56a..29a02cf7 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -80,7 +80,7 @@ serial_port uart_open(const char* pcPortName) if (sp == 0) return INVALID_SERIAL_PORT; if (memcmp(pcPortName, "tcp:", 4) == 0) { - struct addrinfo *addr, *rp; + struct addrinfo *addr = NULL, *rp; char *addrstr = strdup(pcPortName + 4); if (addrstr == NULL) { printf("Error: strdup\n"); @@ -98,7 +98,13 @@ serial_port uart_open(const char* pcPortName) } else portstr = "7901"; - int s = getaddrinfo(addrstr, portstr, NULL, &addr); + struct addrinfo info; + + memset (&info, 0, sizeof(info)); + + info.ai_socktype = SOCK_STREAM; + + int s = getaddrinfo(addrstr, portstr, &info, &addr); if (s != 0) { printf("Error: getaddrinfo: %s\n", gai_strerror(s)); return INVALID_SERIAL_PORT; From b8dd1ef6490a49784c797e9312df8622445e28dd Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 6 Jun 2019 07:33:12 +0200 Subject: [PATCH 08/29] upgrading 'hf mfu' (#830) * chg: write new dump file format by @mceloff * chg: rename 'hf mfu dump' option 'n' to 'f' to align with other commands and RRG repo * chg: replace ISO14443A_CMD_READBLOCK by MIFARE_CMD_READBLOCK, same for WRITEBLOCK * fix: mifare_ultra_readblock() returned 14 bytes instead of 16 * chg: param_gethex_ex() now checks maximum output buffer length * chg: ul_comp_write() was incomplete and for magic testing only * fix: 16bit ULC counter had been displayed as 32bit * chg: add check for 7 Byte UID, drop check for ATQA in type identification GetHF14AMfU_Type() * fix: send HALT instead of dropping field in order to maintain a defined state * chg: DropField() when command ends * chg: check for invalid page ranges in 'hf mfu dump' * fix: print correct lock bits when page range is used * fix: do not write (incomplete) dumpfile when page range is used * add: use UID for filename when no filename is given (RRG repo) * chg: don't clear trace on each ULC authentication, clear trace at beginning of each command * fix: don't send (DESFire?) deselect command after authentication --- armsrc/apps.h | 2 - armsrc/iclass.c | 5 +- armsrc/mifarecmd.c | 82 ++- armsrc/mifaresim.c | 8 +- armsrc/mifareutil.c | 2 +- armsrc/mifareutil.h | 5 - client/cmdhflist.c | 4 +- client/cmdhfmf.c | 13 +- client/cmdhfmfu.c | 1304 +++++++++++++++++++++---------------------- client/util.c | 17 +- common/protocols.h | 59 +- 11 files changed, 729 insertions(+), 772 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index 72a62628..d1c885ab 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -142,8 +142,6 @@ void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -void OnSuccess(); -void OnError(uint8_t reason); /// iclass.h diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 83c9a75b..7ffac62d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1963,7 +1963,10 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { uint8_t *dataout = BigBuf_malloc(255*8); if (dataout == NULL){ Dbprintf("out of memory"); - OnError(1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,1,0,0,0); + LED_A_OFF(); return; } memset(dataout,0xFF,255*8); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 14ce1bcc..a3807cf7 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -23,24 +23,42 @@ #define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication +/* // the block number for the ISO14443-4 PCB static uint8_t pcb_blocknum = 0; // Deselect card by sending a s-block. the crc is precalced for speed static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; +static void OnSuccess(){ + pcb_blocknum = 0; + ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} +*/ + +static void OnError(uint8_t reason){ + // pcb_blocknum = 0; + // ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,reason,0,0,0); + LED_A_OFF(); +} + //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params + LED_A_ON(); + uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - // variables byte_t isOK = 0; byte_t dataoutbuf[16]; uint8_t uid[10]; @@ -53,10 +71,6 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) clear_trace(); - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - while (true) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); @@ -97,21 +111,18 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ + LED_A_ON(); bool turnOffField = (arg0 == 1); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - - if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; - if(!mifare_ultra_auth(keybytes)){ + if (!mifare_ultra_auth(keybytes)){ if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed"); OnError(1); return; @@ -119,9 +130,11 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ if (turnOffField) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); } + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); } // Arg0 = BlockNo, @@ -129,17 +142,15 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ // datain = PWD bytes, void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + LED_A_ON(); + uint8_t blockNo = arg0; byte_t dataout[16] = {0x00}; bool useKey = (arg1 == 1); //UL_C bool usePwd = (arg1 == 2); //UL_EV1/NTAG - LEDsoff(); - LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); @@ -148,7 +159,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -159,7 +170,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-EV1 / NTAG authentication - if ( usePwd ) { + if (usePwd) { uint8_t pwd[4] = {0x00}; memcpy(pwd, datain, 4); uint8_t pack[4] = {0,0,0,0}; @@ -169,13 +180,13 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } } - if( mifare_ultra_readblock(blockNo, dataout) ) { + if (mifare_ultra_readblock(blockNo, dataout)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error"); OnError(2); return; } - if( mifare_ultra_halt() ) { + if (mifare_ultra_halt()) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error"); OnError(3); return; @@ -183,7 +194,8 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) cmd_send(CMD_ACK,1,0,0,dataout,16); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -259,13 +271,11 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // datain = KEY bytes void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) { - LEDsoff(); LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); // free eventually allocated BigBuf memory BigBuf_free(); - clear_trace(); // params uint8_t blockNo = arg0; @@ -288,7 +298,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -340,14 +350,14 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks); + if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks); - countblocks *= 4; + cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); - cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -1598,17 +1608,3 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ LEDsoff(); } -void OnSuccess(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -void OnError(uint8_t reason){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,reason,0,0,0); - LEDsoff(); -} diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 6f97e1b4..137a586d 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -542,8 +542,8 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK - || receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK + if(receivedCmd_dec[0] == MIFARE_CMD_READBLOCK + || receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK || receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE @@ -562,7 +562,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t } } - if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_READBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; emlGetMem(response, blockNo, 1); if (IsSectorTrailer(blockNo)) { @@ -593,7 +593,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); FpgaDisableTracing(); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 36e29721..647305e8 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -451,7 +451,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) return result; } - memcpy(blockData, receivedAnswer, 14); + memcpy(blockData, receivedAnswer, 16); return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 589f780b..856040ca 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -25,11 +25,6 @@ #define AUTH_FIRST 0 #define AUTH_NESTED 2 -// mifare 4bit card answers -#define CARD_ACK 0x0A // 1010 - ACK -#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) -#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error - // reader voltage field detector #define MF_MINFIELDV 4000 diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 4499cd0d..5384bfce 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -415,8 +415,8 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); MifareAuthState = masNone; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 38b7f988..ef48b825 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1516,8 +1516,11 @@ int CmdHF14AMfSim(const char *Cmd) { break; case 'u': case 'U': - param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); - switch(uidlen) { + uidlen = 14; + if (param_gethex_ex(Cmd, cmdp+1, uid, &uidlen)) { + return usage_hf14_mfsim(); + } + switch (uidlen) { case 14: flags = FLAG_7B_UID_IN_DATA; break; case 8: flags = FLAG_4B_UID_IN_DATA; break; default: return usage_hf14_mfsim(); @@ -2726,9 +2729,9 @@ int CmdHF14AMfSniff(const char *Cmd){ //needs nt, ar, at, Data to decrypt int CmdDecryptTraceCmds(const char *Cmd){ uint8_t data[50]; - int len = 0; - param_gethex_ex(Cmd,3,data,&len); - return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2); + int len = 100; + param_gethex_ex(Cmd, 3, data, &len); + return tryDecryptWord(param_get32ex(Cmd, 0, 0, 16), param_get32ex(Cmd, 1, 0, 16), param_get32ex(Cmd, 2, 0, 16), data, len/2); } int CmdHF14AMfAuth4(const char *cmd) { diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index dac51be3..89e58263 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -21,6 +21,7 @@ #include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" +#include "util_posix.h" #include "protocols.h" #include "taginfo.h" @@ -40,12 +41,11 @@ typedef enum TAGTYPE_UL { MY_D = 0x000800, MY_D_NFC = 0x001000, MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, + MY_D_MOVE_LEAN= 0x004000, + NTAG_I2C_1K = 0x008000, + NTAG_I2C_2K = 0x010000, + FUDAN_UL = 0x020000, + MAGIC = 0x040000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, @@ -95,14 +95,13 @@ static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; -#define MAX_UL_TYPES 18 +#define MAX_UL_TYPES 17 static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_LEAN, FUDAN_UL}; static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; - + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; // get version nxp product type static char *getProductTypeStr( uint8_t id){ @@ -123,7 +122,7 @@ static char *getProductTypeStr( uint8_t id){ the LSBit is set to '0' if the size is exactly 2^n and set to '1' if the storage size is between 2^n and 2^(n+1). */ -char *getUlev1CardSizeStr( uint8_t fsize ){ +static char *getUlev1CardSizeStr( uint8_t fsize ){ static char buf[40]; char *retStr = buf; @@ -140,13 +139,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ return buf; } -static void ul_switch_on_field(void) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); -} -static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) { +static int ul_send_cmd_raw(uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}}; memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); @@ -159,34 +153,19 @@ static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uin memcpy(response, resp.d.asBytes, resplen); return resplen; } -/* -static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength, bool append_crc ) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT , cmdlen, 0}}; - if (append_crc) - c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); + +static int ul_select(iso14a_card_select_t *card, bool clear_trace) { + + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS | (clear_trace?ISO14A_CLEAR_TRACE:0), 0, 0}}; clearCommandBuffer(); SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; - if (!resp.arg[0] && responseLength) return -1; - - uint16_t resplen = (resp.arg[0] < responseLength) ? resp.arg[0] : responseLength; - memcpy(response, resp.d.asBytes, resplen); - return resplen; -} -*/ -static int ul_select( iso14a_card_select_t *card ){ - - ul_switch_on_field(); UsbCommand resp; bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); - if (!ans || resp.arg[0] < 1) { + if (ans == 0 || resp.arg[0] == 0) { PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); return 0; } @@ -194,40 +173,62 @@ static int ul_select( iso14a_card_select_t *card ){ return 1; } -// This read command will at least return 16bytes. -static int ul_read( uint8_t page, uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {ISO14443A_CMD_READBLOCK, page}; +// This read command will return 16 bytes. +static int ul_read(uint8_t page, uint8_t *response, uint16_t responseLength) { + uint8_t cmd[] = {MIFARE_CMD_READBLOCK, page}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ul_comp_write( uint8_t page, uint8_t *data, uint8_t datalen ){ - uint8_t cmd[18]; - memset(cmd, 0x00, sizeof(cmd)); - datalen = ( datalen > 16) ? 16 : datalen; - - cmd[0] = ISO14443A_CMD_WRITEBLOCK; - cmd[1] = page; - memcpy(cmd+2, data, datalen); - - uint8_t response[1] = {0xff}; - ul_send_cmd_raw(cmd, 2+datalen, response, sizeof(response)); - // ACK - if ( response[0] == 0x0a ) return 0; - // NACK - return -1; +static int ul_halt(void) { + uint8_t cmd[] = {ISO14443A_CMD_HALT, 0x00}; + uint8_t response; + int len = ul_send_cmd_raw(cmd, sizeof(cmd), &response, sizeof(response)); + return len; } -static int ulc_requestAuthentication( uint8_t *nonce, uint16_t nonceLength ){ + +static int ul_comp_write_ex(uint8_t page, uint8_t *data, uint8_t datalen, bool first_part_only) { + + uint8_t cmd[18] = {0x00}; + datalen = ( datalen > 16) ? 16 : datalen; + + cmd[0] = MIFARE_CMD_WRITEBLOCK; + cmd[1] = page; + + uint8_t response = {0xff}; + ul_send_cmd_raw(cmd, 2, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + if (first_part_only) + return 0; + + memcpy(cmd, data, datalen); + ul_send_cmd_raw(cmd, 16, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + + return 0; +} + + +// not used yet +// static int ul_comp_write(uint8_t page, uint8_t *data, uint8_t datalen) { + // return ul_comp_write_ex(page, data, datalen, false); +// } + + +static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { uint8_t cmd[] = {MIFARE_ULC_AUTH_1, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), nonce, nonceLength); return len; } -static int ulc_authentication( uint8_t *key, bool switch_off_field ){ + +static int ulc_authentication(uint8_t *key, bool switch_off_field) { UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}}; memcpy(c.d.asBytes, key, 16); @@ -240,27 +241,29 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){ return 0; } -static int ulev1_requestAuthentication( uint8_t *pwd, uint8_t *pack, uint16_t packLength ){ + +static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) { uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength); return len; } -static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize){ - if ( hasAuthKey && (tagtype & UL_C)) { + +static int ul_auth_select(iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize) { + + if (hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLogEx(WARNING, "Authentication Failed UL-C"); + PrintAndLogEx(ERR, "Authentication Failed UL-C"); return 0; } } else { - if ( !ul_select(card) ) return 0; + if (!ul_select(card, false)) return 0; if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { - DropField(); - PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(ERR, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -268,7 +271,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool return 1; } -static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ +static int ulev1_getVersion(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -285,21 +288,24 @@ static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ // return 0; // } -static int ulev1_readCounter( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readCounter(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READ_CNT, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readTearing( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readTearing(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_CHECKTEAR, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -320,9 +326,9 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // UL responds with read of page 0, fudan doesn't respond. // // make sure field is off before calling this function -static int ul_fudan_check( void ){ +static int ul_fudan_check(void) { iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -338,20 +344,17 @@ static int ul_fudan_check( void ){ return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP } -static int ul_print_default( uint8_t *data){ + +static int ul_print_default(uint8_t *data) { uint8_t uid[7]; - uid[0] = data[0]; - uid[1] = data[1]; - uid[2] = data[2]; - uid[3] = data[4]; - uid[4] = data[5]; - uid[5] = data[6]; - uid[6] = data[7]; + memcpy(uid, data, 3); + memcpy(uid+3, data+4, 4); - PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL," UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); - if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP + + if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages @@ -360,13 +363,13 @@ static int ul_print_default( uint8_t *data){ } } // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 - int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; if ( data[3] == crc0 ) PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); - int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; if ( data[8] == crc1 ) PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else @@ -374,14 +377,14 @@ static int ul_print_default( uint8_t *data){ PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), printBits(1, data+10), printBits(1, data+11) ); PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", - sprint_hex(data + 12, 4), + sprint_hex(data+12, 4), printBits(1, data+12), printBits(1, data+13), printBits(1, data+14), @@ -391,6 +394,7 @@ static int ul_print_default( uint8_t *data){ return 0; } + static int ndef_print_CC(uint8_t *data) { // no NDEF message if(data[0] != 0xe1) @@ -414,55 +418,55 @@ static int ndef_print_CC(uint8_t *data) { return 0; } + int ul_print_type(uint32_t tagtype, uint8_t spaces){ char spc[11] = " "; spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) + if (tagtype & UL ) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_C) + else if (tagtype & UL_C) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_EV1_48) + else if (tagtype & UL_EV1_48) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) + else if (tagtype & UL_EV1_128) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); - else if ( tagtype & NTAG ) + else if (tagtype & NTAG) PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); - else if ( tagtype & NTAG_203 ) + else if (tagtype & NTAG_203) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); - else if ( tagtype & NTAG_210 ) + else if (tagtype & NTAG_210) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); - else if ( tagtype & NTAG_212 ) + else if (tagtype & NTAG_212) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); - else if ( tagtype & NTAG_213 ) + else if (tagtype & NTAG_213) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); - else if ( tagtype & NTAG_215 ) + else if (tagtype & NTAG_215) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); - else if ( tagtype & NTAG_216 ) + else if (tagtype & NTAG_216) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); - else if ( tagtype & NTAG_I2C_1K ) + else if (tagtype & NTAG_I2C_1K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) + else if (tagtype & NTAG_I2C_2K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); - else if ( tagtype & MY_D ) + else if (tagtype & MY_D) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); - else if ( tagtype & MY_D_NFC ) + else if (tagtype & MY_D_NFC) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); - else if ( tagtype & MY_D_MOVE ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_LEAN ) + else if (tagtype & MY_D_MOVE) + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move | my-d\x99move NFC (SLE 66R01P)", spacer); + else if (tagtype & MY_D_MOVE_LEAN) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); - else if ( tagtype & FUDAN_UL ) + else if (tagtype & FUDAN_UL) PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } -static int ulc_print_3deskey( uint8_t *data){ + +static int ulc_print_3deskey(uint8_t *data) { PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); @@ -471,27 +475,22 @@ static int ulc_print_3deskey( uint8_t *data){ return 0; } -static int ulc_print_configuration( uint8_t *data){ + +static int ulc_print_configuration(uint8_t *data) { PrintAndLogEx(NORMAL, "--- UL-C Configuration"); - PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", sprint_hex(data, 2), printBits(1, data), printBits(1, data+1) ); - PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", - sprint_hex(data+4, 4), - printBits(1, data+4), - printBits(1, data+5), - printBits(1, data+6), - printBits(1, data+7) - ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s", sprint_hex(data+4, 2)); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); - if ( validAuth ) + if (validAuth) PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ - if ( data[8] == 0){ + if (data[8] == 0) { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); @@ -504,7 +503,8 @@ static int ulc_print_configuration( uint8_t *data){ return 0; } -static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ + +static int ulev1_print_configuration(uint8_t *data, uint8_t startPage) { PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); @@ -515,33 +515,34 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ uint8_t vctid = data[5]; PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); - if ( data[3] < 0xff ) - PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); + if (data[3] < 0xff) + PrintAndLogEx(NORMAL, " - page %d and above need authentication", data[3]); else PrintAndLogEx(NORMAL, " - pages don't need authentication"); PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); - if ( authlim == 0) + if (authlim == 0) PrintAndLogEx(NORMAL, " - Unlimited password attempts"); else PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } -static int ulev1_print_counters(){ + +static int ulev1_print_counters(void) { PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; for ( uint8_t i = 0; i<3; ++i) { - ulev1_readTearing(i,tear,sizeof(tear)); - len = ulev1_readCounter(i,counter, sizeof(counter) ); + ulev1_readTearing(i, tear, sizeof(tear)); + len = ulev1_readCounter(i, counter, sizeof(counter) ); if (len == 3) { PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); @@ -550,6 +551,7 @@ static int ulev1_print_counters(){ return len; } + static int ulev1_print_signature( uint8_t *data, uint8_t len){ PrintAndLogEx(NORMAL, "\n--- Tag Signature"); PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); @@ -561,9 +563,10 @@ static int ulev1_print_signature( uint8_t *data, uint8_t len){ return 0; } + static int ulev1_print_version(uint8_t *data){ PrintAndLogEx(NORMAL, "\n--- Tag Version"); - PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Raw bytes : %s", sprint_hex(data, 8) ); PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); @@ -574,154 +577,131 @@ static int ulev1_print_version(uint8_t *data){ return 0; } -/* -static int ulc_magic_test(){ - // Magic Ultralight test - // Magic UL-C, by observation, - // 1) it seems to have a static nonce response to 0x1A command. - // 2) the deskey bytes is not-zero:d out on as datasheet states. - // 3) UID - changeable, not only, but pages 0-1-2-3. - // 4) use the ul_magic_test ! magic tags answers specially! - int returnValue = UL_ERROR; - iso14a_card_select_t card; - uint8_t nonce1[11] = {0x00}; - uint8_t nonce2[11] = {0x00}; - int status = ul_select(&card); - if ( !status ){ - return UL_ERROR; - } - status = ulc_requestAuthentication(nonce1, sizeof(nonce1)); - if ( status > 0 ) { - status = ulc_requestAuthentication(nonce2, sizeof(nonce2)); - returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; - } else { - returnValue = UL; - } - DropField(); - return returnValue; -} -*/ -static int ul_magic_test(){ - // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE - // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: +static int ul_magic_test(void) { + // try a compatibility write to page0, and see if tag answers with ACK/NACK to the first part of the command iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; - int status = ul_comp_write(0, NULL, 0); - DropField(); - if ( status == 0 ) + int status = ul_comp_write_ex(0, NULL, 0, true); + if (status == 0) { return MAGIC; + } return 0; } + uint32_t GetHF14AMfU_Type(void){ TagTypeUL_t tagtype = UNKNOWN; iso14a_card_select_t card; uint8_t version[10] = {0x00}; - int status = 0; int len; - if (!ul_select(&card)) return UL_ERROR; - - // Ultralight - ATQA / SAK - if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + if (!ul_select(&card, true)) { DropField(); + msleep(200); return UL_ERROR; } - if ( card.uid[0] != 0x05) { - - len = ulev1_getVersion(version, sizeof(version)); + // Check for Ultralight Family + if (card.uidlen != 7 || (card.sak & 0x38) != 0x00) { DropField(); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + return UL_ERROR; + } - switch (len) { - case 0x0A: { - - if ( version[2] == 0x03 && version[6] == 0x0B ) - tagtype = UL_EV1_48; - else if ( version[2] == 0x03 && version[6] != 0x0B ) - tagtype = UL_EV1_128; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B ) - tagtype = NTAG_210; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E ) - tagtype = NTAG_212; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F ) - tagtype = NTAG_213; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11 ) - tagtype = NTAG_215; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13 ) - tagtype = NTAG_216; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13 ) - tagtype = NTAG_I2C_1K; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15 ) - tagtype = NTAG_I2C_2K; - else if ( version[2] == 0x04 ) - tagtype = NTAG; - - break; - } - case 0x01: tagtype = UL_C; break; - case 0x00: tagtype = UL; break; - case -1 : tagtype = (UL | UL_C | NTAG_203); break; // could be UL | UL_C magic tags - default : tagtype = UNKNOWN; break; + if (card.uid[0] != 0x05) { + len = ulev1_getVersion(version, sizeof(version)); + if (len == 10) { + if (version[2] == 0x03 && version[6] == 0x0B) + tagtype = UL_EV1_48; + else if (version[2] == 0x03 && version[6] != 0x0B) + tagtype = UL_EV1_128; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B) + tagtype = NTAG_210; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E) + tagtype = NTAG_212; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F) + tagtype = NTAG_213; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11) + tagtype = NTAG_215; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13) + tagtype = NTAG_216; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13) + tagtype = NTAG_I2C_1K; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15) + tagtype = NTAG_I2C_2K; + else if (version[2] == 0x04) + tagtype = NTAG; } + // UL vs UL-C vs ntag203 test - if (tagtype & (UL | UL_C | NTAG_203)) { - if ( !ul_select(&card) ) return UL_ERROR; + if (tagtype == UNKNOWN) { + ul_halt(); + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } // do UL_C check first... uint8_t nonce[11] = {0x00}; - status = ulc_requestAuthentication(nonce, sizeof(nonce)); - DropField(); - if (status > 1) { + len = ulc_requestAuthentication(nonce, sizeof(nonce)); + ul_halt(); + if (len == 11) { tagtype = UL_C; } else { // need to re-select after authentication error - if ( !ul_select(&card) ) return UL_ERROR; + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } uint8_t data[16] = {0x00}; - // read page 0x26-0x29 (last valid ntag203 page) - status = ul_read(0x26, data, sizeof(data)); - if ( status <= 1 ) { + // read page 0x29 (last valid ntag203 page) + len = ul_read(0x29, data, sizeof(data)); + if (len <= 1) { tagtype = UL; } else { // read page 0x30 (should error if it is a ntag203) - status = ul_read(0x30, data, sizeof(data)); - if ( status <= 1 ){ + len = ul_read(0x30, data, sizeof(data)); + if (len <= 1) { + ul_halt(); tagtype = NTAG_203; - } else { - tagtype = UNKNOWN; } } - DropField(); } } if (tagtype & UL) { tagtype = ul_fudan_check(); - DropField(); + ul_halt(); } - } else { - DropField(); - // Infinition MY-D tests Exam high nibble + + } else { // manufacturer Infineon. Check for my-d variants + uint8_t nib = (card.uid[1] & 0xf0) >> 4; - switch ( nib ){ - // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two - case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes + switch (nib) { + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = MY_D_NFC; break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = MY_D_MOVE; break; //or SLE 66R01P // 38 pages of 4 bytes + case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } tagtype |= ul_magic_test(); + if (tagtype == (UNKNOWN | MAGIC)) tagtype = (UL_MAGIC); + + DropField(); + msleep(200); + + printf("Tagtype: %08x\n", tagtype); return tagtype; } + static int usage_hf_mfu_info(void) { PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); @@ -740,24 +720,21 @@ static int usage_hf_mfu_info(void) { return 0; } -static int CmdHF14AMfUInfo(const char *Cmd){ + +static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t authlim = 0xff; - uint8_t data[16] = {0x00}; iso14a_card_select_t card; - int status; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; bool locked = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t dataLen = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authkeyptr = authenticationkey; - uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; - char tempStr[50]; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -768,15 +745,14 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return usage_hf_mfu_info(); case 'k': case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; // handled as bytes from now on - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); errors = true; } cmdp += 2; + keyLen /= 2; hasAuthKey = true; break; case 'l': @@ -793,27 +769,35 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } //Validations - if(errors) return usage_hf_mfu_info(); + if (errors) + return usage_hf_mfu_info(); TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); // Swap endianness - if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); + if (swapEndian && hasAuthKey) + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4 ); - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select(&card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } // read pages 0,1,2,3 (should read 4pages) - status = ul_read(0, data, sizeof(data)); - if ( status == -1 ) { + uint8_t data[16]; + len = ul_read(0, data, sizeof(data)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); - return status; - } else if (status == 16) { + return -1; + } else if (len == 16) { ul_print_default(data); ndef_print_CC(data+12); } else { @@ -825,36 +809,41 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // read pages 0x28, 0x29, 0x2A, 0x2B uint8_t ulc_conf[16] = {0x00}; - status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); - if ( status == -1 ){ - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + len = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + return -1; + } + if (len == 16) { + ulc_print_configuration(ulc_conf); + } else { + locked = true; } - if (status == 16) ulc_print_configuration(ulc_conf); - else locked = true; if ((tagtype & MAGIC)) { //just read key uint8_t ulc_deskey[16] = {0x00}; - status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); - if ( status == -1 ) { + len = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); - return status; + return -1; } - if (status == 16) ulc_print_3deskey(ulc_deskey); - + if (len == 16) ulc_print_3deskey(ulc_deskey); } else { - DropField(); // if we called info with key, just return - if ( hasAuthKey ) return 1; + if (hasAuthKey) { + DropField(); + return 1; + } // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { - key = default_3des_keys[i]; + uint8_t *key = default_3des_keys[i]; if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); @@ -862,6 +851,7 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return 1; } } + DropField(); return 1; } } @@ -872,53 +862,66 @@ static int CmdHF14AMfUInfo(const char *Cmd){ if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { if (ulev1_print_counters() != 3) { // failed - re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; - status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + len = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + return -1; } - if (status == 32) ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); - else { + if (len == 32) { + ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); + } else { // re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_210 | NTAG_212 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K))) { uint8_t version[10] = {0x00}; - status = ulev1_getVersion(version, sizeof(version)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + len = ulev1_getVersion(version, sizeof(version)); + if (len == -1) { DropField(); - return status; - } else if (status == 10) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + return -1; + } else if (len == 10) { ulev1_print_version(version); } else { locked = true; - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } uint8_t startconfigblock = 0; uint8_t ulev1_conf[16] = {0x00}; // config blocks always are last 4 pages - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { startconfigblock = UL_MEMORY_ARRAY[idx]-3; + break; + } + } - if (startconfigblock){ // if we know where the config block is... - status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + if (startconfigblock) { // if we know where the config block is... + len = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); + if (len == -1) { DropField(); - return status; - } else if (status == 16) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + return -1; + } else if (len == 16) { // save AUTHENTICATION LIMITS for later: authlim = (ulev1_conf[4] & 0x07); ulev1_print_configuration(ulev1_conf, startconfigblock); @@ -929,17 +932,20 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // 0 = limitless. // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. - if ( !authlim && !hasAuthKey ) { + if (!authlim && !hasAuthKey) { PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { - key = default_pwd_pack[i]; + uint8_t *key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); break; } else { - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if (len < 1) PrintAndLogEx(WARNING, "password not known"); @@ -947,8 +953,11 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } DropField(); - if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + + if (locked) + PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); PrintAndLogEx(NORMAL, ""); + return 1; } @@ -969,48 +978,35 @@ static int usage_hf_mfu_wrbl(void) { return 0; } + static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; - uint8_t cmdp = 0; - uint8_t keylen = 0; uint8_t blockdata[20] = {0x00}; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { case 'h': case 'H': return usage_hf_mfu_wrbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1044,24 +1040,28 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ if(errors) return usage_hf_mfu_wrbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_wrbl(); + if (blockNo == -1) return usage_hf_mfu_wrbl(); // starting with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian && hasAuthKey) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); if ( blockNo <= 3) PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); @@ -1070,27 +1070,24 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes,blockdata,4); + memcpy(c.d.asBytes, blockdata, 4); - if ( hasAuthKey ) { - c.arg[1] = 1; - memcpy(c.d.asBytes+4,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes+4,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes+4, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { PrintAndLogEx(ERR, "Command execute timeout"); } + DropField(); return 0; } @@ -1112,18 +1109,17 @@ static int usage_hf_mfu_rdbl(void) { return 0; } + static int CmdHF14AMfURdBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t keylen = 0; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -1134,24 +1130,15 @@ static int CmdHF14AMfURdBl(const char *Cmd){ return usage_hf_mfu_rdbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1173,43 +1160,43 @@ static int CmdHF14AMfURdBl(const char *Cmd){ break; } //Validations - if(errors) return usage_hf_mfu_rdbl(); + if (errors) return usage_hf_mfu_rdbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_rdbl(); + if (blockNo == -1) return usage_hf_mfu_rdbl(); // start with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); //Read Block UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - if ( hasAuthKey ){ - c.arg[1] = 1; - memcpy(c.d.asBytes,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; @@ -1222,6 +1209,7 @@ static int CmdHF14AMfURdBl(const char *Cmd){ } else { PrintAndLogEx(ERR, "Command execute time-out"); } + DropField(); return 0; } @@ -1229,196 +1217,43 @@ static int CmdHF14AMfURdBl(const char *Cmd){ // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. -static int usage_hf_mfu_dump(void) { - PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLogEx(NORMAL, "It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); - PrintAndLogEx(NORMAL, " Options : "); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); - PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); - PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " sample : hf mfu dump"); - PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); - PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); - PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); - return 0; -} +typedef struct { + uint8_t version[8]; + uint8_t tbo[2]; + uint8_t tbo1[1]; + uint8_t pages; // max page number in dump + uint8_t signature[32]; + uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag + uint8_t data[1024]; +} mfu_dump_t; -static int CmdHF14AMfUDump(const char *Cmd){ - FILE *fout; - char filename[FILE_PATH_SIZE] = {0x00}; - char *fnameptr = filename; - uint8_t *lockbytes_t = NULL; - uint8_t lockbytes[2] = {0x00}; - uint8_t *lockbytes_t2 = NULL; - uint8_t lockbytes2[2] = {0x00}; - bool bit[16] = {0x00}; - bool bit2[16] = {0x00}; - uint8_t data[1024] = {0x00}; - bool hasAuthKey = false; - int i = 0; - int Pages = 16; +static void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage, TagTypeUL_t tagtype) { + bool tmplockbit = false; - uint8_t dataLen = 0; - uint8_t cmdp = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - size_t fileNlen = 0; - bool errors = false; - bool swapEndian = false; - bool manualPages = false; - uint8_t startPage = 0; - char tempStr[50]; - unsigned char cleanASCII[4]; + bool bit[16] = {false}; + bool bit2[16] = {false}; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { - case 'h': - case 'H': - return usage_hf_mfu_dump(); - case 'k': - case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; - } - cmdp += 2; - hasAuthKey = true; - break; - case 'l': - case 'L': - swapEndian = true; - cmdp++; - break; - case 'n': - case 'N': - fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; - if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; - cmdp += 2; - break; - case 'p': - case 'P': - startPage = param_get8(Cmd, cmdp+1); - manualPages = true; - cmdp += 2; - break; - case 'q': - case 'Q': - Pages = param_get8(Cmd, cmdp+1); - cmdp += 2; - manualPages = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - if(errors) break; + // standard lock bits + for(int i = 0; i < 16; i++){ + bit[i] = card->data[10+i/8] & (1 << (7-i%8)); } - //Validations - if(errors) return usage_hf_mfu_dump(); - - if (swapEndian && hasAuthKey) - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); - - TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; - - if (!manualPages) //get number of pages to read - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) - Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 - - ul_print_type(tagtype, 0); - PrintAndLogEx(NORMAL, "Reading tag memory..."); - UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; - if ( hasAuthKey ) { - if (tagtype & UL_C) - c.arg[2] = 1; //UL_C auth - else - c.arg[2] = 2; //UL_EV1/NTAG auth - - memcpy(c.d.asBytes, authKeyPtr, dataLen); - } - - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLogEx(ERR, "Command execute time-out"); - return 1; - } - if (resp.arg[0] != 1) { - PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); - return 1; - } - - uint32_t startindex = resp.arg[2]; - uint32_t bufferSize = resp.arg[1]; - if (bufferSize > sizeof(data)) { - PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); - bufferSize = sizeof(data); - } - GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); - - Pages = bufferSize/4; - // Load lock bytes. - int j = 0; - - lockbytes_t = data + 8; - lockbytes[0] = lockbytes_t[2]; - lockbytes[1] = lockbytes_t[3]; - for(j = 0; j < 16; j++){ - bit[j] = lockbytes[j/8] & ( 1 <<(7-j%8)); - } - - // Load bottom lockbytes if available - // TODO -- FIGURE OUT LOCK BYTES FOR TO EV1 and/or NTAG - if ( Pages == 44 ) { - lockbytes_t2 = data + (40*4); - lockbytes2[0] = lockbytes_t2[2]; - lockbytes2[1] = lockbytes_t2[3]; - for (j = 0; j < 16; j++) { - bit2[j] = lockbytes2[j/8] & ( 1 <<(7-j%8)); - } - } - - // add keys to block dump - if (hasAuthKey) { - if (!swapEndian){ - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); - } else { - authKeyPtr = authenticationkey; - } - - if (tagtype & UL_C){ //add 4 pages - memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; - } else { // 2nd page from end - memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); + // dynamic lock bits + // TODO -- FIGURE OUT LOCK BYTES FOR EV1 and/or NTAG + if (tagtype & UL_C) { + for (int i = 0; i < 16; i++) { + bit2[i] = card->data[40*4+i/8] & (1 << (7-i%8)); } } PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); PrintAndLogEx(NORMAL, "---------+-------------+---+------"); - for (i = 0; i < Pages; ++i) { - if ( i < 3 ) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); + + for (int i = startpage; i < startpage + pages; i++) { + if (i < 3) { + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i, i, sprint_hex(card->data + i * 4, 4)); continue; } switch(i){ @@ -1466,34 +1301,240 @@ static int CmdHF14AMfUDump(const char *Cmd){ default: break; } - // convert unprintable characters and line breaks to dots - memcpy(cleanASCII, data+i*4, 4); - clean_ascii(cleanASCII, 4); - - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i, i, sprint_hex(card->data + i * 4, 4), tmplockbit, sprint_ascii(card->data + i * 4, 4)); } PrintAndLogEx(NORMAL, "---------------------------------"); +} - // user supplied filename? - if (fileNlen < 1) { - // UID = data 0-1-2 4-5-6-7 (skips a beat) - sprintf(fnameptr,"%02X%02X%02X%02X%02X%02X%02X.bin", - data[0],data[1], data[2], data[4],data[5],data[6], data[7]); - } else { - sprintf(fnameptr + fileNlen,".bin"); - } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLogEx(NORMAL, "Could not create file name %s", filename); - return 1; - } - fwrite( data, 1, Pages*4, fout ); - fclose(fout); +static int usage_hf_mfu_dump(void) { + PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); + PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); + PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLogEx(NORMAL, "It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, " f : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); + PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); - PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu dump"); + PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); + PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); return 0; } + +static int CmdHF14AMfUDump(const char *Cmd){ + + char filename[FILE_PATH_SIZE] = {'\0'}; + size_t fileNameLen = 0; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; + bool hasAuthKey = false; + uint8_t cmdp = 0; + bool errors = false; + bool swapEndian = false; + bool manualPages = false; + uint8_t startPage = 0; + int Pages = 16; + iso14a_card_select_t card_select; + mfu_dump_t card; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_mfu_dump(); + case 'k': + case 'K': + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; + } + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; + break; + case 'l': + case 'L': + swapEndian = true; + cmdp++; + break; + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + if (fileNameLen == 0) errors = true; + if (fileNameLen > FILE_PATH_SIZE-5) fileNameLen = FILE_PATH_SIZE-5; + cmdp += 2; + break; + case 'p': + case 'P': + startPage = param_get8(Cmd, cmdp+1); + manualPages = true; + cmdp += 2; + break; + case 'q': + case 'Q': + Pages = param_get8(Cmd, cmdp+1); + cmdp += 2; + manualPages = true; + break; + default: + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if (errors) break; + } + + //Validations + if (errors) return usage_hf_mfu_dump(); + + if (swapEndian && hasAuthKey) + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); + + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + + if (tagtype == UL_ERROR) { + return -1; + } + + uint8_t maxPages = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { + maxPages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 + break; + } + } + + if (!manualPages) { + Pages = maxPages; + } else { + if (startPage + Pages - 1 > maxPages - 1) { + PrintAndLogEx(ERR, "Invalid page range. Card has only %d readable pages.", maxPages); + DropField(); + return 1; + } + } + + ul_print_type(tagtype, 0); + + PrintAndLogEx(NORMAL, "Reading tag memory..."); + memset(&card, 0x00, sizeof(card)); + UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, Pages}}; + if (hasAuthKey) { + if (tagtype & UL_C) + c.arg[2] = 1; //UL_C auth + else + c.arg[2] = 2; //UL_EV1/NTAG auth + memcpy(c.d.asBytes, authenticationkey, keyLen); + } + + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); + return 1; + } + if (resp.arg[0] != 1) { + PrintAndLogEx(ERR, "Failed reading card"); + DropField(); + return 1; + } + + uint32_t startindex = resp.arg[2]; + uint32_t bufferSize = resp.arg[1]; + if (bufferSize > sizeof(card.data)) { + PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); + bufferSize = sizeof(card.data); + } + + if (!GetFromBigBuf(card.data + startPage*4, bufferSize, startindex, NULL, -1, false)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); + return 1; + } + + // not ul_c and not std ul then attempt to collect + // VERSION, SIGNATURE, COUNTERS, TEARING, PACK + if (!(tagtype & UL_C || tagtype & UL)) { + //attempt to read pack + if (!ul_auth_select(&card_select, tagtype, true, authenticationkey, card.data + maxPages*4 - 4, 2)) { + //reset pack + card.data[maxPages*4 - 4] = 0; + card.data[maxPages*4 - 3] = 0; + } + + if (hasAuthKey) { + uint8_t dummy_pack[2]; + ul_auth_select(&card_select, tagtype, hasAuthKey, authenticationkey, dummy_pack, sizeof(dummy_pack)); + } else { + ul_select(&card_select, false); + } + ulev1_getVersion(card.version, sizeof(card.version)); + for (uint8_t n = 0; n < 3; ++n) { + ulev1_readTearing(n, &card.counter_tearing[n][3], 1); + ulev1_readCounter(n, &card.counter_tearing[n][0], 3); + } + + ulev1_readSignature(card.signature, sizeof(card.signature)); + } + + DropField(); + + // add key to dump data + if (hasAuthKey) { + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); + if (tagtype & UL_C){ // additional 4 pages + memcpy(card.data + maxPages*4, authenticationkey, keyLen); + maxPages += 4; + } else { // 2nd page from end + memcpy(card.data + (maxPages*4) - 8, authenticationkey, 4); + } + } + + printMFUdumpEx(&card, Pages, startPage, tagtype); + + if (!manualPages) { + // user supplied filename? + if (fileNameLen < 1) { + char *fptr = filename; + fptr += sprintf(fptr, "hf-mfu-"); + uint8_t UID[] = {card.data[0], card.data[1], card.data[2], card.data[4], card.data[5], card.data[6], card.data[7]}; + FillFileNameByUID(fptr, UID, "-dump.bin", 7); + } else { + sprintf(filename + fileNameLen, ".bin"); + } + +#define MFU_DUMP_PREFIX_LENGTH (sizeof(card) - sizeof(card.data)) + + FILE *fout; + if ((fout = fopen(filename, "wb")) == NULL) { + PrintAndLogEx(ERR, "Could not create file name %s", filename); + return 1; + } + fwrite(&card, 1, MFU_DUMP_PREFIX_LENGTH + maxPages*4, fout); + fclose(fout); + + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", maxPages, MFU_DUMP_PREFIX_LENGTH + maxPages*4, filename); + } + + return 0; +} + + //------------------------------------------------------------------------------- // Ultralight C Methods //------------------------------------------------------------------------------- @@ -1533,110 +1574,16 @@ static int CmdHF14AMfucAuth(const char *Cmd){ } uint8_t *key = default_3des_keys[keyNo]; - if (ulc_authentication(key, true)) + if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); - else + } else { + DropField(); PrintAndLogEx(WARNING, "Authentication failed"); - - return 0; -} - -/** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl - -int CmdTestDES(const char * cmd) -{ - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); - DES_cblock RndA, RndB; - - PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); - { - uint8_t e_RndB[8] = {0x00}; - unsigned char RndARndB[16] = {0x00}; - - DES_cblock iv = { 0 }; - DES_key_schedule ks1,ks2; - DES_cblock key1,key2; - - memcpy(key,key3_3des_data,16); - memcpy(key1,key,8); - memcpy(key2,key+8,8); - - - DES_set_key((DES_cblock *)key1,&ks1); - DES_set_key((DES_cblock *)key2,&ks2); - - DES_random_key(&RndA); - PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); - //void DES_ede2_cbc_encrypt(const unsigned char *input, - // unsigned char *output, long length, DES_key_schedule *ks1, - // DES_key_schedule *ks2, DES_cblock *ivec, int enc); - DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); - rol(RndB,8); - memcpy(RndARndB,RndA,8); - memcpy(RndARndB+8,RndB,8); - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); - DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); - - } - PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); - { - uint8_t random_a[8] = { 0 }; - uint8_t enc_random_a[8] = { 0 }; - uint8_t random_b[8] = { 0 }; - uint8_t enc_random_b[8] = { 0 }; - uint8_t random_a_and_b[16] = { 0 }; - des3_context ctx = { 0 }; - - memcpy(random_a, RndA,8); - - uint8_t output[8] = { 0 }; - uint8_t iv[8] = { 0 }; - - PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); - - des3_set2key_dec(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_DECRYPT // int mode - , sizeof(random_b) // size_t length - , iv // unsigned char iv[8] - , enc_random_b // const unsigned char *input - , random_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); - - rol(random_b,8); - memcpy(random_a_and_b ,random_a,8); - memcpy(random_a_and_b+8,random_b,8); - - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); - - des3_set2key_enc(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_ENCRYPT // int mode - , sizeof(random_a_and_b) // size_t length - , enc_random_b // unsigned char iv[8] - , random_a_and_b // const unsigned char *input - , random_a_and_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } return 0; } -**/ + // // Mifare Ultralight C - Set password @@ -1668,16 +1615,18 @@ static int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - if ( (resp.arg[0] & 0xff) == 1) + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); + if ((resp.arg[0] & 0xff) == 1) { PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); - else{ + return 0; + } else { PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } - } - else { - PrintAndLogEx(ERR, "command execution time out"); + } else { + DropField(); + PrintAndLogEx(ERR, "command execution timeout"); return 1; } @@ -1715,6 +1664,7 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } @@ -1732,7 +1682,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } @@ -1745,7 +1696,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = uid[6]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1758,14 +1710,17 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = oldblock2[3]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } + DropField(); return 0; } + static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; @@ -1875,6 +1830,7 @@ static command_t CommandTable[] = {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"}, {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, + // {"restore", CmdHF14AMfURestore, 0, "Restore a dump onto a MFU MAGIC tag"}, {"rdbl", CmdHF14AMfURdBl, 0, "Read block"}, {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, {"cauth", CmdHF14AMfucAuth, 0, "Authentication - Ultralight C"}, diff --git a/client/util.c b/client/util.c index eef97e2a..cd18fc00 100644 --- a/client/util.c +++ b/client/util.c @@ -117,9 +117,8 @@ void AddLogCurrentDT(char *fileName) { AddLogLine(fileName, "\nanticollision: ", buff); } -void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) { +void FillFileNameByUID(char *fileName, uint8_t *uid, char *ext, int byteCount) { char * fnameptr = fileName; - memset(fileName, 0x00, 200); for (int j = 0; j < byteCount; j++, fnameptr += 2) sprintf(fnameptr, "%02x", (unsigned int) uid[j]); @@ -323,13 +322,12 @@ uint32_t SwapBits(uint32_t value, int nrbits) { uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize){ static uint8_t buf[64]; memset(buf, 0x00, 64); - uint8_t *tmp = buf; for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ for (size_t i = 0; i < blockSize; i++){ - tmp[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; + buf[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; } } - return tmp; + return buf; } //assumes little endian @@ -338,7 +336,7 @@ char *printBits(size_t const size, void const * const ptr) unsigned char *b = (unsigned char*) ptr; unsigned char byte; static char buf[1024]; - char * tmp = buf; + char *tmp = buf; int i, j; for (i=size-1;i>=0;i--) @@ -354,7 +352,7 @@ char *printBits(size_t const size, void const * const ptr) return buf; } -char * printBitsPar(const uint8_t *b, size_t len) { +char *printBitsPar(const uint8_t *b, size_t len) { static char buf1[512] = {0}; static char buf2[512] = {0}; static char *buf; @@ -519,7 +517,8 @@ int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) return 0; } -int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) + +int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) { int bg, en, temp, i; @@ -528,6 +527,8 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) if (param_getptr(line, &bg, &en, paramnum)) return 1; + if (en - bg + 1 > *hexcnt) return 1; + *hexcnt = en - bg + 1; if (*hexcnt % 2) //error if not complete hex bytes return 1; diff --git a/common/protocols.h b/common/protocols.h index 39fed40f..ab556516 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -105,44 +105,49 @@ NXP/Philips CUSTOM COMMANDS #define ISO14443A_CMD_REQA 0x26 -#define ISO14443A_CMD_READBLOCK 0x30 #define ISO14443A_CMD_WUPA 0x52 #define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_3 0x97 -#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? #define ISO14443A_CMD_HALT 0x50 #define ISO14443A_CMD_RATS 0xE0 -#define MIFARE_AUTH_KEYA 0x60 -#define MIFARE_AUTH_KEYB 0x61 -#define MIFARE_MAGICWUPC1 0x40 -#define MIFARE_MAGICWUPC2 0x43 -#define MIFARE_MAGICWIPEC 0x41 -#define MIFARE_CMD_INC 0xC0 -#define MIFARE_CMD_DEC 0xC1 -#define MIFARE_CMD_RESTORE 0xC2 -#define MIFARE_CMD_TRANSFER 0xB0 +#define MIFARE_CMD_READBLOCK 0x30 +#define MIFARE_CMD_WRITEBLOCK 0xA0 +#define MIFARE_AUTH_KEYA 0x60 +#define MIFARE_AUTH_KEYB 0x61 +#define MIFARE_MAGICWUPC1 0x40 +#define MIFARE_MAGICWUPC2 0x43 +#define MIFARE_MAGICWIPEC 0x41 +#define MIFARE_CMD_INC 0xC0 +#define MIFARE_CMD_DEC 0xC1 +#define MIFARE_CMD_RESTORE 0xC2 +#define MIFARE_CMD_TRANSFER 0xB0 -#define MIFARE_EV1_PERSONAL_UID 0x40 -#define MIFARE_EV1_SETMODE 0x43 +#define MIFARE_EV1_PERSONAL_UID 0x40 +#define MIFARE_EV1_SETMODE 0x43 +#define MIFARE_ULC_WRITE 0xA2 +#define MIFARE_ULC_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULC_AUTH_1 0x1A +#define MIFARE_ULC_AUTH_2 0xAF -#define MIFARE_ULC_WRITE 0xA2 -//#define MIFARE_ULC__COMP_WRITE 0xA0 -#define MIFARE_ULC_AUTH_1 0x1A -#define MIFARE_ULC_AUTH_2 0xAF +#define MIFARE_ULEV1_AUTH 0x1B +#define MIFARE_ULEV1_VERSION 0x60 +#define MIFARE_ULEV1_FASTREAD 0x3A +#define MIFARE_ULEV1_WRITE 0xA2 +#define MIFARE_ULEV1_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULEV1_READ_CNT 0x39 +#define MIFARE_ULEV1_INCR_CNT 0xA5 +#define MIFARE_ULEV1_READSIG 0x3C +#define MIFARE_ULEV1_CHECKTEAR 0x3E +#define MIFARE_ULEV1_VCSL 0x4B + +// mifare 4bit card answers +#define CARD_ACK 0x0A // 1010 - ACK +#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) +#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error -#define MIFARE_ULEV1_AUTH 0x1B -#define MIFARE_ULEV1_VERSION 0x60 -#define MIFARE_ULEV1_FASTREAD 0x3A -//#define MIFARE_ULEV1_WRITE 0xA2 -//#define MIFARE_ULEV1_COMP_WRITE 0xA0 -#define MIFARE_ULEV1_READ_CNT 0x39 -#define MIFARE_ULEV1_INCR_CNT 0xA5 -#define MIFARE_ULEV1_READSIG 0x3C -#define MIFARE_ULEV1_CHECKTEAR 0x3E -#define MIFARE_ULEV1_VCSL 0x4B /** 06 00 = INITIATE From dd8e45133090d9684a7f0d37ef59137e6b7159a9 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 16 Jun 2019 15:35:10 +1000 Subject: [PATCH 09/29] T55xx downlink Modes Changes : - Added t55xx downlink protocols (long leading reference, leading 0 and 1 of 4) - Added function to all read to call differnet downlink functions (to match write) - Update functions to support using differnet downlink modes. - Added support for calling downlink modes for lf t55 read, write and detect - Added new function lf t55 bruteforcedl to support downlink modes as well as try each mode for each password in password file. for functions with downlink mode extenstion. e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference, '2' Leading Zero, '3' 1 of 4 --- armsrc/lfops.c | 442 +++++++++++++++++++++++++++++++++++++++++++- client/cmdlft55xx.c | 332 +++++++++++++++++++++++++++++++-- client/cmdlft55xx.h | 3 +- 3 files changed, 755 insertions(+), 22 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 81fdd7a6..36efe729 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1203,6 +1203,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 +// Long Leading Reference +#define Reference_llr (136+18)*8 // Needs to be WRITR_0 + 136 clocks. void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1220,6 +1222,265 @@ void T55xxWriteBit(int bit) { WaitUS(WRITE_GAP); } +void T55xxWrite_LLR (void) +{ + TurnReadLFOn (Reference_llr); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP); +} + +#define START_GAPlz 31*8 +#define WRITE_GAPlz 20*8 +#define WRITElz_0 18*8 +#define WRITElz_1 40*8 +#define READ_GAP 15*8 + +void T55xxWriteBit_Leading0(int bit) { + if (!bit) + TurnReadLFOn(WRITElz_0); + else + TurnReadLFOn(WRITElz_1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAPlz); +// WaitUS(160); +} + +#define START_GAP1of4 31*8 // SPEC: 1*8 to 50*8 - typ 10*8 (or 15fc) +#define WRITE_GAP1of4 20*8 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) +// 00 = reference // 8 * 8 - - 68 * 8 +#define WRITE1of4_00 18*8 // SPEC: 8*8 to 68*8 - typ 24*8 (or 24fc) +#define WRITE1of4_01 34*8 // SPEC: dref+9 - dref+16 - dref+24 +#define WRITE1of4_10 50*8 // SPEC: dref+25 - dref+32 - dref+40 +#define WRITE1of4_11 66*8 // SPEC: dref+41 - dref+48 - dref+56 +#define READ1of4_GAP 15*8 + +void T55xxWriteBit_1of4(int bits) { + + switch (bits) + { + case 0 : TurnReadLFOn(WRITE1of4_00); break; + case 1 : TurnReadLFOn(WRITE1of4_01); break; + case 2 : TurnReadLFOn(WRITE1of4_10); break; + case 3 : TurnReadLFOn(WRITE1of4_11); break; + default: + TurnReadLFOn(WRITE1of4_00); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP1of4); +// WaitUS(160); +} + +void T55xxWriteBlockExt_Leading0 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + uint32_t i = 0; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + WaitUS(START_GAPlz); + + + /* + 0 : Leading Zero + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 0 1p L <32 data bits> <3 bit addr> + 0 10 0 00000000000000000000000000000000 001 + Protected Write: 0 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 0 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 0 10 00 <32 pwd bits> + Protected Read 0 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 0 1p 0 <3 bit addr> + Page 0/1 read 0 1p + Reset 0 00 + + */ + T55xxWriteBit_Leading0 (0); //T55xxWriteBit(0); + + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + T55xxWriteBit_Leading0 (testMode ? 0 : 1); + T55xxWriteBit_Leading0 (testMode ? 1 : Page); //Page 0 + + + if (PwdMode) { + // Leading zero - insert two fixed 00 between opcode and password + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + + // Send Lock bit + T55xxWriteBit_Leading0 (0); + + // Send Data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Data & i); + + // Send Block number + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Block & i); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} +void T55xxWriteBlockExt_1of4 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + int bitpos; + uint8_t bits; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + + WaitUS(START_GAP1of4); + + + /* + 00 : 1 if 4 + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 00 1p L <32 data bits> <3 bit addr> + 00 10 0 00000000000000000000000000000000 001 + Protected Write: 00 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 00 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 00 10 00 <32 pwd bits> + Protected Read 00 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 00 1p 0 <3 bit addr> + Page 0/1 read 00 1p + Reset 00 00 + + */ + T55xxWriteBit_1of4 (0); //Send Reference 00 + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + if (testMode) bits = 0; else bits = 2; // 0x or 1x + if (testMode) bits |= 1; else bits += (Page); // x0 or x1 + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Data - offset by 1 bit due to lock bit + // 2 bits at a time - Initilised with lock bit above + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { + bits |= ((Data >> bitpos) & 1); // Add Low bit + T55xxWriteBit_1of4 (bits); + bits = ((Data >> (bitpos-1)) & 1) << 1; // Set next high bit + } + + // Send Block number + bits |= ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3);// 1) & 2) + (Block & 1); + T55xxWriteBit_1of4 (bits); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} + // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); @@ -1324,12 +1585,34 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - T55xxWriteBlockExt(Data, Block, Pwd, arg); +// arg 8 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 Test Mode +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg >> 3) & 0x03; + + switch (downlink_mode) + { + case 0 : T55xxWriteBlockExt (Data, Block, Pwd, arg); break; + case 1 : T55xxWrite_LLR (); + T55xxWriteBlockExt (Data, Block, Pwd, arg); + break; + case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; + case 3 : T55xxWriteBlockExt_1of4 (Data, Block, Pwd, arg); break; + + default: + T55xxWriteBlockExt (Data, Block, Pwd, arg); + } + cmd_send(CMD_ACK,0,0,0,0,0); } // Read one card block in page [page] -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { +void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { LED_A_ON(); bool PwdMode = arg0 & 0x1; uint8_t Page = (arg0 & 0x2) >> 1; @@ -1379,10 +1662,163 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); +// cmd_send(CMD_ACK,0,0,0,0,0); LED_A_OFF(); } +void T55xxReadBlockExt_Leading0 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAPlz); + + T55xxWriteBit_Leading0 (0); + + // Opcode 1[page] + T55xxWriteBit_Leading0 (1); + T55xxWriteBit_Leading0 (Page); //Page 0 + + if (PwdMode){ + // Send Pwd + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + // Send a zero bit separation + T55xxWriteBit_Leading0(0); + + // Send Block number (if direct access mode) + if (!RegReadMode) + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Block & i); + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlockExt_1of4 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + //uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + uint8_t bits; + int bitpos; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAP1of4); + + T55xxWriteBit_1of4 (0); // 2 Bit 00 leading reference + + // Opcode 1[page] + bits = 2 + Page; + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Block number (if direct access mode) + if (!RegReadMode){ + // Send Block number + bits += ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3); // + (Block & 1); + T55xxWriteBit_1of4 (bits); + } + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { +// arg0 16 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg0 >> 3) & 0x03; + + // downlink mode id set to match the 2 bit as per Tech Sheet + switch (downlink_mode) + { + case 0 : T55xxReadBlockExt (arg0, Block, Pwd); break; + case 1 : T55xxWrite_LLR (); + T55xxReadBlockExt (arg0, Block, Pwd); + break; + case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; + case 3 : T55xxReadBlockExt_1of4 (arg0, Block, Pwd); break; + default: + T55xxReadBlockExt (arg0, Block, Pwd) ; + } + +// T55xxReadBlockExt (arg0, Block, Pwd) ; + cmd_send(CMD_ACK,0,0,0,0,0); +} + void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); uint32_t i = 0; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index b286c392..25df4c76 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,6 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -86,6 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -132,6 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -182,6 +188,24 @@ int usage_t55xx_bruteforce(){ PrintAndLog(""); return 0; } +int usage_t55xx_bruteforce_downlink(){ + PrintAndLog("This command uses A) bruteforce to scan a number range"); + PrintAndLog(" B) a dictionary attack"); + PrintAndLog("Usage: lf t55xx bruteforce [i <*.dic>]"); + PrintAndLog(" password must be 4 bytes (8 hex symbols)"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(""); + PrintAndLog("Examples:"); + PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(""); + return 0; +} int usage_t55xx_wipe(){ PrintAndLog("Usage: lf t55xx wipe [h] [Q5]"); PrintAndLog("This commands wipes a tag, fills blocks 1-7 with zeros and a default configuration block"); @@ -311,12 +335,12 @@ int CmdT55xxSetConfig(const char *Cmd) { return printConfiguration ( config ); } -int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){ +int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ //Password mode if ( usepwd ) { // try reading the config block and verify that PWD bit is set before doing this! if ( !override ) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0; + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0; if ( !tryDetectModulation() ) { PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits."); return 0; @@ -330,7 +354,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 } } - if (!AquireData(page1, block, usepwd, password) ) return 0; + if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0; if (!DecodeT55xxBlock()) return 0; char blk[10]={0}; @@ -342,6 +366,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 int CmdT55xxReadBlock(const char *Cmd) { uint8_t block = REGULAR_READ_MODE_BLOCK; uint32_t password = 0; //default to blank Block 7 + uint8_t downlink_mode = 0; + bool usepwd = false; bool override = false; bool page1 = false; @@ -372,6 +398,12 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -386,7 +418,7 @@ int CmdT55xxReadBlock(const char *Cmd) { } printT5xxHeader(page1); - return T55xxReadBlock(block, page1, usepwd, override, password); + return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode); } bool DecodeT55xxBlock(){ @@ -465,6 +497,7 @@ int CmdT55xxDetect(const char *Cmd){ bool usepwd = false; uint32_t password = 0; uint8_t cmdp = 0; + uint8_t downlink_mode = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { @@ -482,6 +515,12 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -491,13 +530,24 @@ int CmdT55xxDetect(const char *Cmd){ if (errors) return usage_t55xx_detect(); if ( !useGB) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) ) + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) ) return 0; } if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); - + else { + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + // default: + + // No default action + } + } return 1; } @@ -898,6 +948,8 @@ int CmdT55xxWriteBlock(const char *Cmd) { uint8_t block = 0xFF; //default to invalid block uint32_t data = 0; //default to blank Block uint32_t password = 0; //default to blank Block 7 + uint32_t downlink_mode = 0; + bool usepwd = false; bool page1 = false; bool gotdata = false; @@ -935,6 +987,12 @@ int CmdT55xxWriteBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -952,17 +1010,19 @@ int CmdT55xxWriteBlock(const char *Cmd) { UsbCommand resp; c.d.asBytes[0] = (page1) ? 0x2 : 0; c.d.asBytes[0] |= (testMode) ? 0x4 : 0; - + c.d.asBytes[0] |= (downlink_mode << 3); + char pwdStr[16] = {0}; snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); PrintAndLog("Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); - + //Password mode if (usepwd) { c.arg[2] = password; c.d.asBytes[0] |= 0x1; } + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ @@ -980,7 +1040,7 @@ int CmdT55xxReadTrace(const char *Cmd) { return usage_t55xx_trace(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) ) return 0; if ( config.Q5 ) { @@ -1144,7 +1204,7 @@ int CmdT55xxInfo(const char *Cmd){ return usage_t55xx_info(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) ) return 1; if (!DecodeT55xxBlock()) return 1; @@ -1212,20 +1272,21 @@ int CmdT55xxDump(const char *Cmd){ printT5xxHeader(0); for ( uint8_t i = 0; i <8; ++i) - T55xxReadBlock(i, 0, usepwd, override, password); + T55xxReadBlock(i, 0, usepwd, override, password,0); printT5xxHeader(1); for ( uint8_t i = 0; i<4; i++) - T55xxReadBlock(i, 1, usepwd, override, password); + T55xxReadBlock(i, 1, usepwd, override, password,0); return 1; } -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){ +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){ // arg0 bitmodes: // bit0 = pwdmode // bit1 = page to read from uint8_t arg0 = (page<<1) | pwdmode; + arg0 |= (downlink_mode << 3); UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}}; clearCommandBuffer(); @@ -1397,6 +1458,7 @@ int CmdT55xxBruteForce(const char *Cmd) { char buf[9]; char filename[FILE_PATH_SIZE]={0}; int keycnt = 0; + uint8_t downlink_mode = 0; int ch; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; @@ -1480,7 +1542,7 @@ int CmdT55xxBruteForce(const char *Cmd) { PrintAndLog("Testing %08X", testpwd); - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1525,7 +1587,7 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1547,6 +1609,239 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } +int CmdT55xxBruteForce_downlink(const char *Cmd) { + + // load a default pwd file. + char buf[9]; + char filename[FILE_PATH_SIZE]={0}; + int keycnt = 0; + uint8_t downlink_mode = 0; + int ch; + uint8_t stKeyBlock = 20; + uint8_t *keyBlock = NULL, *p = NULL; + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + bool found = false; + uint8_t cmdp = 0; + int cmd_offset = 0; + int errors = 0; + int len; + bool use_file = false; + bool use_range = false; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + + keyBlock = calloc(stKeyBlock, 6); + if (keyBlock == NULL) return 1; + + PrintAndLog("New Downlink Supprt"); + + while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_t55xx_bruteforce_downlink(); + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + cmd_offset += 4; + PrintAndLog ("DL Mode : %d",downlink_mode); + break; + case 'i': + case 'I': + if (use_range) { + PrintAndLog ("use Range or File"); + return 0; + } + use_file = true; + len = strlen(Cmd+2); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd+cmd_offset+2, len); + cmdp += 2; + // PrintAndLog (" File : [%s]",filename); + break; + case 'r': + case 'R': + if (use_file) { + PrintAndLog ("use Range or File"); + return 0; + } + use_range = true; // = param_get32ex(Cmd, cmdp+1, 0, 16); + start_password = param_get32ex(Cmd, cmdp+1, 0, 16); + end_password = param_get32ex(Cmd, cmdp+2, 0, 16); + cmdp += 3; + cmd_offset += 20; // 8 + 8 + 1 + 1 + 1 + // PrintAndLog (" Range : [%0X] - [%0X]",start_password,end_password); + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + +// if (cmdp == 'i' || cmdp == 'I') { + + if (use_file) + { + FILE * f = fopen( filename , "r"); + + if ( !f ) { + PrintAndLog("File: %s: not found or locked.", filename); + free(keyBlock); + return 1; + } + + while( fgets(buf, sizeof(buf), f) ) { + if (strlen(buf) < 8 || buf[7] == '\n') continue; + + while (fgetc(f) != '\n' && !feof(f)) ; //goto next line + + //The line start with # is comment, skip + if( buf[0]=='#' ) continue; + + if (!isxdigit((unsigned char)buf[0])) { + PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); + continue; + } + + buf[8] = 0; + + if ( stKeyBlock - keycnt < 2) { + p = realloc(keyBlock, 6*(stKeyBlock+=10)); + if (!p) { + PrintAndLog("Cannot allocate memory for defaultKeys"); + free(keyBlock); + fclose(f); + return 2; + } + keyBlock = p; + } + memset(keyBlock + 4 * keycnt, 0, 4); + num_to_bytes(strtoll(buf, NULL, 16), 4, keyBlock + 4*keycnt); + PrintAndLog("chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4*keycnt, 4)); + keycnt++; + memset(buf, 0, sizeof(buf)); + } + fclose(f); + + if (keycnt == 0) { + PrintAndLog("No keys found in file"); + free(keyBlock); + return 1; + } + PrintAndLog("Loaded %d keys", keycnt); + + // loop + uint64_t testpwd = 0x00; + for (uint16_t c = 0; c < keycnt; ++c ) { + + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + testpwd = bytes_to_num(keyBlock + 4*c, 4); + + PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode of asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) + { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,dl_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + + found = tryDetectModulation(); + + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + // Add downlink mode to reference. + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + return 0; + } + if (!try_all_dl_modes) // Exit loop + dl_mode = 4; + } + } + PrintAndLog("Password NOT found."); + free(keyBlock); + return 0; + } + + if (use_range) + { + // incremental pwd range search + // start_password = param_get32ex(Cmd, 0, 0, 16); + // end_password = param_get32ex(Cmd, 1, 0, 16); + + if ( start_password >= end_password ) { + free(keyBlock); + return usage_t55xx_bruteforce_downlink(); + } + PrintAndLog("Search password range [%08X -> %08X]", start_password, end_password); + + uint32_t i = start_password; + + while ((!found) && (i <= end_password)) { + + printf("."); + fflush(stdout); + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + found = tryDetectModulation(); + + if (found) break; + i++; + } + + PrintAndLog(""); + + if (found) { + PrintAndLog("Found valid password: [%08x]", i); + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + } + else + PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + + free(keyBlock); + } + return 0; +} + // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1558,7 +1853,7 @@ bool tryDetectP1(bool getData) { bool st = true; if ( getData ) { - if ( !AquireData(T55x7_PAGE1, 1, false, 0) ) + if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) ) return false; } @@ -1687,7 +1982,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ if (errors) return usage_t55xx_detectP1(); if ( !useGB ) { - if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) ) + if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) ) return false; } bool success = tryDetectP1(false); @@ -1697,7 +1992,8 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforcedl",CmdT55xxBruteForce_downlink,0, "r [i <*.dic>] [e ] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 2ae3e69b..1ba4dca4 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -74,6 +74,7 @@ void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); +extern int CmdT55xxBruteForce_downlink(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxWriteBlock(const char *Cmd); @@ -98,7 +99,7 @@ bool tryDetectModulation(void); extern bool tryDetectP1(bool getData); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5); int special(const char *Cmd); -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ); +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode ); void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ); void printT5555Trace( t5555_tracedata_t data, uint8_t repeat ); From 6dd0ff3035ed40ab47f22d76dbc22942a492dca3 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 17 Jun 2019 21:37:50 +1000 Subject: [PATCH 10/29] Update cmdlft55xx.c Minor Cleanup --- client/cmdlft55xx.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 25df4c76..a05838b4 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,8 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -88,8 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -136,8 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -196,9 +196,10 @@ int usage_t55xx_bruteforce_downlink(){ PrintAndLog("Options:"); PrintAndLog(" h - this help"); PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); - PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); From be1b97d81fe44d9227a5c581fd279fed062a18cd Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 17 Jun 2019 22:01:25 +1000 Subject: [PATCH 11/29] Update cmdlft55xx.c Fixed bruteforce filename --- client/cmdlft55xx.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index a05838b4..da8fc703 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -1635,8 +1635,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; - PrintAndLog("New Downlink Supprt"); - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { case 'h': @@ -1649,7 +1647,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; cmd_offset += 4; - PrintAndLog ("DL Mode : %d",downlink_mode); break; case 'i': case 'I': @@ -1661,8 +1658,11 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { len = strlen(Cmd+2); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd+cmd_offset+2, len); + // Drop any characters after space + char *p = strstr(filename," "); + if (p) *p = 0; cmdp += 2; - // PrintAndLog (" File : [%s]",filename); + // PrintAndLog (" File : [%s]",filename); break; case 'r': case 'R': @@ -1670,12 +1670,11 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { PrintAndLog ("use Range or File"); return 0; } - use_range = true; // = param_get32ex(Cmd, cmdp+1, 0, 16); + use_range = true; start_password = param_get32ex(Cmd, cmdp+1, 0, 16); end_password = param_get32ex(Cmd, cmdp+2, 0, 16); cmdp += 3; - cmd_offset += 20; // 8 + 8 + 1 + 1 + 1 - // PrintAndLog (" Range : [%0X] - [%0X]",start_password,end_password); + cmd_offset += 20; break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); @@ -1684,9 +1683,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { } } - -// if (cmdp == 'i' || cmdp == 'I') { - if (use_file) { FILE * f = fopen( filename , "r"); @@ -1753,7 +1749,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { PrintAndLog("Testing %08X", testpwd); - // Try each downlink_mode of asked to + // Try each downlink_mode if asked to // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) { @@ -1768,7 +1764,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if ( found ) { PrintAndLog("Found valid password: [%08X]", testpwd); free(keyBlock); - // Add downlink mode to reference. + // Add downlink mode for reference. switch (dl_mode) { case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; @@ -1788,9 +1784,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (use_range) { - // incremental pwd range search - // start_password = param_get32ex(Cmd, 0, 0, 16); - // end_password = param_get32ex(Cmd, 1, 0, 16); if ( start_password >= end_password ) { free(keyBlock); @@ -1827,7 +1820,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (found) { PrintAndLog("Found valid password: [%08x]", i); - // Add downlink mode to reference. + // Add downlink mode for reference. switch (downlink_mode) { case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; From 6763dc17a3f76370c766bfdb39179bde3ff7619f Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 18 Jun 2019 21:17:12 +1000 Subject: [PATCH 12/29] Cleanup Code Update downlink option from e to r fixed long leading reference added downling option to original bruteforce --- armsrc/lfops.c | 23 ++- client/cmdlft55xx.c | 379 ++++++++++---------------------------------- client/cmdlft55xx.h | 1 - 3 files changed, 103 insertions(+), 300 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 36efe729..112a1173 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1519,6 +1519,10 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg uint8_t Page = (arg & 0x2)>>1; bool testMode = arg & 0x4; uint32_t i = 0; + uint8_t downlink_mode; + + downlink_mode = (arg >> 3) & 0x03; + // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1529,6 +1533,9 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(START_GAP); + // Long Leading Reference, same as fixed/default just with leading reference + if (downlink_mode == 1) T55xxWrite_LLR (); + if (testMode) Dbprintf("TestMODE"); // Std Opcode 10 T55xxWriteBit(testMode ? 0 : 1); @@ -1597,8 +1604,8 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { switch (downlink_mode) { - case 0 : T55xxWriteBlockExt (Data, Block, Pwd, arg); break; - case 1 : T55xxWrite_LLR (); + case 0 :// T55xxWriteBlockExt (Data, Block, Pwd, arg); break; + case 1 : // T55xxWrite_LLR (); T55xxWriteBlockExt (Data, Block, Pwd, arg); break; case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; @@ -1618,7 +1625,10 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { uint8_t Page = (arg0 & 0x2) >> 1; uint32_t i = 0; bool RegReadMode = (Block == 0xFF);//regular read mode - + uint8_t downlink_mode; + + downlink_mode = (arg0 >> 3) & 0x03; + //clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); @@ -1634,6 +1644,9 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(START_GAP); + // Long Leading Reference, same as fixed/default just with leading reference + if (downlink_mode == 1) T55xxWrite_LLR (); + // Opcode 1[page] T55xxWriteBit(1); T55xxWriteBit(Page); //Page 0 @@ -1805,8 +1818,8 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { // downlink mode id set to match the 2 bit as per Tech Sheet switch (downlink_mode) { - case 0 : T55xxReadBlockExt (arg0, Block, Pwd); break; - case 1 : T55xxWrite_LLR (); + case 0 :// T55xxReadBlockExt (arg0, Block, Pwd); break; + case 1 : // T55xxWrite_LLR (); T55xxReadBlockExt (arg0, Block, Pwd); break; case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index da8fc703..ed980f9b 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,7 +67,7 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); @@ -88,7 +88,7 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); @@ -136,7 +136,7 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); @@ -168,7 +168,7 @@ int usage_t55xx_wakup(){ PrintAndLog(" - [required] password 4bytes (8 hex symbols)"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); + PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); return 0; } int usage_t55xx_bruteforce(){ @@ -178,32 +178,16 @@ int usage_t55xx_bruteforce(){ PrintAndLog(" password must be 4 bytes (8 hex symbols)"); PrintAndLog("Options:"); PrintAndLog(" h - this help"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(" - 4 byte hex value to start pwd search at"); PrintAndLog(" - 4 byte hex value to end pwd search at"); PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); - PrintAndLog(""); - return 0; -} -int usage_t55xx_bruteforce_downlink(){ - PrintAndLog("This command uses A) bruteforce to scan a number range"); - PrintAndLog(" B) a dictionary attack"); - PrintAndLog("Usage: lf t55xx bruteforce [i <*.dic>]"); - PrintAndLog(" password must be 4 bytes (8 hex symbols)"); - PrintAndLog("Options:"); - PrintAndLog(" h - this help"); - PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); - PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default)"); - PrintAndLog(" '1' long leading reference, '2' leading zero "); - PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(" lf t55xx bruteforce [r 2] aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce [r 2] i default_pwd.dic"); PrintAndLog(""); return 0; } @@ -399,8 +383,8 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -516,8 +500,8 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -540,13 +524,10 @@ int CmdT55xxDetect(const char *Cmd){ else { // Add downlink mode to reference. switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - // default: - - // No default action + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; } } return 1; @@ -988,8 +969,8 @@ int CmdT55xxWriteBlock(const char *Cmd) { page1 = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -1459,16 +1440,29 @@ int CmdT55xxBruteForce(const char *Cmd) { char buf[9]; char filename[FILE_PATH_SIZE]={0}; int keycnt = 0; - uint8_t downlink_mode = 0; int ch; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; uint32_t start_password = 0x00000000; //start password uint32_t end_password = 0xFFFFFFFF; //end password bool found = false; - + uint8_t downlink_mode = 0; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + uint8_t cmd_offset = 0; + int cmd_opt = 0; + char cmdp = param_getchar(Cmd, 0); + if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce(); + if (cmdp == 'r' || cmdp == 'R') { + downlink_mode = param_getchar(Cmd, 1) - '0'; // get 2nd option, as this is fixed order. + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmd_opt += 2; // To help start/end passwords for range to be found + cmd_offset += 4; // r x To help the string offset for filename start position in cmd + cmdp = param_getchar(Cmd, 2); // get 3rd option, as this is fixed order. + } keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; @@ -1477,7 +1471,7 @@ int CmdT55xxBruteForce(const char *Cmd) { int len = strlen(Cmd+2); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd+2, len); + memcpy(filename, Cmd+2+cmd_offset, len); FILE * f = fopen( filename , "r"); @@ -1542,20 +1536,32 @@ int CmdT55xxBruteForce(const char *Cmd) { testpwd = bytes_to_num(keyBlock + 4*c, 4); PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,downlink_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } + found = tryDetectModulation(); - found = tryDetectModulation(); - - if ( found ) { - PrintAndLog("Found valid password: [%08X]", testpwd); - free(keyBlock); - return 0; - } + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; + } + return 0; + } + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; + } } PrintAndLog("Password NOT found."); free(keyBlock); @@ -1565,8 +1571,8 @@ int CmdT55xxBruteForce(const char *Cmd) { // Try to read Block 7, first :) // incremental pwd range search - start_password = param_get32ex(Cmd, 0, 0, 16); - end_password = param_get32ex(Cmd, 1, 0, 16); + start_password = param_get32ex(Cmd, cmd_opt , 0, 16); + end_password = param_get32ex(Cmd, cmd_opt+1 , 0, 16); if ( start_password >= end_password ) { free(keyBlock); @@ -1587,225 +1593,10 @@ int CmdT55xxBruteForce(const char *Cmd) { free(keyBlock); return 0; } - - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } - found = tryDetectModulation(); - - if (found) break; - i++; - } - - PrintAndLog(""); - - if (found) - PrintAndLog("Found valid password: [%08x]", i); - else - PrintAndLog("Password NOT found. Last tried: [%08x]", --i); - - free(keyBlock); - return 0; -} - -int CmdT55xxBruteForce_downlink(const char *Cmd) { - - // load a default pwd file. - char buf[9]; - char filename[FILE_PATH_SIZE]={0}; - int keycnt = 0; - uint8_t downlink_mode = 0; - int ch; - uint8_t stKeyBlock = 20; - uint8_t *keyBlock = NULL, *p = NULL; - uint32_t start_password = 0x00000000; //start password - uint32_t end_password = 0xFFFFFFFF; //end password - bool found = false; - uint8_t cmdp = 0; - int cmd_offset = 0; - int errors = 0; - int len; - bool use_file = false; - bool use_range = false; - bool try_all_dl_modes = false; - uint8_t dl_mode = 0; - - keyBlock = calloc(stKeyBlock, 6); - if (keyBlock == NULL) return 1; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_t55xx_bruteforce_downlink(); - case 'e': - case 'E': - downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; - if (downlink_mode == 4) try_all_dl_modes = true; - if (downlink_mode > 3) downlink_mode = 0; - cmdp +=2; - cmd_offset += 4; - break; - case 'i': - case 'I': - if (use_range) { - PrintAndLog ("use Range or File"); - return 0; - } - use_file = true; - len = strlen(Cmd+2); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd+cmd_offset+2, len); - // Drop any characters after space - char *p = strstr(filename," "); - if (p) *p = 0; - cmdp += 2; - // PrintAndLog (" File : [%s]",filename); - break; - case 'r': - case 'R': - if (use_file) { - PrintAndLog ("use Range or File"); - return 0; - } - use_range = true; - start_password = param_get32ex(Cmd, cmdp+1, 0, 16); - end_password = param_get32ex(Cmd, cmdp+2, 0, 16); - cmdp += 3; - cmd_offset += 20; - break; - default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - if (use_file) - { - FILE * f = fopen( filename , "r"); - - if ( !f ) { - PrintAndLog("File: %s: not found or locked.", filename); - free(keyBlock); - return 1; - } - - while( fgets(buf, sizeof(buf), f) ) { - if (strlen(buf) < 8 || buf[7] == '\n') continue; - - while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - - //The line start with # is comment, skip - if( buf[0]=='#' ) continue; - - if (!isxdigit((unsigned char)buf[0])) { - PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); - continue; - } - - buf[8] = 0; - - if ( stKeyBlock - keycnt < 2) { - p = realloc(keyBlock, 6*(stKeyBlock+=10)); - if (!p) { - PrintAndLog("Cannot allocate memory for defaultKeys"); - free(keyBlock); - fclose(f); - return 2; - } - keyBlock = p; - } - memset(keyBlock + 4 * keycnt, 0, 4); - num_to_bytes(strtoll(buf, NULL, 16), 4, keyBlock + 4*keycnt); - PrintAndLog("chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4*keycnt, 4)); - keycnt++; - memset(buf, 0, sizeof(buf)); - } - fclose(f); - - if (keycnt == 0) { - PrintAndLog("No keys found in file"); - free(keyBlock); - return 1; - } - PrintAndLog("Loaded %d keys", keycnt); - - // loop - uint64_t testpwd = 0x00; - for (uint16_t c = 0; c < keycnt; ++c ) { - - if (ukbhit()) { - ch = getchar(); - (void)ch; - printf("\naborted via keyboard!\n"); - free(keyBlock); - return 0; - } - - testpwd = bytes_to_num(keyBlock + 4*c, 4); - - PrintAndLog("Testing %08X", testpwd); - - // Try each downlink_mode if asked to - // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 - for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) - { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } - - found = tryDetectModulation(); - - if ( found ) { - PrintAndLog("Found valid password: [%08X]", testpwd); - free(keyBlock); - // Add downlink mode for reference. - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - } - return 0; - } - if (!try_all_dl_modes) // Exit loop - dl_mode = 4; - } - } - PrintAndLog("Password NOT found."); - free(keyBlock); - return 0; - } - - if (use_range) - { - - if ( start_password >= end_password ) { - free(keyBlock); - return usage_t55xx_bruteforce_downlink(); - } - PrintAndLog("Search password range [%08X -> %08X]", start_password, end_password); - - uint32_t i = start_password; - - while ((!found) && (i <= end_password)) { - - printf("."); - fflush(stdout); - if (ukbhit()) { - ch = getchar(); - (void)ch; - printf("\naborted via keyboard!\n"); - free(keyBlock); - return 0; - } - - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1813,29 +1604,30 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { found = tryDetectModulation(); if (found) break; - i++; + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; } - - PrintAndLog(""); - - if (found) { - PrintAndLog("Found valid password: [%08x]", i); - // Add downlink mode for reference. - switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - } - } - else - PrintAndLog("Password NOT found. Last tried: [%08x]", --i); - - free(keyBlock); + if (found) break; + i++; } + + if (found){ + PrintAndLog("Found valid password: [%08x]", i); + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading Zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; + } + } + else{ + PrintAndLog(""); + PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + } + + free(keyBlock); return 0; } - // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1987,7 +1779,6 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, - {"bruteforcedl",CmdT55xxBruteForce_downlink,0, "r [i <*.dic>] [e ] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 1ba4dca4..4541bd3a 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -74,7 +74,6 @@ void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); -extern int CmdT55xxBruteForce_downlink(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxWriteBlock(const char *Cmd); From 4be71814b4a7f5647a01d55882664c5889f4e605 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sat, 22 Jun 2019 15:26:56 +1000 Subject: [PATCH 13/29] T55xx Downlink - Updates Improved code. --- CHANGELOG.md | 28 ++ armsrc/lfops.c | 799 ++++++++++++++++---------------------------- client/cmdlft55xx.c | 57 ++-- 3 files changed, 341 insertions(+), 543 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 399f87f9..55f1d1f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,34 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] +## T55xx Downlink Protocol - 22 Jun 2019 + +# armsrc/lfops + +### Added +- Added typedef T55xx_Timing to hold downlink timings. +- Added Timing Records for long leading reference (llr), Leading 0 and 1 of 4 +- Added some constant defines for code readability +- Added function T55xx_SetBits to build a bit stream for writing to T55xx +- Added function T55xx_SendCMD to build the bit stream and send to T55xx + +### Changed +- Converted Timing for default/fixed bit to T55xx_Timing +- Updated T55xxWriteBit (and calls) to support all downlink protocols +- Updated T55xxWriteBlock to call T55xx_SendCMD (removed local bit writes) +- Updated T55xxReadBlock to call T55xx_SendCMD (removed local bit writes) + +# client/cmdlft55xx + +### Added +- Added function T55xx_Print_DownlinkMode to print downlink mode information when uesd + +### Changes +- Added downlink mode options r [ 0 (or missing) default/fixed bit, 1 long leading, leading 0 and 1 of 4 ] +- Added r 4 option to bruteforce to try all downlink modes (0,1,2 and 3) +- Updated help messages for each support functions t55xx_read, t55xx_write, t55_detect, t55xx_bruteforce + + ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 112a1173..c1f32f87 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1198,13 +1198,90 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * and enlarge the gap ones. * Q5 tags seems to have issues when these values changes. */ + /* + // Original Timings for reference + #define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 -// Long Leading Reference -#define Reference_llr (136+18)*8 // Needs to be WRITR_0 + 136 clocks. +*/ + +// Structure to hold Timing values. In future will be simplier to add user changable timings. +typedef struct { + uint16_t START_GAP; + uint16_t WRITE_GAP; + uint16_t WRITE_0; + uint16_t WRITE_1; + uint16_t WRITE_2; + uint16_t WRITE_3; + uint16_t READ_GAP; +} T55xx_Timing; + +/* + T5577 Timeing from datasheet for reference + + Fixed bit length + ---------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 15 50 8 15 50 + Write gap 8 10 20 8 10 20 + 0 data 16 24 32 8 12 16 + 1 data 48 56 64 24 28 32 + + + Long Leading Reference + ---------------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 152 160 168 140 144 148 + 136 + 0 data 132 + 0 data + 0 data r - 143 r - 136 r - 128 r - 135 r - 132 r - 124 + 1 data r - 111 r - 104 r - 96 r - 119 r - 116 r - 112 + + + Leading Zero Reference + ---------------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 12 - 72 8 - 68 + 0 data r - 7 r r + 8 r - 3 r r + 4 + 1 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 + + + 1 of 4 Coding + ------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 8 - 68 12 - 72 + 00 data r - 7 r r + 8 r - 3 r r + 4 + 01 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 + 10 data r + 25 r + 32 r + 40 r + 13 r + 16 r + 20 + 11 data r + 41 r + 48 r + 56 r + 21 r + 24 r + 28 + +*/ + +// Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. +T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 }; + + +// Some defines for readability +#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference +#define T55xx_DLMode_Fixed 0 // Default Mode +#define T55xx_DLMode_LLR 1 // Long Leading Reference +#define T55xx_DLMode_Leading0 2 // Leading Zero +#define T55xx_DLMode_1of4 3 // 1 of 4 void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1213,272 +1290,59 @@ void TurnReadLFOn(int delay) { } // Write one bit to card -void T55xxWriteBit(int bit) { - if (!bit) - TurnReadLFOn(WRITE_0); - else - TurnReadLFOn(WRITE_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP); -} +void T55xxWriteBit(int bit, T55xx_Timing *Timings) { -void T55xxWrite_LLR (void) -{ - TurnReadLFOn (Reference_llr); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP); -} + // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 -#define START_GAPlz 31*8 -#define WRITE_GAPlz 20*8 -#define WRITElz_0 18*8 -#define WRITElz_1 40*8 -#define READ_GAP 15*8 - -void T55xxWriteBit_Leading0(int bit) { - if (!bit) - TurnReadLFOn(WRITElz_0); - else - TurnReadLFOn(WRITElz_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAPlz); -// WaitUS(160); -} - -#define START_GAP1of4 31*8 // SPEC: 1*8 to 50*8 - typ 10*8 (or 15fc) -#define WRITE_GAP1of4 20*8 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) -// 00 = reference // 8 * 8 - - 68 * 8 -#define WRITE1of4_00 18*8 // SPEC: 8*8 to 68*8 - typ 24*8 (or 24fc) -#define WRITE1of4_01 34*8 // SPEC: dref+9 - dref+16 - dref+24 -#define WRITE1of4_10 50*8 // SPEC: dref+25 - dref+32 - dref+40 -#define WRITE1of4_11 66*8 // SPEC: dref+41 - dref+48 - dref+56 -#define READ1of4_GAP 15*8 - -void T55xxWriteBit_1of4(int bits) { - - switch (bits) - { - case 0 : TurnReadLFOn(WRITE1of4_00); break; - case 1 : TurnReadLFOn(WRITE1of4_01); break; - case 2 : TurnReadLFOn(WRITE1of4_10); break; - case 3 : TurnReadLFOn(WRITE1of4_11); break; - default: - TurnReadLFOn(WRITE1of4_00); + switch (bit){ + case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 + case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 + case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 + case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 + case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP1of4); -// WaitUS(160); + WaitUS(Timings->WRITE_GAP); } -void T55xxWriteBlockExt_Leading0 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - uint32_t i = 0; - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +// Function to abstract an Arbitrary length byte array to store bit pattern. +// bit_array - Array to hold data/bit pattern +// start_offset - bit location to start storing new bits. +// data - upto 32 bits of data to store +// num_bits - how many bits (low x bits of data) Max 32 bits at a time +// max_len - how many bytes can the bit_array hold (ensure no buffer overflow) +// returns "Next" bit offset / bits stored (for next store) +int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +{ + int bit,byte_idx, bit_idx; + int offset; + int NextOffset = start_offset; - WaitUS(START_GAPlz); - - - /* - 0 : Leading Zero - 11 : Opcode - 00 : Fixed 00 if protected write (i.e. have password) - <32 bit Password> - 0 : Lock Bit - <32 bit data> - <3 bit addr> + // Check if data will fit. + if ((start_offset + num_bits) <= (max_len*8)) { + + // Loop through the data and store + for (offset = (num_bits-1); offset >= 0; offset--) { + + bit = (data >> offset) & 1; // Get data bit value (0/1) + byte_idx = (NextOffset / 8); // Get Array Byte Index to Store + bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr - Standard Write : 0 1p L <32 data bits> <3 bit addr> - 0 10 0 00000000000000000000000000000000 001 - Protected Write: 0 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> - 0 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 - Wake Up 0 10 00 <32 pwd bits> - Protected Read 0 1p 00 <32 pwd bits> 0 <3 bit addr> - Standard Read 0 1p 0 <3 bit addr> - Page 0/1 read 0 1p - Reset 0 00 - - */ - T55xxWriteBit_Leading0 (0); //T55xxWriteBit(0); - - - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - T55xxWriteBit_Leading0 (testMode ? 0 : 1); - T55xxWriteBit_Leading0 (testMode ? 1 : Page); //Page 0 - - - if (PwdMode) { - // Leading zero - insert two fixed 00 between opcode and password - T55xxWriteBit_Leading0 (0); - T55xxWriteBit_Leading0 (0); - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Pwd & i); - } - - // Send Lock bit - T55xxWriteBit_Leading0 (0); + // If set (1) we OR, if clear (0) we AND with inverse + // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); + if (bit == 1) + bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 + + else + bit_array[byte_idx] &= (0xff ^ (1 << bit_idx)); // Set the bit to 0 (clr) - // Send Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0(Data & i); - - // Send Block number - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Block & i); - - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - // "there is a clock delay before programming" - // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 - // so we should wait 1 clock + 5.6ms then read response? - // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... - if (testMode) { - //TESTMODE TIMING TESTS: - // <566us does nothing - // 566-568 switches between wiping to 0s and doing nothing - // 5184 wipes and allows 1 block to be programmed. - // indefinite power on wipes and then programs all blocks with bitshifted data sent. - TurnReadLFOn(5184); - - } else { - TurnReadLFOn(20 * 1000); - //could attempt to do a read to confirm write took - // as the tag should repeat back the new block - // until it is reset, but to confirm it we would - // need to know the current block 0 config mode for - // modulation clock an other details to demod the response... - // response should be (for t55x7) a 0 bit then (ST if on) - // block data written in on repeat until reset. - - //DoPartialAcquisition(20, true, 12000); - } - - // turn field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - -} -void T55xxWriteBlockExt_1of4 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - int bitpos; - uint8_t bits; - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - - WaitUS(START_GAP1of4); - - - /* - 00 : 1 if 4 - 11 : Opcode - 00 : Fixed 00 if protected write (i.e. have password) - <32 bit Password> - 0 : Lock Bit - <32 bit data> - <3 bit addr> - - Standard Write : 00 1p L <32 data bits> <3 bit addr> - 00 10 0 00000000000000000000000000000000 001 - Protected Write: 00 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> - 00 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 - Wake Up 00 10 00 <32 pwd bits> - Protected Read 00 1p 00 <32 pwd bits> 0 <3 bit addr> - Standard Read 00 1p 0 <3 bit addr> - Page 0/1 read 00 1p - Reset 00 00 - - */ - T55xxWriteBit_1of4 (0); //Send Reference 00 - - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - if (testMode) bits = 0; else bits = 2; // 0x or 1x - if (testMode) bits |= 1; else bits += (Page); // x0 or x1 - T55xxWriteBit_1of4 (bits); - - if (PwdMode) { - // 1 of 4 00 - insert two fixed 00 between opcode and password - T55xxWriteBit_1of4 (0); // 00 - - // Send Pwd - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time - bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); - T55xxWriteBit_1of4 (bits); - } - } - - // Send Lock bit - bits = 0; // Add lock bit (Not Set) to the next 2 bits - - // Send Data - offset by 1 bit due to lock bit - // 2 bits at a time - Initilised with lock bit above - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { - bits |= ((Data >> bitpos) & 1); // Add Low bit - T55xxWriteBit_1of4 (bits); - bits = ((Data >> (bitpos-1)) & 1) << 1; // Set next high bit - } - - // Send Block number - bits |= ((Block >> 2) & 1); - T55xxWriteBit_1of4 (bits); - bits = (Block & 3);// 1) & 2) + (Block & 1); - T55xxWriteBit_1of4 (bits); - - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - // "there is a clock delay before programming" - // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 - // so we should wait 1 clock + 5.6ms then read response? - // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... - if (testMode) { - //TESTMODE TIMING TESTS: - // <566us does nothing - // 566-568 switches between wiping to 0s and doing nothing - // 5184 wipes and allows 1 block to be programmed. - // indefinite power on wipes and then programs all blocks with bitshifted data sent. - TurnReadLFOn(5184); - - } else { - TurnReadLFOn(20 * 1000); - //could attempt to do a read to confirm write took - // as the tag should repeat back the new block - // until it is reset, but to confirm it we would - // need to know the current block 0 config mode for - // modulation clock an other details to demod the response... - // response should be (for t55x7) a 0 bit then (ST if on) - // block data written in on repeat until reset. - - //DoPartialAcquisition(20, true, 12000); - } - - // turn field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - + NextOffset++; + } + } + else + Dbprintf ("Too Many Bits to fit into bit buffer"); + return NextOffset; } // Send T5577 reset command then read stream (see if we can identify the start of the stream) @@ -1495,13 +1359,13 @@ void T55xxResetRead(void) { // Trigger T55x7 in mode. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(T55xx_Timing_FixedBit.START_GAP); // reset tag - op code 00 - T55xxWriteBit(0); - T55xxWriteBit(0); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); - TurnReadLFOn(READ_GAP); + TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); @@ -1512,18 +1376,85 @@ void T55xxResetRead(void) { LED_A_OFF(); } -// Write one card block in page 0, no lock -void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - uint32_t i = 0; - uint8_t downlink_mode; +// Send one downlink command to the card +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { - downlink_mode = (arg >> 3) & 0x03; + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + + */ + bool PwdMode = ((arg & 0x01) == 0x01); + uint8_t Page = (arg & 0x02) >> 1; + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03;; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + + int i = 0; + uint8_t BitStream[10]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) + uint8_t BitStreamLen; + int byte_idx, bit_idx; + T55xx_Timing *Timing; + // Assigning Downlink Timeing for write + switch (downlink_mode) + { + case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; + case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; + default: + Timing = &T55xx_Timing_FixedBit; + } + + // Build Bit Stream to send. + memset (BitStream,0x00,sizeof(BitStream)); + + BitStreamLen = 0; + + // Add Leading 0 and 1 of 4 reference bit + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add extra reference 0 for 1 of 4 + if (downlink_mode == T55xx_DLMode_1of4) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Opcode + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + + if (PwdMode) { + + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + + } + // Add Lock bit + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + + + + // Send Bits to T55xx + // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); StartTicks(); @@ -1531,31 +1462,56 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg WaitMS(5); // Trigger T55x7 in mode. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(Timing->START_GAP); - // Long Leading Reference, same as fixed/default just with leading reference - if (downlink_mode == 1) T55xxWrite_LLR (); - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - T55xxWriteBit(testMode ? 0 : 1); - T55xxWriteBit(testMode ? 1 : Page); //Page 0 + // If long leading 0 send long reference pulse + if (downlink_mode == T55xx_DLMode_LLR) + T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (PwdMode) { - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + uint8_t SendBits; + + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for (i = 0; i < BitStreamLen; i+=2) { + byte_idx = i / 8; + bit_idx = i - (byte_idx * 8); + SendBits = ((BitStream[byte_idx] >> bit_idx) & 1) << 1; + + byte_idx = (i+1) / 8; + bit_idx = (i+1) - (byte_idx * 8); + SendBits += (BitStream[byte_idx] >> bit_idx) & 1; + + T55xxWriteBit (SendBits,Timing); + } } - // Send Lock bit - T55xxWriteBit(0); + else { + for (i = 0; i < BitStreamLen; i++) { + byte_idx = i / 8; + bit_idx = i - (byte_idx * 8); + SendBits = (BitStream[byte_idx] >> bit_idx) & 1; + T55xxWriteBit (SendBits,Timing); + } + } + +} - // Send Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Data & i); - - // Send Block number - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); +// Write one card block in page 0, no lock +void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + */ + + bool testMode = ((arg & 0x04) == 0x04); + arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 + + LED_A_ON (); + T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false); // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, // so wait a little more) @@ -1584,86 +1540,43 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg //DoPartialAcquisition(20, true, 12000); } - // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); -} - -// Write one card block in page 0, no lock -void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { -// arg 8 bit 00000000 -// 0000000x Password -// 000000x0 Page -// 00000x00 Test Mode -// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference -// 10 - Leading 0, 11 - 1 of 4 - uint8_t downlink_mode; - - downlink_mode = (arg >> 3) & 0x03; - - switch (downlink_mode) - { - case 0 :// T55xxWriteBlockExt (Data, Block, Pwd, arg); break; - case 1 : // T55xxWrite_LLR (); - T55xxWriteBlockExt (Data, Block, Pwd, arg); - break; - case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; - case 3 : T55xxWriteBlockExt_1of4 (Data, Block, Pwd, arg); break; - default: - T55xxWriteBlockExt (Data, Block, Pwd, arg); - } - cmd_send(CMD_ACK,0,0,0,0,0); + + LED_A_OFF (); } // Read one card block in page [page] -void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { + LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - uint8_t downlink_mode; - - downlink_mode = (arg0 >> 3) & 0x03; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + */ + + // Set Read Flag to ensure SendCMD does not add "data" to the packet + arg0 |= 0x40; + + + if (Block == 0xff) arg0 |= 0x20; + //make sure block is at max 7 Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Long Leading Reference, same as fixed/default just with leading reference - if (downlink_mode == 1) T55xxWrite_LLR (); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + T55xx_SendCMD (0, Block, Pwd, arg0); //, true); + - // Opcode 1[page] - T55xxWriteBit(1); - T55xxWriteBit(Page); //Page 0 - - if (PwdMode){ - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); - // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... // but we want to go past the start and let the repeating data settle in... @@ -1675,163 +1588,11 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); } -void T55xxReadBlockExt_Leading0 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { - LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - //make sure block is at max 7 - Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAPlz); - - T55xxWriteBit_Leading0 (0); - - // Opcode 1[page] - T55xxWriteBit_Leading0 (1); - T55xxWriteBit_Leading0 (Page); //Page 0 - - if (PwdMode){ - // Send Pwd - T55xxWriteBit_Leading0 (0); - T55xxWriteBit_Leading0 (0); - - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit_Leading0(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit_Leading0(Block & i); - - // Turn field on to read the response - // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); - - // Acquisition - // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); - - // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); -} - -void T55xxReadBlockExt_1of4 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { - LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - //uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - uint8_t bits; - int bitpos; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - //make sure block is at max 7 - Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP1of4); - - T55xxWriteBit_1of4 (0); // 2 Bit 00 leading reference - - // Opcode 1[page] - bits = 2 + Page; - T55xxWriteBit_1of4 (bits); - - if (PwdMode) { - // 1 of 4 00 - insert two fixed 00 between opcode and password - T55xxWriteBit_1of4 (0); // 00 - - // Send Pwd - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time - bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); - T55xxWriteBit_1of4 (bits); - } - } - - // Send Lock bit - bits = 0; // Add lock bit (Not Set) to the next 2 bits - - // Send Block number (if direct access mode) - if (!RegReadMode){ - // Send Block number - bits += ((Block >> 2) & 1); - T55xxWriteBit_1of4 (bits); - bits = (Block & 3); // + (Block & 1); - T55xxWriteBit_1of4 (bits); - } - - // Turn field on to read the response - // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); - - // Acquisition - // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); -} - -void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { -// arg0 16 bit 00000000 -// 0000000x Password -// 000000x0 Page -// 00000x00 -// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference -// 10 - Leading 0, 11 - 1 of 4 - uint8_t downlink_mode; - - downlink_mode = (arg0 >> 3) & 0x03; - - // downlink mode id set to match the 2 bit as per Tech Sheet - switch (downlink_mode) - { - case 0 :// T55xxReadBlockExt (arg0, Block, Pwd); break; - case 1 : // T55xxWrite_LLR (); - T55xxReadBlockExt (arg0, Block, Pwd); - break; - case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; - case 3 : T55xxReadBlockExt_1of4 (arg0, Block, Pwd); break; - default: - T55xxReadBlockExt (arg0, Block, Pwd) ; - } - -// T55xxReadBlockExt (arg0, Block, Pwd) ; - cmd_send(CMD_ACK,0,0,0,0,0); -} - void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); uint32_t i = 0; @@ -1844,15 +1605,16 @@ void T55xxWakeUp(uint32_t Pwd){ // Trigger T55x7 Direct Access Mode FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(T55xx_Timing_FixedBit.START_GAP); // Opcode 10 - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 + T55xxWriteBit(1,&T55xx_Timing_FixedBit); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); // Turn and leave field on to let the begin repeating transmission TurnReadLFOn(20*1000); @@ -1863,7 +1625,8 @@ void T55xxWakeUp(uint32_t Pwd){ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { // write last block first and config block last (if included) for (uint8_t i = numblocks+startblock; i > startblock; i--) { - T55xxWriteBlockExt(blockdata[i-1],i-1,0,0); + T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + // T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); } } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index ed980f9b..c64e5ef2 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -311,13 +311,13 @@ int CmdT55xxSetConfig(const char *Cmd) { } // No args - if (cmdp == 0) return printConfiguration( config ); + if (cmdp == 0) return printConfiguration( config); //Validations if (errors) return usage_t55xx_config(); config.block0 = 0; - return printConfiguration ( config ); + return printConfiguration ( config); } int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ @@ -476,6 +476,25 @@ bool DecodeT5555TraceBlock() { return (bool) ASKDemod("64 0 1", false, false, 1); } +void T55xx_Print_DownlinkMode (uint8_t downlink_mode) +{ + char Msg[80]; + sprintf (Msg,"Downlink Mode used : "); + + switch (downlink_mode) { + case 0 : strcat (Msg,"default/fixed bit length"); break; + case 1 : strcat (Msg,"long leading reference (r 1)"); break; + case 2 : strcat (Msg,"leading zero reference (r 2)"); break; + case 3 : strcat (Msg,"1 of 4 coding reference (r 3)"); break; + default : + strcat (Msg,"default/fixed bit length"); break; + + } + + PrintAndLog (Msg); + +} + int CmdT55xxDetect(const char *Cmd){ bool errors = false; bool useGB = false; @@ -522,13 +541,8 @@ int CmdT55xxDetect(const char *Cmd){ if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); else { - // Add downlink mode to reference. - switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + // Add downlink mode for reference. + T55xx_Print_DownlinkMode (downlink_mode); } return 1; } @@ -681,7 +695,8 @@ bool tryDetectModulation(){ config.block0 = tests[0].block0; config.Q5 = tests[0].Q5; config.ST = tests[0].ST; - printConfiguration( config ); + + printConfiguration( config); return true; } @@ -689,7 +704,7 @@ bool tryDetectModulation(){ PrintAndLog("Found [%d] possible matches for modulation.",hits); for(int i=0; i 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); + PrintAndLog("Acquiring data from device failed. Quitting"); free(keyBlock); return 0; } @@ -1551,12 +1566,9 @@ int CmdT55xxBruteForce(const char *Cmd) { if ( found ) { PrintAndLog("Found valid password: [%08X]", testpwd); free(keyBlock); - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + + T55xx_Print_DownlinkMode (dl_mode); + return 0; } if (!try_all_dl_modes) // Exit loop if not trying all downlink modes @@ -1597,7 +1609,7 @@ int CmdT55xxBruteForce(const char *Cmd) { // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); + PrintAndLog("Acquiring data from device failed. Quitting"); free(keyBlock); return 0; } @@ -1613,12 +1625,7 @@ int CmdT55xxBruteForce(const char *Cmd) { if (found){ PrintAndLog("Found valid password: [%08x]", i); - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading Zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + T55xx_Print_DownlinkMode (downlink_mode); } else{ PrintAndLog(""); From 2de26056ce3650d8ae48f30bf657e27b3669a0a3 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sun, 23 Jun 2019 07:43:56 -0400 Subject: [PATCH 14/29] add lf em 4x05protect plus lf config s option (#833) * add "samples to skip" for lf config (mainly for lf snoop) * add lf em 4x05protect command to write protection on em4x05 chips * fix spacing * and remove old comment git added back in.. * update changelog * fix flags - only need 1 bit --- CHANGELOG.md | 2 + armsrc/appmain.c | 3 ++ armsrc/apps.h | 1 + armsrc/lfops.c | 81 ++++++++++++++++++++++++++++--- armsrc/lfsampling.c | 20 +++++--- client/cmdlf.c | 34 +++++++------ client/cmdlfem4x.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ include/usb_cmd.h | 2 + 8 files changed, 231 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 399f87f9..cb508cd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `hf 15 sim` now works as expected (piwi) ### Added +- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) +- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) - Support Standard Communication Mode in HITAG S - Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) - `hf mfp` group of commands (Merlok) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 37328a50..5169383e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1088,6 +1088,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_EM4X_WRITE_WORD: EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]); break; + case CMD_EM4X_PROTECT: + EM4xProtect(c->arg[0], c->arg[1], c->arg[2]); + break; case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation CmdAWIDdemodFSK(c->arg[0], 0, 0, 1); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index d1c885ab..4d9a1482 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -89,6 +89,7 @@ void TurnReadLFOn(); //void T55xxReadTrace(void); void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd); +void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd); void Cotag(uint32_t arg0); /// iso14443.h diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 81fdd7a6..ed207dbb 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1198,10 +1198,45 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * and enlarge the gap ones. * Q5 tags seems to have issues when these values changes. */ -#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) -#define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) -#define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) -#define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 + +/* Q5 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 | 14*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ + +/* T5557 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 |50-150us | 30*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 31*8 | + * Write_1 Normal mode | 48*8 | 54*8 | 63*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 15*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 31*8 | +*/ + +/* T5577C timing datasheet for Fixed-Bit-Length protocol (defualt): + * Type | MIN | Typical | Max | + * Start_Gap | 8*8 | 15*8 | 50*8 | + * Write_Gap Normal mode | 8*8 | 10*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | 10*8 | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ + +//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) +#define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 +#define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us +#define WRITE_0 18*8 //18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) - T5557: 16*8 to 31*8 typ 24*8 +#define WRITE_1 50*8 //50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) - T5557: 48*8 to 63*8 typ 54*8 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 void TurnReadLFOn(int delay) { @@ -1355,7 +1390,7 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { T55xxWriteBit(1); T55xxWriteBit(Page); //Page 0 - if (PwdMode){ + if (PwdMode) { // Send Pwd for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i); @@ -1614,6 +1649,7 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 #define FWD_CMD_DISABLE 0x5 +#define FWD_CMD_PROTECT 0x3 uint8_t forwardLink_data[64]; //array of forwarded bits uint8_t * forward_ptr; //ptr for forward message preparation @@ -1783,7 +1819,7 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { - bool PwdMode = (flag & 0xF); + bool PwdMode = (flag & 0x1); uint8_t Address = (flag >> 8) & 0xFF; uint8_t fwd_bit_count; @@ -1813,6 +1849,39 @@ void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { LED_A_OFF(); cmd_send(CMD_ACK,0,0,0,0,0); } + +void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd) { + + bool PwdMode = (flag & 0x1); + uint8_t fwd_bit_count; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + LED_A_ON(); + StartTicks(); + //If password mode do login + if (PwdMode) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_PROTECT ); + + //unsure if this needs the full packet config... + fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); + + SendForward(fwd_bit_count); + + //Wait for write to complete + //SpinDelay(10); + + WaitUS(6500); + //Capture response if one exists + DoPartialAcquisition(20, true, 6000, 1000); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_A_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); +} /* Reading a COTAG. diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 03bccf41..e53d0205 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -14,7 +14,7 @@ #include "usb_cdc.h" // for usb_poll_validate_length #include "fpgaloader.h" -sample_config config = { 1, 8, 1, 95, 0 } ; +sample_config config = { 1, 8, 1, 95, 0, 0 } ; void printConfig() { @@ -24,6 +24,7 @@ void printConfig() Dbprintf(" [d] decimation: %d ", config.decimation); Dbprintf(" [a] averaging: %d ", config.averaging); Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); + Dbprintf(" [s] samples to skip: %d ", config.samples_to_skip); } @@ -34,7 +35,7 @@ void printConfig() * Other functions may read samples and ignore the sampling config, * such as functions to read the UID from a prox tag or similar. * - * Values set to '0' implies no change (except for averaging) + * Values set to '0' implies no change (except for averaging, threshold, samples_to_skip) * @brief setSamplingConfig * @param sc */ @@ -44,6 +45,7 @@ void setSamplingConfig(sample_config *sc) if(sc->bits_per_sample!= 0) config.bits_per_sample= sc->bits_per_sample; if(sc->decimation!= 0) config.decimation= sc->decimation; if(sc->trigger_threshold != -1) config.trigger_threshold= sc->trigger_threshold; + if(sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; config.averaging= sc->averaging; if(config.bits_per_sample > 8) config.bits_per_sample = 8; @@ -119,7 +121,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) * @param silent - is true, now outputs are made. If false, dbprints the status * @return the number of bits occupied by the samples. */ -uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after) +uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after, int samples_to_skip) { //. uint8_t *dest = BigBuf_get_addr(); @@ -141,6 +143,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag uint32_t sample_total_numbers =0 ; uint32_t sample_total_saved =0 ; uint32_t cancel_counter = 0; + uint32_t samples_skipped = 0; while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { WDT_HIT(); @@ -160,6 +163,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag continue; } trigger_threshold = 0; + if (samples_to_skip > samples_skipped) { + samples_skipped++; + continue; + } sample_total_numbers++; if(averaging) @@ -218,7 +225,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag */ uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { - return DoAcquisition(1,8,0,trigger_threshold,silent,0,0); + return DoAcquisition(1,8,0,trigger_threshold,silent,0,0,0); } uint32_t DoAcquisition_config(bool silent, int sample_size) { @@ -228,11 +235,12 @@ uint32_t DoAcquisition_config(bool silent, int sample_size) ,config.trigger_threshold ,silent ,sample_size - ,0); + ,0 + ,config.samples_to_skip); } uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) { - return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after); + return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after,0); } uint32_t ReadLF(bool activeField, bool silent, int sample_size) diff --git a/client/cmdlf.c b/client/cmdlf.c index 12d30663..f661e518 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -224,24 +224,25 @@ int usage_lf_config(void) { PrintAndLog("Usage: lf config [H|] [b ] [d ] [a 0|1]"); PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" L Low frequency (125 KHz)"); - PrintAndLog(" H High frequency (134 KHz)"); - PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); - PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); - PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); - PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); - PrintAndLog(" t Sets trigger threshold. 0 means no threshold (range: 0-128)"); + PrintAndLog(" h This help"); + PrintAndLog(" L Low frequency (125 KHz)"); + PrintAndLog(" H High frequency (134 KHz)"); + PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); + PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); + PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); + PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); + PrintAndLog(" t Sets trigger threshold. 0 means no threshold (range: 0-128)"); + PrintAndLog(" s Sets a number of samples to skip before capture. Default: 0"); PrintAndLog("Examples:"); PrintAndLog(" lf config b 8 L"); - PrintAndLog(" Samples at 125KHz, 8bps."); + PrintAndLog(" Samples at 125KHz, 8bps."); PrintAndLog(" lf config H b 4 d 3"); - PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with "); - PrintAndLog(" a resolution of 4 bits per sample."); + PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with "); + PrintAndLog(" a resolution of 4 bits per sample."); PrintAndLog(" lf read"); - PrintAndLog(" Performs a read (active field)"); + PrintAndLog(" Performs a read (active field)"); PrintAndLog(" lf snoop"); - PrintAndLog(" Performs a snoop (no active field)"); + PrintAndLog(" Performs a snoop (no active field)"); return 0; } @@ -255,6 +256,7 @@ int CmdLFSetConfig(const char *Cmd) bool errors = false; int trigger_threshold =-1;//Means no change uint8_t unsigned_trigg = 0; + int samples_to_skip = -1; uint8_t cmdp =0; while(param_getchar(Cmd, cmdp) != 0x00) @@ -295,6 +297,10 @@ int CmdLFSetConfig(const char *Cmd) averaging = param_getchar(Cmd,cmdp+1) == '1'; cmdp+=2; break; + case 's': + samples_to_skip = param_get32ex(Cmd,cmdp+1,0,10); + cmdp+=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = 1; @@ -316,7 +322,7 @@ int CmdLFSetConfig(const char *Cmd) if(bps >> 4) bps = 8; sample_config config = { - decimation,bps,averaging,divisor,trigger_threshold + decimation,bps,averaging,divisor,trigger_threshold,samples_to_skip }; //Averaging is a flag on high-bit of arg[1] UsbCommand c = {CMD_SET_LF_SAMPLING_CONFIG}; diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index cdaeb5ed..d1bde911 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1161,6 +1161,119 @@ int CmdEM4x05WriteWord(const char *Cmd) { return EM4x05WriteWord(addr, data, pwd, usePwd, swap, invert); } +int usage_lf_em_protect(void) { + PrintAndLog("Protect EM4x05. Tag must be on antenna. "); + PrintAndLog(""); + PrintAndLog("Usage: lf em 4x05protect [h] d p [s] [i]"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" d - data to write (hex)"); + PrintAndLog(" p - password (hex) (optional)"); + PrintAndLog(" s - swap the data bit order before write"); + PrintAndLog(" i - invert the data bits before write"); + PrintAndLog("samples:"); + PrintAndLog(" lf em 4x05protect d 11223344"); + PrintAndLog(" lf em 4x05protect p deadc0de d 11223344 s i"); + return 0; +} + +int EM4x05Protect(uint32_t data, uint32_t pwd, bool usePwd, bool swap, bool invert) { + if (swap) data = SwapBits(data, 32); + + if (invert) data ^= 0xFFFFFFFF; + + if ( !usePwd ) { + PrintAndLog("Writing Protect data %08X", data); + } else { + PrintAndLog("Writing Protect data %08X using password %08X", data, pwd); + } + + uint16_t flag = usePwd; + + UsbCommand c = {CMD_EM4X_PROTECT, {flag, data, pwd}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){ + PrintAndLog("Error occurred, device did not respond during protect operation."); + return -1; + } + if ( !downloadSamplesEM() ) { + return -1; + } + //check response for 00001010 for write confirmation! + //attempt demod: + uint32_t dummy = 0; + int result = demodEM4x05resp(&dummy,false); + if (result == 1) { + PrintAndLog("Protect Verified"); + } else { + PrintAndLog("Protect could not be verified"); + } + return result; +} + +int CmdEM4x05ProtectWrite(const char *Cmd) { + bool errors = false; + bool usePwd = false; + uint32_t data = 0xFFFFFFFF; + uint32_t pwd = 0xFFFFFFFF; + bool swap = false; + bool invert = false; + bool gotData = false; + char cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_lf_em_write(); + case 'd': + case 'D': + data = param_get32ex(Cmd, cmdp+1, 0, 16); + gotData = true; + cmdp += 2; + break; + case 'i': + case 'I': + invert = true; + cmdp++; + break; + case 'p': + case 'P': + pwd = param_get32ex(Cmd, cmdp+1, 1, 16); + if (pwd == 1) { + PrintAndLog("invalid pwd"); + errors = true; + } + usePwd = true; + cmdp += 2; + break; + case 's': + case 'S': + swap = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_lf_em_protect(); + + if ( strlen(Cmd) == 0 ) return usage_lf_em_protect(); + + if (!gotData) { + PrintAndLog("You must enter the data you want to write"); + return usage_lf_em_protect(); + } + return EM4x05Protect(data, pwd, usePwd, swap, invert); +} + void printEM4x05config(uint32_t wordData) { uint16_t datarate = EM4x05_GET_BITRATE(wordData); uint8_t encoder = ((wordData >> 6) & 0xF); @@ -1345,6 +1458,7 @@ static command_t CommandTable[] = {"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"}, {"4x05readword", CmdEM4x05ReadWord, 0, " (pwd) -- Read EM4x05/EM4x69 word data"}, {"4x05writeword", CmdEM4x05WriteWord, 0, " (pwd) -- Write EM4x05/EM4x69 word data"}, + {"4x05protect", CmdEM4x05ProtectWrite, 0, " (pwd) -- Write Protection to EM4x05"}, {"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"}, {NULL, NULL, 0, NULL} }; diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 9ef929b9..82981acf 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -41,6 +41,7 @@ typedef struct{ bool averaging; int divisor; int trigger_threshold; + int samples_to_skip; } sample_config; // For the bootloader @@ -116,6 +117,7 @@ typedef struct{ #define CMD_T55XX_WAKEUP 0x0224 #define CMD_COTAG 0x0225 #define CMD_PARADOX_CLONE_TAG 0x0226 +#define CMD_EM4X_PROTECT 0x0228 // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 From 99c52f9d85cf952d6a13dbd0be35cb6be1f50cdf Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 23 Jun 2019 22:23:08 +1000 Subject: [PATCH 15/29] Update CHANGELOG.md Change Log Update --- CHANGELOG.md | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55f1d1f9..19a20557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,33 +4,11 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol - 22 Jun 2019 - -# armsrc/lfops - +## T55xx Downlink Protocol ### Added -- Added typedef T55xx_Timing to hold downlink timings. -- Added Timing Records for long leading reference (llr), Leading 0 and 1 of 4 -- Added some constant defines for code readability -- Added function T55xx_SetBits to build a bit stream for writing to T55xx -- Added function T55xx_SendCMD to build the bit stream and send to T55xx - -### Changed -- Converted Timing for default/fixed bit to T55xx_Timing -- Updated T55xxWriteBit (and calls) to support all downlink protocols -- Updated T55xxWriteBlock to call T55xx_SendCMD (removed local bit writes) -- Updated T55xxReadBlock to call T55xx_SendCMD (removed local bit writes) - -# client/cmdlft55xx - -### Added -- Added function T55xx_Print_DownlinkMode to print downlink mode information when uesd - -### Changes -- Added downlink mode options r [ 0 (or missing) default/fixed bit, 1 long leading, leading 0 and 1 of 4 ] -- Added r 4 option to bruteforce to try all downlink modes (0,1,2 and 3) -- Updated help messages for each support functions t55xx_read, t55xx_write, t55_detect, t55xx_bruteforce - +- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] +- Added special option r 4 to bruteforce, to try all downlink modes (0,1,2 and 3) for each password +- Support added to lf t55xx detect, read, write, bruteforce ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) From d3521ae609658fa00955c8fd57f69eb84ce7a7cd Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 24 Jun 2019 08:42:57 +0200 Subject: [PATCH 16/29] Update CHANGELOG.md --- CHANGELOG.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19a20557..9439399a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol -### Added -- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] -- Added special option r 4 to bruteforce, to try all downlink modes (0,1,2 and 3) for each password -- Support added to lf t55xx detect, read, write, bruteforce - ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) @@ -39,6 +33,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) - Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) +- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` +- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password + ## [v3.1.0][2018-10-10] From e220fc63aaa4f61ca2f91216c4420c18612dd544 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 18:56:32 +1000 Subject: [PATCH 17/29] Update lfops.c --- armsrc/lfops.c | 50 +------------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c1f32f87..c56d08f9 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1219,55 +1219,7 @@ typedef struct { uint16_t READ_GAP; } T55xx_Timing; -/* - T5577 Timeing from datasheet for reference - - Fixed bit length - ---------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 15 50 8 15 50 - Write gap 8 10 20 8 10 20 - 0 data 16 24 32 8 12 16 - 1 data 48 56 64 24 28 32 - - - Long Leading Reference - ---------------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 152 160 168 140 144 148 - 136 + 0 data 132 + 0 data - 0 data r - 143 r - 136 r - 128 r - 135 r - 132 r - 124 - 1 data r - 111 r - 104 r - 96 r - 119 r - 116 r - 112 - - - Leading Zero Reference - ---------------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 12 - 72 8 - 68 - 0 data r - 7 r r + 8 r - 3 r r + 4 - 1 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 - - - 1 of 4 Coding - ------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 8 - 68 12 - 72 - 00 data r - 7 r r + 8 r - 3 r r + 4 - 01 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 - 10 data r + 25 r + 32 r + 40 r + 13 r + 16 r + 20 - 11 data r + 41 r + 48 r + 56 r + 21 r + 24 r + 28 - -*/ + // Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; From 50764caadcf78a3657ca014d4710fd2521dbd534 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 19:28:06 +1000 Subject: [PATCH 18/29] Update lfops.c --- armsrc/lfops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index efa75652..819653f0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1206,8 +1206,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 -======= +*/ /* Q5 timing datasheet: * Type | MIN | Typical | Max | * Start_Gap | 10*8 | ? | 50*8 | @@ -1240,7 +1240,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | */ - +/* //note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) #define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 #define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us @@ -1271,11 +1271,11 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 // Some defines for readability -#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero #define T55xx_DLMode_1of4 3 // 1 of 4 +#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1324,7 +1324,7 @@ int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , in bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr // If set (1) we OR, if clear (0) we AND with inverse - // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); + // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); if (bit == 1) bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 From 5a9964829e8e6ef8382ed8b61dc71b1705a270f7 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 20:46:10 +1000 Subject: [PATCH 19/29] Resolved Conflicts --- armsrc/lfops.c | 45 ++++++++++----------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 819653f0..19bf6555 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1307,32 +1307,17 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // num_bits - how many bits (low x bits of data) Max 32 bits at a time // max_len - how many bytes can the bit_array hold (ensure no buffer overflow) // returns "Next" bit offset / bits stored (for next store) -int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +int T55xx_SetBits (bool *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) { - int bit,byte_idx, bit_idx; int offset; int NextOffset = start_offset; // Check if data will fit. - if ((start_offset + num_bits) <= (max_len*8)) { - + if ((start_offset + num_bits) <= (max_len*8)) { // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) { - - bit = (data >> offset) & 1; // Get data bit value (0/1) - byte_idx = (NextOffset / 8); // Get Array Byte Index to Store - bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr - - // If set (1) we OR, if clear (0) we AND with inverse - // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); - if (bit == 1) - bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 - - else - bit_array[byte_idx] &= (0xff ^ (1 << bit_idx)); // Set the bit to 0 (clr) - - NextOffset++; - } + for (offset = (num_bits-1); offset >= 0; offset--) + bit_array[NextOffset++] = (data >> offset) & 1; } else Dbprintf ("Too Many Bits to fit into bit buffer"); @@ -1390,11 +1375,11 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { bool reg_readmode = ((arg & 0x20) == 0x20); bool read_cmd = ((arg & 0x40) == 0x40); - int i = 0; - uint8_t BitStream[10]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) + int i = 0; + bool BitStream[100]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; - int byte_idx, bit_idx; T55xx_Timing *Timing; + uint8_t SendBits; // Assigning Downlink Timeing for write @@ -1463,26 +1448,16 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - uint8_t SendBits; if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time for (i = 0; i < BitStreamLen; i+=2) { - byte_idx = i / 8; - bit_idx = i - (byte_idx * 8); - SendBits = ((BitStream[byte_idx] >> bit_idx) & 1) << 1; - - byte_idx = (i+1) / 8; - bit_idx = (i+1) - (byte_idx * 8); - SendBits += (BitStream[byte_idx] >> bit_idx) & 1; - + SendBits = (BitStream[i] << 1) + BitStream[i+1]; T55xxWriteBit (SendBits,Timing); } } else { for (i = 0; i < BitStreamLen; i++) { - byte_idx = i / 8; - bit_idx = i - (byte_idx * 8); - SendBits = (BitStream[byte_idx] >> bit_idx) & 1; + SendBits = (BitStream[i]); T55xxWriteBit (SendBits,Timing); } } From 2994ab10d64e4121a1894b8f01e350be4fc1e988 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 20:52:29 +1000 Subject: [PATCH 20/29] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 037bab99..a3421c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] +## T55xx Downlink Protocol +### Added +- Added downlink reference mode option r [ 0 - (default) fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] +Supported commands lf t55xx detect, read, write, bruteforce (with special r 4 to try all downlink modes) (mwalker33) + + ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) From 59f75a789546405310e6ba06c01d9c6582a69071 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 25 Jun 2019 18:37:25 +0200 Subject: [PATCH 21/29] Update CHANGELOG.md --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3421c77..037bab99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol -### Added -- Added downlink reference mode option r [ 0 - (default) fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] -Supported commands lf t55xx detect, read, write, bruteforce (with special r 4 to try all downlink modes) (mwalker33) - - ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) From 7db36608a266a1f0f46dd4032cede2930e221d51 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Wed, 26 Jun 2019 11:34:31 +1000 Subject: [PATCH 22/29] Code improved for less memory --- armsrc/lfops.c | 236 ++++++++++++++++++++++++------------------------- 1 file changed, 117 insertions(+), 119 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 19bf6555..95fa9e7c 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1261,21 +1261,22 @@ typedef struct { uint16_t READ_GAP; } T55xx_Timing; - - // Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 }; - // Some defines for readability #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero #define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference +// Macro for code readability +#define BitStream_Byte(X) ((X) / 8) +#define BitStream_Bit(X) ((X) - ((X) / 8) * 8) + void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1299,7 +1300,6 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { WaitUS(Timings->WRITE_GAP); } - // Function to abstract an Arbitrary length byte array to store bit pattern. // bit_array - Array to hold data/bit pattern // start_offset - bit location to start storing new bits. @@ -1308,22 +1308,129 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // max_len - how many bytes can the bit_array hold (ensure no buffer overflow) // returns "Next" bit offset / bits stored (for next store) //int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) -int T55xx_SetBits (bool *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) { - int offset; - int NextOffset = start_offset; + int8_t offset; + int8_t NextOffset = start_offset; // Check if data will fit. if ((start_offset + num_bits) <= (max_len*8)) { // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) - bit_array[NextOffset++] = (data >> offset) & 1; + for (offset = (num_bits-1); offset >= 0; offset--) { + + if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 + else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 + + NextOffset++; + } } else Dbprintf ("Too Many Bits to fit into bit buffer"); + return NextOffset; } +// Send one downlink command to the card +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { + + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + + */ + bool PwdMode = ((arg & 0x01) == 0x01); + uint8_t Page = (arg & 0x02) >> 1; + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + uint8_t i = 0; + uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) + uint8_t BitStreamLen; + T55xx_Timing *Timing; + uint8_t SendBits; + + // Assigning Downlink Timeing for write + switch (downlink_mode) + { + case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; + case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; + default: + Timing = &T55xx_Timing_FixedBit; + } + + // Build Bit Stream to send. + memset (BitStream,0x00,sizeof(BitStream)); + + BitStreamLen = 0; + + // Add Leading 0 and 1 of 4 reference bit + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add extra reference 0 for 1 of 4 + if (downlink_mode == T55xx_DLMode_1of4) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Opcode + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } + + // Add Lock bit 0 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + + // Send Bits to T55xx + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(Timing->START_GAP); + + // If long leading 0 send long reference pulse + if (downlink_mode == T55xx_DLMode_LLR) + T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference + + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for ( i = 0; i < BitStreamLen; i+=2 ) { + SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i + SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; + T55xxWriteBit (SendBits & 3,Timing); + } + } + else { + for (i = 0; i < BitStreamLen; i++) { + SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); + T55xxWriteBit (SendBits & 1,Timing); + } + } +} + // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); @@ -1355,115 +1462,6 @@ void T55xxResetRead(void) { LED_A_OFF(); } -// Send one downlink command to the card -void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { - - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - - */ - bool PwdMode = ((arg & 0x01) == 0x01); - uint8_t Page = (arg & 0x02) >> 1; - bool testMode = ((arg & 0x04) == 0x04); - uint8_t downlink_mode = (arg >> 3) & 0x03;; - bool reg_readmode = ((arg & 0x20) == 0x20); - bool read_cmd = ((arg & 0x40) == 0x40); - - int i = 0; - bool BitStream[100]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) - uint8_t BitStreamLen; - T55xx_Timing *Timing; - uint8_t SendBits; - - - // Assigning Downlink Timeing for write - switch (downlink_mode) - { - case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; - case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; - case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; - case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; - default: - Timing = &T55xx_Timing_FixedBit; - } - - // Build Bit Stream to send. - memset (BitStream,0x00,sizeof(BitStream)); - - BitStreamLen = 0; - - // Add Leading 0 and 1 of 4 reference bit - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add extra reference 0 for 1 of 4 - if (downlink_mode == T55xx_DLMode_1of4) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Opcode - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - - if (PwdMode) { - - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - - } - // Add Lock bit - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); - - - - // Send Bits to T55xx - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(Timing->START_GAP); - - - // If long leading 0 send long reference pulse - if (downlink_mode == T55xx_DLMode_LLR) - T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - - - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time - for (i = 0; i < BitStreamLen; i+=2) { - SendBits = (BitStream[i] << 1) + BitStream[i+1]; - T55xxWriteBit (SendBits,Timing); - } - } - else { - for (i = 0; i < BitStreamLen; i++) { - SendBits = (BitStream[i]); - T55xxWriteBit (SendBits,Timing); - } - } - -} - // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { /* @@ -1518,6 +1516,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // Read one card block in page [page] +//void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { LED_A_ON(); @@ -1613,7 +1612,6 @@ void T55xxWakeUp(uint32_t Pwd){ T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); From 28597bb6c742c6d717d33aebdbb5b0ba98bc95eb Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Thu, 27 Jun 2019 16:57:28 +1000 Subject: [PATCH 23/29] Update lfops.c moved wakeup and reset to call T55xx_SendCMD. Small code improvements --- armsrc/lfops.c | 110 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 95fa9e7c..16a46910 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1274,8 +1274,8 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 #define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference // Macro for code readability -#define BitStream_Byte(X) ((X) / 8) -#define BitStream_Bit(X) ((X) - ((X) / 8) * 8) +#define BitStream_Byte(X) ((X) >> 3) +#define BitStream_Bit(X) ((X) & 7) void TurnReadLFOn(int delay) { @@ -1288,7 +1288,7 @@ void TurnReadLFOn(int delay) { void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 - + // Dbprintf ("Bits : %d",bit); switch (bit){ case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 @@ -1324,14 +1324,16 @@ int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uin NextOffset++; } } - else - Dbprintf ("Too Many Bits to fit into bit buffer"); - + else{ + // Note: This should never happen unless some code changes cause it. + // So short message for coders when testing. + Dbprintf ("T55 too many bits"); + } return NextOffset; } // Send one downlink command to the card -void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { /* arg bits @@ -1339,16 +1341,19 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet - + 1xxxxxxx 0x80 reset + */ bool PwdMode = ((arg & 0x01) == 0x01); - uint8_t Page = (arg & 0x02) >> 1; + bool Page = (arg & 0x02); bool testMode = ((arg & 0x04) == 0x04); uint8_t downlink_mode = (arg >> 3) & 0x03; bool reg_readmode = ((arg & 0x20) == 0x20); bool read_cmd = ((arg & 0x40) == 0x40); + bool reset = (arg & 0x80); + uint8_t i = 0; uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; @@ -1379,29 +1384,35 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_1of4) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - // Add Opcode - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + // Add Opcode + if (reset) { + // Reset : r*) 00 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + else + { + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - if (PwdMode) { - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - } + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } - // Add Lock bit 0 - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + // Add Lock bit 0 + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + } + // Send Bits to T55xx // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1434,6 +1445,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); +/* //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1452,6 +1464,15 @@ void T55xxResetRead(void) { T55xxWriteBit(0,&T55xx_Timing_FixedBit); TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); +*/ + + // send r* 00 + uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + T55xx_SendCMD (0, 0, 0, arg); //, true); // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); @@ -1470,8 +1491,9 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset */ bool testMode = ((arg & 0x04) == 0x04); @@ -1516,7 +1538,6 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // Read one card block in page [page] -//void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { LED_A_ON(); @@ -1527,14 +1548,15 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset */ // Set Read Flag to ensure SendCMD does not add "data" to the packet arg0 |= 0x40; - + // RegRead Mode true of block 0xff if (Block == 0xff) arg0 |= 0x20; //make sure block is at max 7 @@ -1595,8 +1617,8 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); + /* uint32_t i = 0; - // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); StartTicks(); @@ -1614,6 +1636,26 @@ void T55xxWakeUp(uint32_t Pwd){ // Send Pwd for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); +*/ + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset + */ + + // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD + // So, default Opcode 10 and pwd. + uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + T55xx_SendCMD (0, 0, Pwd, arg); //, true); // Turn and leave field on to let the begin repeating transmission TurnReadLFOn(20*1000); From d7569065cb7464f42005b2fdbc17feef7d2f129b Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Wed, 3 Jul 2019 19:58:49 +1000 Subject: [PATCH 24/29] Code tidy removed commented code --- armsrc/lfops.c | 72 -------------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 16a46910..4a7de24d 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1445,26 +1445,6 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); -/* - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_keep_EM(); - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(T55xx_Timing_FixedBit.START_GAP); - - // reset tag - op code 00 - T55xxWriteBit(0,&T55xx_Timing_FixedBit); - T55xxWriteBit(0,&T55xx_Timing_FixedBit); - - TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); -*/ // send r* 00 uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). @@ -1566,39 +1546,7 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 BigBuf_Clear_ext(false); T55xx_SendCMD (0, Block, Pwd, arg0); //, true); - -/* -// the send has been moved to the above SendCMD Call -======= - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Opcode 1[page] - T55xxWriteBit(1); - T55xxWriteBit(Page); //Page 0 - - if (PwdMode) { - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); - - -*/ // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... // but we want to go past the start and let the repeating data settle in... @@ -1617,26 +1565,6 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); - /* - uint32_t i = 0; - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - - // Trigger T55x7 Direct Access Mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(T55xx_Timing_FixedBit.START_GAP); - - // Opcode 10 - T55xxWriteBit(1,&T55xx_Timing_FixedBit); - T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 - - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); -*/ /* arg bits xxxxxxx1 0x01 PwdMode From dcd936a1da12a50a4084f4445d8ebbb080b5bc36 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sat, 6 Jul 2019 15:20:25 +1000 Subject: [PATCH 25/29] Update lfops.c Fixed lf t55 reset --- armsrc/lfops.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 4a7de24d..c6aecf0f 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1201,11 +1201,13 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) /* // Original Timings for reference +//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) #define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 +#define READ_GAP 15*8 */ /* Q5 timing datasheet: @@ -1240,15 +1242,6 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | */ -/* -//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) -#define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 -#define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us -#define WRITE_0 18*8 //18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) - T5557: 16*8 to 31*8 typ 24*8 -#define WRITE_1 50*8 //50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) - T5557: 48*8 to 63*8 typ 54*8 432 for T55x7; 448 for E5550 - -#define READ_GAP 15*8 -*/ // Structure to hold Timing values. In future will be simplier to add user changable timings. typedef struct { @@ -1374,7 +1367,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Build Bit Stream to send. memset (BitStream,0x00,sizeof(BitStream)); - BitStreamLen = 0; + BitStreamLen = 0; // Ensure 0 bit index to start. // Add Leading 0 and 1 of 4 reference bit if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) @@ -1427,8 +1420,8 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time - for ( i = 0; i < BitStreamLen; i+=2 ) { + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; T55xxWriteBit (SendBits & 3,Timing); @@ -1452,8 +1445,13 @@ void T55xxResetRead(void) { // Add in downlink_mode when ready // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_keep_EM(); + T55xx_SendCMD (0, 0, 0, arg); //, true); + TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); + // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); From bdc97796459e46419e72468b2e92d46f0a10a56e Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 7 Jul 2019 05:00:08 +1000 Subject: [PATCH 26/29] Update lfops.c boundary length check --- armsrc/lfops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c6aecf0f..ed83df48 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1420,7 +1420,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; From 347efc12741e72e6ce3a3c4f3ed554fae0cefc73 Mon Sep 17 00:00:00 2001 From: jmorsch Date: Thu, 11 Jul 2019 13:01:36 -0400 Subject: [PATCH 27/29] whitespace cleaning --- armsrc/lfops.c | 172 ++++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index ed83df48..c9947d97 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1264,7 +1264,7 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero -#define T55xx_DLMode_1of4 3 // 1 of 4 +#define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference // Macro for code readability #define BitStream_Byte(X) ((X) >> 3) @@ -1281,14 +1281,14 @@ void TurnReadLFOn(int delay) { void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 - // Dbprintf ("Bits : %d",bit); + // Dbprintf ("Bits : %d",bit); switch (bit){ case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 - case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 - case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference - } + case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 + case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(Timings->WRITE_GAP); } @@ -1303,31 +1303,31 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { //int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) { - int8_t offset; - int8_t NextOffset = start_offset; + int8_t offset; + int8_t NextOffset = start_offset; - // Check if data will fit. - if ((start_offset + num_bits) <= (max_len*8)) { - // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) { + // Check if data will fit. + if ((start_offset + num_bits) <= (max_len*8)) { + // Loop through the data and store + for (offset = (num_bits-1); offset >= 0; offset--) { - if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 - else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 + if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 + else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 - NextOffset++; - } - } - else{ - // Note: This should never happen unless some code changes cause it. - // So short message for coders when testing. - Dbprintf ("T55 too many bits"); - } - return NextOffset; + NextOffset++; + } + } + else { + // Note: This should never happen unless some code changes cause it. + // So short message for coders when testing. + Dbprintf ("T55 too many bits"); + } + return NextOffset; } // Send one downlink command to the card void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - + /* arg bits xxxxxxx1 0x01 PwdMode @@ -1337,32 +1337,32 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset - + */ - bool PwdMode = ((arg & 0x01) == 0x01); - bool Page = (arg & 0x02); - bool testMode = ((arg & 0x04) == 0x04); - uint8_t downlink_mode = (arg >> 3) & 0x03; - bool reg_readmode = ((arg & 0x20) == 0x20); - bool read_cmd = ((arg & 0x40) == 0x40); - bool reset = (arg & 0x80); - - uint8_t i = 0; + bool PwdMode = ((arg & 0x01) == 0x01); + bool Page = (arg & 0x02); + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + bool reset = (arg & 0x80); + + uint8_t i = 0; uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; T55xx_Timing *Timing; uint8_t SendBits; - + // Assigning Downlink Timeing for write switch (downlink_mode) { case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; - case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; default: Timing = &T55xx_Timing_FixedBit; - } + } // Build Bit Stream to send. memset (BitStream,0x00,sizeof(BitStream)); @@ -1370,42 +1370,42 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { BitStreamLen = 0; // Ensure 0 bit index to start. // Add Leading 0 and 1 of 4 reference bit - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); // Add extra reference 0 for 1 of 4 - if (downlink_mode == T55xx_DLMode_1of4) + if (downlink_mode == T55xx_DLMode_1of4) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); // Add Opcode - if (reset) { - // Reset : r*) 00 - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } - else - { - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - - if (PwdMode) { - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - } + if (reset) { + // Reset : r*) 00 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + else + { + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - // Add Lock bit 0 - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + // Add Lock bit 0 + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + } - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); - } - // Send Bits to T55xx // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1420,18 +1420,18 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time + if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i - SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; + SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; T55xxWriteBit (SendBits & 3,Timing); } } else { for (i = 0; i < BitStreamLen; i++) { - SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); + SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); T55xxWriteBit (SendBits & 1,Timing); - } + } } } @@ -1439,11 +1439,11 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { void T55xxResetRead(void) { LED_A_ON(); - // send r* 00 - uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). + // send r* 00 + uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1474,7 +1474,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { 1xxxxxxx 0x80 reset */ - bool testMode = ((arg & 0x04) == 0x04); + bool testMode = ((arg & 0x04) == 0x04); arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 LED_A_ON (); @@ -1509,7 +1509,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - + cmd_send(CMD_ACK,0,0,0,0,0); LED_A_OFF (); @@ -1517,7 +1517,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Read one card block in page [page] void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { - + LED_A_ON(); /* @@ -1530,11 +1530,11 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset */ - + // Set Read Flag to ensure SendCMD does not add "data" to the packet arg0 |= 0x40; - // RegRead Mode true of block 0xff + // RegRead Mode true of block 0xff if (Block == 0xff) arg0 |= 0x20; //make sure block is at max 7 @@ -1542,7 +1542,7 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 //clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); - + T55xx_SendCMD (0, Block, Pwd, arg0); //, true); // Turn field on to read the response @@ -1573,13 +1573,13 @@ void T55xxWakeUp(uint32_t Pwd){ x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset */ - - // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD - // So, default Opcode 10 and pwd. - uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block - - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD + // So, default Opcode 10 and pwd. + uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) T55xx_SendCMD (0, 0, Pwd, arg); //, true); @@ -1592,8 +1592,8 @@ void T55xxWakeUp(uint32_t Pwd){ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { // write last block first and config block last (if included) for (uint8_t i = numblocks+startblock; i > startblock; i--) { - T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); - // T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + //T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); } } From 817611f5651d4e99e13f091baf098d8385c69cb8 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Thu, 11 Jul 2019 14:31:51 -0400 Subject: [PATCH 28/29] update em4x05 timing (#846) See @mwalker33 issue #838 --- armsrc/lfops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c9947d97..12f9de08 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1907,7 +1907,7 @@ void SendForward(uint8_t fwd_bit_count) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on WaitUS(18*8); //18 cycles on (8us each) - // now start writting + // now start writting - each bit should be 32*8 total length while(fwd_bit_sz-- > 0) { //prepare next bit modulation if(((*fwd_write_ptr++) & 1) == 1) WaitUS(32*8); //32 cycles at 125Khz (8us each) @@ -1916,7 +1916,7 @@ void SendForward(uint8_t fwd_bit_count) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off WaitUS(23*8); //23 cycles off (8us each) FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - WaitUS(18*8); //18 cycles on (8us each) + WaitUS((32-23)*8); //remaining cycles on (8us each) } } } From 096dee178438c0a722eaf112c8b63ad4eaa9064a Mon Sep 17 00:00:00 2001 From: t0m4 Date: Sun, 14 Jul 2019 12:31:33 +0200 Subject: [PATCH 29/29] Add 'hf 15 csetuid' command to set UID on ISO15693 Magic tags (#842) --- CHANGELOG.md | 1 + armsrc/appmain.c | 5 +++ armsrc/iso15693.c | 79 +++++++++++++++++++++++++++++++++++++++++ armsrc/iso15693.h | 1 + client/cmdhf15.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++- client/cmdhf15.h | 1 + include/usb_cmd.h | 1 + 7 files changed, 177 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 037bab99..d5cd979d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `hf 15 sim` now works as expected (piwi) ### Added +- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) - Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) - Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) - Support Standard Communication Mode in HITAG S diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5169383e..9b9acb6f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1158,9 +1158,14 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_READER_ISO_15693: ReaderIso15693(c->arg[0]); break; + case CMD_SIMTAG_ISO_15693: SimTagIso15693(c->arg[0], c->d.asBytes); break; + + case CMD_CSETUID_ISO_15693: + SetTag15693Uid(c->d.asBytes); + break; #endif #ifdef WITH_LEGICRF diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e3524375..f4120512 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1591,6 +1591,85 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint LED_A_OFF(); } +//----------------------------------------------------------------------------- +// Work with "magic Chinese" card. +// +//----------------------------------------------------------------------------- + +// Set the UID to the tag (based on Iceman work). +void SetTag15693Uid(uint8_t *uid) +{ + uint8_t cmd[4][9] = {0x00}; + + uint16_t crc; + + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + LED_A_ON(); + + // Command 1 : 02213E00000000 + cmd[0][0] = 0x02; + cmd[0][1] = 0x21; + cmd[0][2] = 0x3e; + cmd[0][3] = 0x00; + cmd[0][4] = 0x00; + cmd[0][5] = 0x00; + cmd[0][6] = 0x00; + + // Command 2 : 02213F69960000 + cmd[1][0] = 0x02; + cmd[1][1] = 0x21; + cmd[1][2] = 0x3f; + cmd[1][3] = 0x69; + cmd[1][4] = 0x96; + cmd[1][5] = 0x00; + cmd[1][6] = 0x00; + + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][0] = 0x02; + cmd[2][1] = 0x21; + cmd[2][2] = 0x38; + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; + + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][0] = 0x02; + cmd[3][1] = 0x21; + cmd[3][2] = 0x39; + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; + + for (int i=0; i<4; i++) { + // Add the CRC + crc = Crc(cmd[i], 7); + cmd[i][7] = crc & 0xff; + cmd[i][8] = crc >> 8; + + if (DEBUG) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + } + + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); + + if (DEBUG) { + Dbprintf("RECV:"); + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + + cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } + + LED_D_OFF(); + + LED_A_OFF(); +} diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index e5b78a8a..68df2693 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -19,6 +19,7 @@ void ReaderIso15693(uint32_t parameter); void SimTagIso15693(uint32_t parameter, uint8_t *uid); void BruteforceIso15693Afi(uint32_t speed); void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); +void SetTag15693Uid(uint8_t *uid); void SetDebugIso15693(uint32_t flag); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 5a7973f6..c2a13354 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -382,6 +382,7 @@ static command_t CommandTable15[] = {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"}, + {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, {NULL, NULL, 0, NULL} }; @@ -954,6 +955,92 @@ int CmdHF15CmdWrite(const char *Cmd) { return 0; } +int CmdHF15CSetUID(const char *Cmd) +{ + uint8_t uid[8] = {0x00}; + uint8_t oldUid[8], newUid[8] = {0x00}; + + uint8_t needHelp = 0; + char cmdp = 1; + + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 16)) { + PrintAndLog("UID must include 16 HEX symbols"); + return 1; + } + + if (uid[0] != 0xe0) { + PrintAndLog("UID must begin with the byte 'E0'"); + return 1; + } + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + needHelp = 1; + break; + default: + PrintAndLog("ERROR: Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + needHelp = 1; + break; + } + cmdp++; + } + + if (strlen(Cmd) < 1 || needHelp) { + PrintAndLog(""); + PrintAndLog("Usage: hf 15 csetuid "); + PrintAndLog("sample: hf 15 csetuid E004013344556677"); + PrintAndLog("Set UID for magic Chinese card (only works with such cards)"); + return 0; + } + + PrintAndLog(""); + PrintAndLog("new UID | %s", sprint_hex(uid, 8)); + PrintAndLog("Using backdoor Magic tag function"); + + if (!getUID(oldUid)) { + PrintAndLog("Can't get old UID."); + return 1; + } + + UsbCommand resp; + uint8_t *recv; + char *hexout; + UsbCommand c = {CMD_CSETUID_ISO_15693, {0, 0, 0}}; + memcpy(c.d.asBytes, uid, 8); + + SendCommand(&c); + + for (int i=0; i<4; i++) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + recv = resp.d.asBytes; + PrintAndLog("received %i octets",resp.arg[0]); + hexout = (char *)malloc(resp.arg[0] * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < resp.arg[0]; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); + } + } else { + PrintAndLog("timeout while waiting for reply."); + } + } + + if (!getUID(newUid)) { + PrintAndLog("Can't get new UID."); + return 1; + } + + PrintAndLog(""); + PrintAndLog("old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); + PrintAndLog("new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); + return 0; +} static command_t CommandTable15Cmd[] = @@ -967,7 +1054,8 @@ static command_t CommandTable15Cmd[] = {"write", CmdHF15CmdWrite, 0, "Write a block"}, {"readmulti",CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"}, {"sysinfo",CmdHF15CmdSysinfo, 0, "Get Card Information"}, - {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf15.h b/client/cmdhf15.h index d0517fe5..ddaa4f71 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -22,6 +22,7 @@ int CmdHF15Reader(const char *Cmd); int CmdHF15Sim(const char *Cmd); int CmdHF15Record(const char *Cmd); int CmdHF15Cmd(const char*Cmd); +int CmdHF15CSetUID(const char *Cmd); int CmdHF15CmdHelp(const char*Cmd); int CmdHF15Help(const char*Cmd); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 82981acf..c998bf94 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -132,6 +132,7 @@ typedef struct{ #define CMD_ISO_15693_FIND_AFI 0x0315 #define CMD_ISO_15693_DEBUG 0x0316 #define CMD_LF_SNOOP_RAW_ADC_SAMPLES 0x0317 +#define CMD_CSETUID_ISO_15693 0x0318 // For Hitag2 transponders #define CMD_SNOOP_HITAG 0x0370