diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c43c33c..94d492c41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001) + - Fixed `hf 15693/iclass sniff` trace timings (@nvx) + - Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp) + - Fixed `trace list` - now handles marking of crc bytes w color a bit better (@iceman1001) + - Changed `hf mfu pwdgen -r` - now generates pwd/pack for Philips Sonicare, thanks @ckuenzi, @atc1441 (@iceman1001) + - Changed `hf mfu info` - now detects Philips Sonicare devices (@iceman1001) - Fixed truncated FPGA upload due to incorrect integer size variable (@d18c7db) - Changed `usart btfactory` - handles the new BT board with version "BT SPP V3.0" (@iceman1001) - Changed `hf mf eview --sk` - now can extract keys and save to file (@iceman1001) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index daa84f886..703f1288f 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1736,14 +1736,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla // no need to try decoding reader data if the tag is sending if (!tag_is_active) { - if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader)) { + int extra_8s = 1; + if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader) || + (++extra_8s && Handle15693SampleFromReader(sniffdata & 0x01, &dreader))) { - uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF if (dreader.byteCount > 0) { + // sof/eof_times are in ssp_clk, which is 13.56MHz / 4 + // not sure where the extra +8's on the EOF time comes from though, if someone knows update this comment + uint32_t eof_time = dma_start_time + (samples * 16) + (extra_8s * 8) - DELAY_READER_TO_ARM_SNIFF; // end of EOF uint32_t sof_time = eof_time - - dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - - 32 * 16 // time for SOF transfer - - 16 * 16; // time for EOF transfer + - dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 1024 : 16384) // time for byte transfers + - 256 // time for SOF transfer (1024/fc / 4) + - 128; // time for EOF transfer (512/fc / 4) + // sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); if (!iclass) { // Those flags don't exist in iClass @@ -1751,52 +1756,38 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH; } } + // And ready to receive another command. //DecodeReaderReset(&dreader); // already reseted DecodeTagReset(&dtag); DecodeTagFSKReset(&dtagfsk); reader_is_active = false; expect_tag_answer = true; - } else if (Handle15693SampleFromReader(sniffdata & 0x01, &dreader)) { - - uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (dreader.byteCount > 0) { - uint32_t sof_time = eof_time - - dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - - 32 * 16 // time for SOF transfer - - 16 * 16; // time for EOF transfer - LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); - if (!iclass) { // Those flags don't exist in iClass - expect_fsk_answer = dreader.output[0] & ISO15_REQ_SUBCARRIER_TWO; - expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH; - } - } - // And ready to receive another command - //DecodeReaderReset(&dreader); // already reseted - DecodeTagReset(&dtag); - DecodeTagFSKReset(&dtagfsk); - reader_is_active = false; - expect_tag_answer = true; } else { reader_is_active = (dreader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); } } - if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (!reader_is_active && expect_tag_answer) { if (!expect_fsk_answer) { + // single subcarrier tag response if (Handle15693SamplesFromTag((sniffdata >> 4) << 2, &dtag, expect_fast_answer)) { + // sof/eof_times are in ssp_clk, which is 13.56MHz / 4 uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF if (dtag.lastBit == SOF_PART2) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } uint32_t sof_time = eof_time - - dtag.len * 8 * 8 * 16 // time for byte transfers - - (32 * 16) // time for SOF transfer - - (dtag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer + - dtag.len * 1024 // time for byte transfers (4096/fc / 4) + - 512 // time for SOF transfer (2048/fc / 4) + - (dtag.lastBit != SOF_PART2 ? 512 : 0); // time for EOF transfer (2048/fc / 4) + // sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq LogTrace_ISO15693(dtag.output, dtag.len, (sof_time * 4), (eof_time * 4), NULL, false); + // And ready to receive another response. DecodeTagReset(&dtag); DecodeTagFSKReset(&dtagfsk); @@ -1807,26 +1798,23 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA); } } else { + // dual subcarrier tag response if (FREQ_IS_0((sniffdata >> 2) & 0x3)) // tolerate 1 00 sniffdata = sniffdata_prev; if (Handle15693FSKSamplesFromTag((sniffdata >> 2) & 0x3, &dtagfsk, expect_fast_answer)) { - expect_fsk_answer = false; - } else { - tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484); - } - if (!expect_fsk_answer) { - // FSK answer no more expected: switch back to ASK if (dtagfsk.len > 0) { + // sof/eof_times are in ssp_clk, which is 13.56MHz / 4 uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF if (dtagfsk.lastBit == SOF) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } uint32_t sof_time = eof_time - - dtagfsk.len * 8 * 8 * 16 // time for byte transfers - - (32 * 16) // time for SOF transfer - - (dtagfsk.lastBit != SOF ? (32 * 16) : 0); // time for EOF transfer + - dtagfsk.len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different + - 512 // time for SOF transfer (2048/fc / 4) + - (dtagfsk.lastBit != SOF ? 512 : 0); // time for EOF transfer (2048/fc / 4) + // sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq LogTrace_ISO15693(dtagfsk.output, dtagfsk.len, (sof_time * 4), (eof_time * 4), NULL, false); } @@ -1834,6 +1822,10 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla DecodeReaderReset(&dreader); expect_tag_answer = false; tag_is_active = false; + // FSK answer no more expected: switch back to ASK + expect_fsk_answer = false; + } else { + tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484); } } } diff --git a/client/dictionaries/mfulc_default_keys.dic b/client/dictionaries/mfulc_default_keys.dic index 51b4b9365..09dea8caf 100644 --- a/client/dictionaries/mfulc_default_keys.dic +++ b/client/dictionaries/mfulc_default_keys.dic @@ -1,5 +1,5 @@ # -# Mifare Ultralight Default Keys +# Mifare Ultralight C Default Keys # -- iceman fork version -- # -- contribute to this list, sharing is caring -- # diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index d6260ac88..21684b6fb 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -221,7 +221,7 @@ end --- -- curency-codes for Legic-Cash-Segments (ISO 4217) local currency = { - ["03d2"]="EUR", + ["03D2"]="EUR", ["0348"]="USD", ["033A"]="GBP", ["02F4"]="CHF" @@ -1447,7 +1447,10 @@ function dumpLegicCash(tag, x) print("--------------------------------\n\tLegic-Cash Values\n--------------------------------") local limit, curr, balance, rid, tcv -- currency of balance & limit - curr=currency[tag.SEG[x].data[8]..tag.SEG[x].data[9]] + curr=string.upper(tag.SEG[x].data[8]..tag.SEG[x].data[9]) + if currency[curr] ~= nil then + curr = currency[curr] + end -- maximum balance limit=string.format("%4.2f", tonumber(tag.SEG[x].data[10]..tag.SEG[x].data[11]..tag.SEG[x].data[12], 16)/100) -- current balance @@ -1784,17 +1787,17 @@ end --- -- edit Segment Data -function editSegmentData(data) +function editSegmentData(data, uid) io.write("\n") if istable(data) == false then print("no Segment-Data found") end - local lc = check4LegicCash(data) + local lc = check4LegicCash(data, uid) for i=0, #data-1 do data[i]=input(accyan.."Data"..i..acoff..": ", data[i]) end if (lc) then - data = fixLegicCash(data) + data = fixLegicCash(data, uid) end return data end @@ -1917,7 +1920,7 @@ function autoSelectSegment(tag, s) repeat io.write(". ") x=x-1 - res=check4LegicCash(tag.SEG[x].data) + res=check4LegicCash(tag.SEG[x].data, uid) until ( res or x==0 ) end --- @@ -2011,7 +2014,7 @@ end --- -- edit Legic Cash -function editLegicCash(data) +function editLegicCash(data, uid) local limit, curr, balance, rid, tcv -- currency of balance & limit curr=currency[data[8]..data[9]] @@ -2064,12 +2067,12 @@ function editLegicCash(data) data[20]=string.sub(rid, 5, 6) end - return fixLegicCash(data) + return fixLegicCash(data, uid) end --- -- chack for signature of a 'Legic-Cash-Segment' -function check4LegicCash(data) +function check4LegicCash(data, uid) if(#data==32) then local stamp_len=(#data-25) local stamp="" @@ -2077,9 +2080,9 @@ function check4LegicCash(data) stamp=stamp..data[i].." " end if (data[7]=="01") then - if (("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12))) == data[13]..data[14]) then - if (("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20))) == data[21]..data[22]) then - if (("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29))) == data[30]..data[31]) then + if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 0, 12), uid)) == data[13]..data[14]) then + if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 15, 20), uid)) == data[21]..data[22]) then + if (("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 23, 29), uid)) == data[30]..data[31]) then io.write(accyan.."Legic-Cash Segment detected "..acoff) return true end @@ -2156,7 +2159,7 @@ end --- -- repair / fix crc's of a 'Legic-Cash-Segment' -function fixLegicCash(data) +function fixLegicCash(data, uid) if(#data==32 and data[7]=="01") then local crc1, crc2, crc3 -- set shadow-balance equal to balance @@ -2168,9 +2171,9 @@ function fixLegicCash(data) data[27]=data[19] data[28]=data[20] -- calculate all crc's - crc1=("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12))) - crc2=("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20))) - crc3=("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29))) + crc1=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 0, 12), uid)) + crc2=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 15, 20), uid)) + crc3=("%04x"):format(utils.Crc16Legic(dumpTable(data, "", 23, 29), uid)) -- set crc's data[13]=string.sub(crc1, 1, 2) data[14]=string.sub(crc1, 3, 4) @@ -2413,7 +2416,7 @@ function modifyMode() for i=0, #inTAG.SEG do if(check43rdPartyCash1(uid, inTAG.SEG[i].data)) then io.write(accyan.."in Segment index: "..inTAG.SEG[i].index ..acoff.. "\n") - elseif(check4LegicCash(inTAG.SEG[i].data)) then + elseif(check4LegicCash(inTAG.SEG[i].data, uid)) then io.write(accyan.."in Segment index: "..inTAG.SEG[i].index..acoff.."\n") lc=true; lci=inTAG.SEG[i].index; @@ -2520,7 +2523,8 @@ function modifyMode() if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10) else sel=selectSegment(inTAG) end if (istable(inTAG.SEG[sel])) then - inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data) + local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 + inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data, uid) end end, --- @@ -2587,13 +2591,15 @@ function modifyMode() else x = selectSegment(inTAG) end - inTAG.SEG[x].data=fixLegicCash(inTAG.SEG[x].data) + local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 + inTAG.SEG[x].data=fixLegicCash(inTAG.SEG[x].data, uid) end, --- - -- edit legic-cash values fixLegicCash(data) + -- edit legic-cash values fixLegicCash(data, uid) ["elc"] = function(x) x=autoSelectSegment(inTAG, "legiccash") - inTAG.SEG[x].data=editLegicCash(inTAG.SEG[x].data) + local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 + inTAG.SEG[x].data=editLegicCash(inTAG.SEG[x].data, uid) end, --- -- dump legic-cash human-readable diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 7207e50f9..fe0ee46b0 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -70,7 +70,7 @@ static uint8_t *gs_mfuc_key = NULL; uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) { if (n < 3) return 2; - if (isResponse && (n < 6)) return 2; + if (isResponse && (n == 5)) return 2; if (d[1] == 0x50 && d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT && d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 3dee09d3b..6aac4677c 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -207,7 +207,7 @@ static char GetFormatFromSector(uint8_t sectors) { } } -static bool mfc_value(const uint8_t *d, int32_t *val) { +bool mfc_value(const uint8_t *d, int32_t *val) { // values int32_t a = (int32_t)MemLeToUint4byte(d); uint32_t a_inv = MemLeToUint4byte(d + 4); @@ -225,7 +225,7 @@ static bool mfc_value(const uint8_t *d, int32_t *val) { return val_checks; } -static void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { +void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { if (blockno == 0) { PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); } else if (mfIsSectorTrailer(blockno)) { @@ -389,7 +389,7 @@ static void mf_print_values(uint16_t n, uint8_t *d) { } */ -static void mf_print_sector_hdr(uint8_t sector) { +void mf_print_sector_hdr(uint8_t sector) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, " # | sector " _GREEN_("%02d") " / " _GREEN_("0x%02X") " | ascii", sector, sector); PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); diff --git a/client/src/cmdhfmf.h b/client/src/cmdhfmf.h index 5c21c7fb3..4e92bca70 100644 --- a/client/src/cmdhfmf.h +++ b/client/src/cmdhfmf.h @@ -34,6 +34,11 @@ void showSectorTable(sector_t *k_sector, size_t k_sectors_cnt); void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose); void printKeyTable(size_t sectorscnt, sector_t *e_sector); void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector); +// void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector, bool singel_sector); + +bool mfc_value(const uint8_t *d, int32_t *val); +void mf_print_sector_hdr(uint8_t sector); +void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose); int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len); #endif diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 4f956d3af..9434d88ed 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -33,6 +33,7 @@ #include "fileutils.h" #include "protocols.h" #include "crypto/libpcrypto.h" +#include "cmdhfmf.h" // printblock, header static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; @@ -172,7 +173,7 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature const ecdsa_publickey_t nxp_plus_public_keys[] = { {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}, {"MIFARE Plus Ev_x", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"}, - {"MIFARE Plus Trojka", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"} + {"MIFARE Plus Troika", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"} }; uint8_t i; @@ -766,25 +767,25 @@ static int CmdHFMFPRdbl(const char *Cmd) { return PM3_ESOFT; } + uint8_t sector = mfSectorNum(blockn); + mf_print_sector_hdr(sector); + int indx = blockn; for (int i = 0; i < blocksCount; i++) { - PrintAndLogEx(INFO, "data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16)); + mf_print_block_one(indx, data + 1 + (i * MFBLOCK_SIZE), verbose); indx++; - if (mfIsSectorTrailer(indx) && i != blocksCount - 1) { - PrintAndLogEx(INFO, "data[%03d]: ------------------- trailer -------------------", indx); - indx++; + } + + if (memcmp(&data[(blocksCount * 16) + 1], mac, 8)) { + PrintAndLogEx(WARNING, "WARNING: mac not equal..."); + PrintAndLogEx(WARNING, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + (blocksCount * MFBLOCK_SIZE)], 8)); + PrintAndLogEx(WARNING, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac, sizeof(mac))); + } else { + if (verbose) { + PrintAndLogEx(INFO, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + (blocksCount * MFBLOCK_SIZE)], 8)); } } - - if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) { - PrintAndLogEx(WARNING, "WARNING: mac not equal..."); - PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8)); - PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); - } else { - if (verbose) - PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8)); - } - + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -849,8 +850,12 @@ static int CmdHFMFPRdsc(const char *Cmd) { uint8_t data[250] = {0}; int datalen = 0; uint8_t mac[8] = {0}; - for (int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) { - res = MFPReadBlock(&mf4session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); + + mf_print_sector_hdr(sectorNum); + + for (int blockno = mfFirstBlockOfSector(sectorNum); blockno < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); blockno++) { + + res = MFPReadBlock(&mf4session, plain, blockno & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); if (res) { PrintAndLogEx(ERR, "Read error: %d", res); DropField(); @@ -862,25 +867,27 @@ static int CmdHFMFPRdsc(const char *Cmd) { DropField(); return PM3_ESOFT; } - if (datalen != 1 + 16 + 8 + 2) { + + if (datalen != 1 + MFBLOCK_SIZE + 8 + 2) { PrintAndLogEx(ERR, "Error return length:%d", datalen); DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16)); + mf_print_block_one(blockno, data + 1, verbose); if (memcmp(&data[1 + 16], mac, 8)) { - PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n); - PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8)); - PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); + PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", blockno); + PrintAndLogEx(WARNING, "MAC card... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + MFBLOCK_SIZE], 8)); + PrintAndLogEx(WARNING, "MAC reader... " _YELLOW_("%s"), sprint_hex_inrow(mac, sizeof(mac))); } else { - if (verbose) - PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8)); + if (verbose) { + PrintAndLogEx(INFO, "MAC... " _YELLOW_("%s"), sprint_hex_inrow(&data[1 + MFBLOCK_SIZE], 8)); + } } } + PrintAndLogEx(NORMAL, ""); DropField(); - return PM3_SUCCESS; } @@ -993,7 +1000,7 @@ static int CmdHFMFPWrbl(const char *Cmd) { #define AES_KEY_LEN 16 #define MAX_KEYS_LIST_LEN 1024 -static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, +static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], bool verbose) { int res; @@ -1097,16 +1104,12 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3 } static int CmdHFMFPChk(const char *Cmd) { - int res; - uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; - uint32_t keyListLen = 0; - uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp chk", "Checks keys on MIFARE Plus card", "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" - "hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n" + "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n" "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" "hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00"); @@ -1133,6 +1136,10 @@ static int CmdHFMFPChk(const char *Cmd) { uint8_t startSector = arg_get_int_def(ctx, 3, 0); uint8_t endSector = arg_get_int_def(ctx, 4, 0); + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; + uint32_t keyListLen = 0; + uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; + uint8_t vkey[16] = {0}; int vkeylen = 0; CLIGetHexWithReturn(ctx, 5, vkey, &vkeylen); @@ -1201,10 +1208,10 @@ static int CmdHFMFPChk(const char *Cmd) { uint8_t startKeyAB = 0; uint8_t endKeyAB = 1; - if (keyA && !keyB) + if (keyA && (keyB == false)) endKeyAB = 0; - if (!keyA && keyB) + if ((keyA == false) && keyB) startKeyAB = 1; if (endSector < startSector) @@ -1212,8 +1219,9 @@ static int CmdHFMFPChk(const char *Cmd) { // 1-byte pattern search mode if (pattern1b) { - for (int i = 0; i < 0x100; i++) + for (int i = 0; i < 0x100; i++) { memset(keyList[i], i, 16); + } keyListLen = 0x100; } @@ -1222,6 +1230,8 @@ static int CmdHFMFPChk(const char *Cmd) { if (pattern2b) Fill2bPattern(keyList, &keyListLen, &startPattern); + int res = PM3_SUCCESS; + // dictionary mode size_t endFilePosition = 0; if (dict_filenamelen) { @@ -1236,8 +1246,9 @@ static int CmdHFMFPChk(const char *Cmd) { if (keyListLen == 0) { for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { - if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) + if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) { break; + } keyListLen++; } @@ -1250,21 +1261,26 @@ static int CmdHFMFPChk(const char *Cmd) { PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " keys", keyListLen); } - if (verbose == false) + if (verbose == false) { PrintAndLogEx(INFO, "Search keys"); + } while (true) { - res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); - if (res == PM3_EOPABORTED) + res = plus_key_check(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); + if (res == PM3_EOPABORTED) { break; + } + if (pattern2b && startPattern < 0x10000) { - if (verbose == false) + if (verbose == false) { PrintAndLogEx(NORMAL, "p" NOLF); + } keyListLen = 0; Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } + if (dict_filenamelen && endFilePosition) { if (verbose == false) PrintAndLogEx(NORMAL, "d" NOLF); @@ -1274,6 +1290,7 @@ static int CmdHFMFPChk(const char *Cmd) { if (res == PM3_SUCCESS && endFilePosition) { keyListLen = keycnt; } + continue; } break; @@ -1282,26 +1299,38 @@ static int CmdHFMFPChk(const char *Cmd) { PrintAndLogEx(NORMAL, ""); // print result + char strA[46 + 1] = {0}; + char strB[46 + 1] = {0}; + bool printedHeader = false; - for (uint8_t sector = startSector; sector <= endSector; sector++) { - if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) { - if (!printedHeader) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------+--------------------------------+---------------------------------"); - PrintAndLogEx(INFO, "|sector| key A | key B |"); - PrintAndLogEx(INFO, "|------+--------------------------------+--------------------------------|"); - printedHeader = true; - } - PrintAndLogEx(INFO, "| %02d |%32s|%32s|", - sector, - (foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN), - (foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN)); + for (uint8_t s = startSector; s <= endSector; s++) { + if (printedHeader == false) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); + PrintAndLogEx(INFO, " Sec | key A | key B"); + PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); + printedHeader = true; } + + if (foundKeys[0][s][0]) { + snprintf(strA, sizeof(strA), _GREEN_("%s"), sprint_hex_inrow(&foundKeys[0][s][1], AES_KEY_LEN)); + } else { + snprintf(strA, sizeof(strA), _RED_("%s"), "--------------------------------"); + } + + if (foundKeys[1][s][0]) { + snprintf(strB, sizeof(strB), _GREEN_("%s"), sprint_hex_inrow(&foundKeys[1][s][1], AES_KEY_LEN)); + } else { + snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------"); + } + + PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB); } - if (!printedHeader) + + if (printedHeader == false) PrintAndLogEx(INFO, "No keys found("); else - PrintAndLogEx(INFO, "'------+--------------------------------+--------------------------------'\n"); + PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n"); // save keys to json if ((jsonnamelen > 0) && printedHeader) { @@ -1581,7 +1610,7 @@ int CmdHFMFPNDEFRead(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - if (!datalen) { + if (datalen == 0) { PrintAndLogEx(ERR, "no NDEF data"); return PM3_SUCCESS; } @@ -1595,8 +1624,20 @@ int CmdHFMFPNDEFRead(const char *Cmd) { if (fnlen != 0) { saveFile(filename, ".bin", data, datalen); } - NDEFDecodeAndPrint(data, datalen, verbose); - PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -vv`") " for more details"); + + res = NDEFDecodeAndPrint(data, datalen, verbose); + if (res != PM3_SUCCESS) { + PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); + res = NDEFRecordsDecodeAndPrint(data, datalen, verbose); + } + + if (verbose == false) { + PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details"); + } else { + if (verbose2 == false) { + PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -vv`") " for more details"); + } + } return PM3_SUCCESS; } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index f720d8599..e17032507 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1305,10 +1305,10 @@ typedef struct { } mfu_otp_identify_t; static mfu_otp_identify_t mfu_otp_ident_table[] = { - { "SALTO", 12, 4, "534C544F", ul_c_otpgenA, NULL }, -// { "SAFLOK", 12, 4, NULL, ul_c_otpgenB, NULL }, -// { "VINGCARD", 12, 4, NULL, ul_c_otpgenC, NULL }, -// { "DORMA KABA", 12, 4, NULL, ul_c_otpgenD, NULL }, + { "SALTO tag", 12, 4, "534C544F", ul_c_otpgenA, NULL }, +// { "SAFLOK tag", 12, 4, NULL, ul_c_otpgenB, NULL }, +// { "VINGCARD tag", 12, 4, NULL, ul_c_otpgenC, NULL }, +// { "DORMA KABA tag", 12, 4, NULL, ul_c_otpgenD, NULL }, { NULL, 0, 0, NULL, NULL, NULL } }; @@ -1391,6 +1391,18 @@ static mfu_identify_t mfu_ident_table[] = { "hf mfu dump -k %08x" }, */ + { + "Philips Toothbrush", "0004040201010F03", + 16, 20, "0310D1010C55027068696C6970732E636F6DFE00", + ul_ev1_pwdgen_def, ul_ev1_packgen_def, + "hf mfu pwdgen -r" + }, + { + "Philips Toothbrush", "0004040201010F03", + 16, 36, "0320D1011C55027068696C6970732E636F6D2F6E6663627275736868656164746170FE00", + ul_ev1_pwdgen_def, ul_ev1_packgen_def, + "hf mfu pwdgen -r" + }, {NULL, NULL, 0, 0, NULL, NULL, NULL, NULL} }; @@ -1412,7 +1424,7 @@ static mfu_identify_t *mfu_match_fingerprint(uint8_t *version, uint8_t *data) { uint8_t mtmp[40] = {0}; param_gethex_to_eol(mfu_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml); - bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0); + bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0); if (m2) { PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_ident_table[i].desc); return &mfu_ident_table[i]; @@ -1815,6 +1827,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) { else locked = true; + mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len); + if ((tagtype & MAGIC)) { //just read key uint8_t ulc_deskey[16] = {0x00}; @@ -3581,6 +3595,8 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { if (selftest) return generator_selftest(); + uint8_t philips_mfg[10] = {0}; + if (use_tag) { // read uid from tag int res = ul_read_uid(uid); @@ -3588,6 +3604,19 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { return res; } + iso14a_card_select_t card; + if (ul_select(&card)) { + // Philips toothbrush needs page 0x21-0x23 + uint8_t data[16] = {0x00}; + int status = ul_read(0x21, data, sizeof(data)); + if (status == -1) { + PrintAndLogEx(DEBUG, "Error: tag didn't answer to READ"); + } else if (status == 16) { + memcpy(philips_mfg, data + 2, sizeof(philips_mfg)); + } + DropField(); + } + } else { if (u_len != 7) { PrintAndLogEx(WARNING, "Key must be 7 hex bytes"); @@ -3595,24 +3624,28 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { } } - PrintAndLogEx(INFO, "------------------.---------------"); + PrintAndLogEx(INFO, "------------------.------------------"); PrintAndLogEx(INFO, " Using UID 4b: " _YELLOW_("%s"), sprint_hex(uid, 4)); PrintAndLogEx(INFO, " Using UID 7b: " _YELLOW_("%s"), sprint_hex(uid, 7)); - PrintAndLogEx(INFO, "----------------------------------"); - PrintAndLogEx(INFO, " algo | pwd | pack"); - PrintAndLogEx(INFO, "-----------------+----------+-----"); - PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid)); - PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid)); - PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid)); - PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid)); - PrintAndLogEx(INFO, " Xiaomi purifier | %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid)); - PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid)); - PrintAndLogEx(INFO, "-----------------+----------+-----"); + PrintAndLogEx(INFO, "-------------------------------------"); + PrintAndLogEx(INFO, " algo | pwd | pack"); + PrintAndLogEx(INFO, "--------------------+----------+-----"); + PrintAndLogEx(INFO, " Transport EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid)); + PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid)); + PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid)); + PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid)); + PrintAndLogEx(INFO, " Xiaomi purifier | %08X | %04X", ul_ev1_pwdgenE(uid), ul_ev1_packgenE(uid)); + PrintAndLogEx(INFO, " NTAG tools | %08X | %04X", ul_ev1_pwdgenF(uid), ul_ev1_packgen_def(uid)); + if (philips_mfg[0] != 0) { + PrintAndLogEx(INFO, " Philips Toothbrush | %08X | %04X", ul_ev1_pwdgenG(uid, philips_mfg), ul_ev1_packgenG(uid, philips_mfg)); + } + PrintAndLogEx(INFO, "--------------------+----------+-----"); PrintAndLogEx(INFO, " Vingcard algo"); PrintAndLogEx(INFO, " Saflok algo"); PrintAndLogEx(INFO, " SALTO algo"); PrintAndLogEx(INFO, " Dorma Kaba algo"); - PrintAndLogEx(INFO, "----------------------------------"); + PrintAndLogEx(INFO, " STiD algo"); + PrintAndLogEx(INFO, "-------------------------------------"); return PM3_SUCCESS; } diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index d3096307a..c2e750623 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -570,8 +570,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr //1 CRC-command, CRC ok //2 Not crc-command - //--- Draw the data column - char line[18][160] = {{0}}; + // Draw the data column + #define TRACE_MAX_LINES 36 + // number of hex bytes to be printed per row (16 data + 2 crc) + #define TRACE_MAX_HEX_BYTES 18 + + char line[TRACE_MAX_LINES][160] = {{0}}; if (data_len == 0) { if (protocol == ICLASS && duration == 2048) { @@ -582,9 +586,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr snprintf(line[0], sizeof(line[0]), ""); } } + uint8_t partialbytebuff = 0; uint8_t offset = 0; - for (int j = 0; j < data_len && j / 18 < 18; j++) { + for (int j = 0; j < data_len && (j / TRACE_MAX_HEX_BYTES) < TRACE_MAX_HEX_BYTES; j++) { uint8_t parityBits = parityBytes[j >> 3]; if (protocol != LEGIC && protocol != ISO_14443B @@ -602,11 +607,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr && (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) { snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x! ", frame[j]); + } else if (protocol == ICLASS && hdr->isResponse == false) { + uint8_t parity = 0; for (int i = 0; i < 6; i++) { parity ^= ((frame[0] >> i) & 1); } + if (parity == ((frame[0] >> 7) & 1)) { snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x ", frame[j]); } else { @@ -631,10 +639,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr } - - uint8_t crc_format_string_offset = 0; if (markCRCBytes && data_len > 2) { - //CRC-command + // CRC-command if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) { // Note that UID REQUEST response has no CRC, but we don't know // if the response we see is a UID @@ -647,36 +653,42 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (crcStatus == 0 || crcStatus == 1) { - char *pos1 = line[(data_len - 2) / 18]; - pos1 += (((data_len - 2) % 18) * 4) - 1; + char *pos1 = line[(data_len - 2) / TRACE_MAX_HEX_BYTES]; + pos1 += (((data_len - 2) % TRACE_MAX_HEX_BYTES) * 4) - 1; (*(pos1 + 6 + 1)) = '\0'; char *cb_str = str_dup(pos1 + 1); - if (hdr->isResponse) { - if (g_session.supports_colors) { - if (crcStatus == 0) { - snprintf(pos1, 24, " " _RED_("%s") " ", cb_str); - } else { - snprintf(pos1, 24, " " _GREEN_("%s") " ", cb_str); - } - crc_format_string_offset = 9; + if (g_session.supports_colors) { + if (crcStatus == 0) { + snprintf(pos1, 24, AEND " " _RED_("%s"), cb_str); } else { - snprintf(pos1, 9, "[%s]", cb_str); + snprintf(pos1, 24, AEND " " _GREEN_("%s"), cb_str); } } else { + snprintf(pos1, 9, "[%s]", cb_str); + } + + // odd case of second crc byte is alone in a new line + if (strlen(cb_str) < 5) { + + free(cb_str); + + pos1 = line[((data_len - 2) / TRACE_MAX_HEX_BYTES) + 1]; + cb_str = str_dup(pos1); + if (g_session.supports_colors) { if (crcStatus == 0) { - snprintf(pos1, 24, AEND " " _RED_("%s") " ", cb_str); + snprintf(pos1, 24, _RED_("%s"), cb_str); } else { - snprintf(pos1, 24, AEND " " _GREEN_("%s") " ", cb_str); + snprintf(pos1, 24, _GREEN_("%s"), cb_str); } - crc_format_string_offset = 13; } else { snprintf(pos1, 9, "[%s]", cb_str); } } + free(cb_str); } } @@ -688,8 +700,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr // mark short bytes (less than 8 Bit + Parity) if (protocol == ISO_14443A || - protocol == PROTO_MIFARE || - protocol == THINFILM) { + protocol == PROTO_MIFARE || + protocol == THINFILM) { // approximated with 128 * (9 * data_len); uint16_t bitime = 1056 + 32; @@ -791,8 +803,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr } } - int num_lines = MIN((data_len - 1) / 18 + 1, 18); + int str_padder = 72; + int num_lines = MIN((data_len - 1) / TRACE_MAX_HEX_BYTES + 1, TRACE_MAX_HEX_BYTES); + for (int j = 0; j < num_lines ; j++) { + + bool last_line = (j == num_lines - 1); + str_padder = 72; + if (j == 0) { uint32_t time1 = hdr->timestamp - first_hdr->timestamp; @@ -802,25 +820,30 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr time2 = duration; } + // ansi codes addes extra chars that needs to be taken in consideration. + if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) { + str_padder = 85; + } + if (hdr->isResponse) { // tag row if (use_us) { PrintAndLogEx(NORMAL, " %10.1f | %10.1f | Tag |%-*s | %s| %s", (float)time1 / 13.56, (float)time2 / 13.56, - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + (last_line) ? crc : " ", + (last_line) ? explanation : "" ); } else { PrintAndLogEx(NORMAL, " %10u | %10u | Tag |%-*s | %s| %s", time1, time2, - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + (last_line) ? crc : " ", + (last_line) ? explanation : "" ); } } else { @@ -830,41 +853,51 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr _YELLOW_(" %10.1f") " | " _YELLOW_("%10.1f") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"), (float)time1 / 13.56, (float)time2 / 13.56, - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + (last_line) ? crc : " ", + (last_line) ? explanation : "" ); } else { PrintAndLogEx(NORMAL, _YELLOW_(" %10u") " | " _YELLOW_("%10u") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"), time1, time2, - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + (last_line) ? crc : " ", + (last_line) ? explanation : "" ); } - } } else { + + + if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) { + str_padder = 85; + // odd case of multiline, and last single byte on empty row has been colorised... + if (strlen(line[j]) < 14) { + str_padder = 81; + } + } + if (hdr->isResponse) { PrintAndLogEx(NORMAL, " | | |%-*s | %s| %s", - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + last_line ? crc : " ", + last_line ? explanation : "" ); } else { PrintAndLogEx(NORMAL, " | | |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"), - 72 + crc_format_string_offset, + str_padder, line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : "" + last_line ? crc : " ", + last_line ? explanation : "" ); } + } } @@ -875,8 +908,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr memset(explanation, 0x00, sizeof(explanation)); annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse); uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen); + + //iceman: colorise crc bytes here will need a refactor of code from above. PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s", - 72 + crc_format_string_offset, + str_padder, sprint_hex_inrow_spaces(mfData, mfDataLen, 2), (crcc == 0 ? _RED_(" !! ") : (crcc == 1 ? _GREEN_(" ok ") : " ")), explanation); diff --git a/client/src/nfc/ndef.c b/client/src/nfc/ndef.c index 09ff31945..40cfe7113 100644 --- a/client/src/nfc/ndef.c +++ b/client/src/nfc/ndef.c @@ -1075,10 +1075,11 @@ static int ndefRecordDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen, b return res; ndefPrintHeader(&NDEFHeader, verbose); - PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, _CYAN_("Payload info")); if (verbose) { + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, _CYAN_("Payload info")); + if (NDEFHeader.TypeLen) { PrintAndLogEx(INFO, "Type data"); print_buffer(NDEFHeader.Type, NDEFHeader.TypeLen, 1); @@ -1229,7 +1230,9 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) { break; } case 0xFE: { - PrintAndLogEx(SUCCESS, "NDEF Terminator detected"); + if (verbose) { + PrintAndLogEx(SUCCESS, "NDEF Terminator detected"); + } return PM3_SUCCESS; } default: { diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 378b9f0dc..162bc7776 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -250,16 +250,13 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { if (g_session.incognito) { PrintAndLogEx(INFO, "No history will be recorded"); } else { - bool loaded_history = false; if (searchHomeFilePath(&g_session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) { g_session.history_path = NULL; - } else { - loaded_history = (pm3line_load_history(g_session.history_path) == PM3_SUCCESS); - } - if (loaded_history) { - pm3line_install_signals(); - } else { PrintAndLogEx(ERR, "No history will be recorded"); + } else { + if (pm3line_load_history(g_session.history_path) != PM3_SUCCESS) { + PrintAndLogEx(INFO, "No previous history could be loaded"); + } } } diff --git a/common/crc16.c b/common/crc16.c index f78fab5b4..d402977b9 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -42,10 +42,14 @@ void init_table(CrcType_t crctype) { case CRC_15693: case CRC_ICLASS: case CRC_CRYPTORF: + case CRC_KERMIT: generate_table(CRC16_POLY_CCITT, true); break; case CRC_FELICA: case CRC_XMODEM: + case CRC_CCITT: + case CRC_11784: + case CRC_PHILIPS: generate_table(CRC16_POLY_CCITT, false); break; case CRC_LEGIC: @@ -54,15 +58,6 @@ void init_table(CrcType_t crctype) { case CRC_LEGIC_16: generate_table(CRC16_POLY_LEGIC_16, true); break; - case CRC_CCITT: - generate_table(CRC16_POLY_CCITT, false); - break; - case CRC_KERMIT: - generate_table(CRC16_POLY_CCITT, true); - break; - case CRC_11784: - generate_table(CRC16_POLY_CCITT, false); - break; case CRC_NONE: crc_table_init = false; current_crc_type = CRC_NONE; @@ -210,6 +205,9 @@ void compute_crc(CrcType_t ct, const uint8_t *d, size_t n, uint8_t *first, uint8 case CRC_LEGIC_16: // TODO return; + case CRC_PHILIPS: + crc = crc16_philips(d, n); + break; case CRC_NONE: return; } @@ -244,6 +242,8 @@ uint16_t Crc16ex(CrcType_t ct, const uint8_t *d, size_t n) { case CRC_LEGIC_16: // TODO return 0; + case CRC_PHILIPS: + return crc16_philips(d, n); case CRC_NONE: default: break; @@ -290,6 +290,8 @@ bool check_crc(CrcType_t ct, const uint8_t *d, size_t n) { case CRC_LEGIC_16: // TODO return false; + case CRC_PHILIPS: + return (crc16_philips(d, n) == 0); case CRC_NONE: default: break; @@ -350,3 +352,6 @@ uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc) { return crc16_fast(d, n, initial, true, false); } +uint16_t crc16_philips(uint8_t const *d, size_t n) { + return crc16_fast(d, n, 0x49A3, false, false); +} \ No newline at end of file diff --git a/common/crc16.h b/common/crc16.h index d9631c43c..80758d95b 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -42,6 +42,7 @@ typedef enum { CRC_KERMIT, CRC_XMODEM, CRC_CRYPTORF, + CRC_PHILIPS, } CrcType_t; uint16_t update_crc16_ex(uint16_t crc, uint8_t c, uint16_t polynomial); @@ -78,6 +79,9 @@ uint16_t crc16_iclass(uint8_t const *d, size_t n); // ie: uidcrc = 0x78 then initial_value == 0x7878 uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc); +// Calculate CRC-16/ Philips. +uint16_t crc16_philips(uint8_t const *d, size_t n); + // table implementation void init_table(CrcType_t crctype); void reset_table(void); diff --git a/common/generator.c b/common/generator.c index 852ea2b61..7cf5498e1 100644 --- a/common/generator.c +++ b/common/generator.c @@ -195,6 +195,20 @@ uint32_t ul_ev1_pwdgenF(const uint8_t *uid) { return pwd; } +// Solution from @atc1441 +// https://gist.github.com/atc1441/41af75048e4c22af1f5f0d4c1d94bb56 +// Philips Sonicare toothbrush NFC head +uint32_t ul_ev1_pwdgenG(const uint8_t *uid, const uint8_t *mfg) { + + init_table(CRC_PHILIPS); + // UID + uint32_t crc1 = crc16_philips(uid, 7); + // MFG string + uint32_t crc2 = crc16_fast(mfg, 10, crc1, false, false); + + return (BSWAP_16(crc2) << 16 | BSWAP_16(crc1)); +} + // pack generation for algo 1-3 uint16_t ul_ev1_packgenA(const uint8_t *uid) { uint16_t pack = (uid[0] ^ uid[1] ^ uid[2]) << 8 | (uid[2] ^ 8); @@ -224,13 +238,26 @@ uint16_t ul_ev1_packgenD(const uint8_t *uid) { p ^= 0x5555; return BSWAP_16(p & 0xFFFF); } - uint16_t ul_ev1_packgenE(const uint8_t *uid) { uint32_t pwd = ul_ev1_pwdgenE(uid); return (0xAD << 8 | ((pwd >> 24) & 0xFF)); } +uint16_t ul_ev1_packgenG(const uint8_t *uid, const uint8_t *mfg) { + init_table(CRC_PHILIPS); + // UID + uint32_t crc1 = crc16_philips(uid, 7); + // MFG string + uint32_t crc2 = crc16_fast(mfg, 10, crc1, false, false); + // PWD + uint32_t pwd = (BSWAP_16(crc2) << 16 | BSWAP_16(crc1)); + + uint8_t pb[4]; + num_to_bytes(pwd, 4, pb); + return BSWAP_16(crc16_fast(pb, 4, crc2, false, false)); +} + // default shims uint32_t ul_ev1_pwdgen_def(const uint8_t *uid) { @@ -556,7 +583,7 @@ int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t * int generator_selftest(void) { #ifndef ON_DEVICE -#define NUM_OF_TEST 8 +#define NUM_OF_TEST 9 PrintAndLogEx(INFO, "PWD / KEY generator selftest"); PrintAndLogEx(INFO, "----------------------------"); @@ -606,18 +633,27 @@ int generator_selftest(void) { testresult++; PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid6, 7), pwd6, success ? "OK" : "->A9C4C3C0<--"); + uint8_t uid7[] = {0x04, 0x0D, 0x4B, 0x5A, 0xC5, 0x71, 0x81}; + uint8_t mfg[] = {0x32, 0x31, 0x30, 0x36, 0x32, 0x38, 0x20, 0x35, 0x32, 0x4D}; + uint32_t pwd7 = ul_ev1_pwdgenG(uid7, mfg); + success = (pwd7 == 0xFBCFACC1); + if (success) + testresult++; + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid7, 7), pwd7, success ? "OK" : "->FBCFACC1<--"); + + // uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44}; // uint64_t key1 = mfc_algo_a(uid5); // success = (key1 == 0xD1E2AA68E39A); // PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid5, 4), key1, success ? "OK" : "->D1E2AA68E39A<--"); - uint8_t uid7[] = {0x74, 0x57, 0xCA, 0xA9}; - uint64_t key7 = 0; - mfc_algo_sky_one(uid7, 15, 0, &key7); - success = (key7 == 0x82c7e64bc565); + uint8_t uid8[] = {0x74, 0x57, 0xCA, 0xA9}; + uint64_t key8 = 0; + mfc_algo_sky_one(uid8, 15, 0, &key8); + success = (key8 == 0x82c7e64bc565); if (success) testresult++; - PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid7, 4), key7, success ? "OK" : "->82C7E64BC565<--"); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid8, 4), key8, success ? "OK" : "->82C7E64BC565<--"); uint32_t lf_id = lf_t55xx_white_pwdgen(0x00000080); diff --git a/common/generator.h b/common/generator.h index 1008d01fa..ce2601f26 100644 --- a/common/generator.h +++ b/common/generator.h @@ -28,6 +28,7 @@ uint32_t ul_ev1_pwdgenC(const uint8_t *uid); uint32_t ul_ev1_pwdgenD(const uint8_t *uid); uint32_t ul_ev1_pwdgenE(const uint8_t *uid); uint32_t ul_ev1_pwdgenF(const uint8_t *uid); +uint32_t ul_ev1_pwdgenG(const uint8_t *uid, const uint8_t *mfg); uint16_t ul_ev1_packgen_def(const uint8_t *uid); uint16_t ul_ev1_packgenA(const uint8_t *uid); @@ -35,6 +36,7 @@ uint16_t ul_ev1_packgenB(const uint8_t *uid); uint16_t ul_ev1_packgenC(const uint8_t *uid); uint16_t ul_ev1_packgenD(const uint8_t *uid); uint16_t ul_ev1_packgenE(const uint8_t *uid); +uint16_t ul_ev1_packgenG(const uint8_t *uid, const uint8_t *mfg); uint32_t ul_c_otpgenA(const uint8_t *uid); diff --git a/pm3 b/pm3 index d59d10ea6..b011c8ed5 100755 --- a/pm3 +++ b/pm3 @@ -144,7 +144,8 @@ function get_pm3_list_Windows { DEV=${DEV/ */} #prevent soft bricking when using pm3-flash-all on an outdated bootloader if [ $(basename -- "$0") = "pm3-flash-all" ]; then - if [ ! $(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then + line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}'); + if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" exit 1 fi @@ -189,9 +190,11 @@ function get_pm3_list_WSL { DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p') # ttyS counterpart takes some more time to appear if [ -e "$DEV" ]; then + #prevent soft bricking when using pm3-flash-all on an outdated bootloader if [ $(basename -- "$0") = "pm3-flash-all" ]; then - if [ ! $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then + line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]'); + if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" exit 1 fi