From 72c5877a74d0859b8da12575470a54a3b0ab8128 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sun, 21 Feb 2016 17:05:53 -0500 Subject: [PATCH 01/20] some minor lf fixes from @iceman1001 --- armsrc/lfops.c | 4 ++-- client/cmddata.c | 17 +++++++++-------- client/cmdlf.c | 2 +- client/cmdlft55xx.c | 6 +++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 14b62673..c8924007 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -379,7 +379,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) AcquireTiType(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tiread to check"); + DbpString("Now use `lf ti read` to check"); } void SimulateTagLowFrequency(int period, int gap, int ledcontrol) @@ -1415,7 +1415,7 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { LED_D_ON(); // Write EM410x ID - uint32_t data[] = {0, id>>32, id & 0xFFFFFFFF}; + uint32_t data[] = {0, (uint32_t)(id>>32), (uint32_t)(id & 0xFFFFFFFF)}; clock = (card & 0xFF00) >> 8; clock = (clock == 0) ? 64 : clock; diff --git a/client/cmddata.c b/client/cmddata.c index c7fdc91e..f2d4d883 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -848,16 +848,18 @@ int CmdUndec(const char *Cmd) uint8_t factor = param_get8ex(Cmd, 0,2, 10); //We have memory, don't we? int swap[MAX_GRAPH_TRACE_LEN] = { 0 }; - uint32_t g_index = 0 ,s_index = 0; - while(g_index < GraphTraceLen && s_index < MAX_GRAPH_TRACE_LEN) + uint32_t g_index = 0, s_index = 0; + while(g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) { int count = 0; - for(count = 0; count < factor && s_index+count < MAX_GRAPH_TRACE_LEN; count ++) + for(count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) swap[s_index+count] = GraphBuffer[g_index]; - s_index+=count; + + s_index += count; + g_index++; } - memcpy(GraphBuffer,swap, s_index * sizeof(int)); + memcpy(GraphBuffer, swap, s_index * sizeof(int)); GraphTraceLen = s_index; RepaintGraphWindow(); return 0; @@ -2334,9 +2336,8 @@ int Cmdbin2hex(const char *Cmd) return 0; } -int usage_data_hex2bin(){ - - PrintAndLog("Usage: data bin2hex "); +int usage_data_hex2bin() { + PrintAndLog("Usage: data hex2bin "); PrintAndLog(" This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); return 0; diff --git a/client/cmdlf.c b/client/cmdlf.c index 93a1398d..9d23d97c 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -539,7 +539,7 @@ int CmdLFSetConfig(const char *Cmd) return usage_lf_config(); } //Bps is limited to 8, so fits in lower half of arg1 - if(bps >> 8) bps = 8; + if(bps >> 4) bps = 8; sample_config config = { decimation,bps,averaging,divisor,trigger_threshold diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 7d954353..9e4883c7 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -76,7 +76,7 @@ int usage_t55xx_read(){ return 0; } int usage_t55xx_write(){ - PrintAndLog("Usage: lf t55xx wr [b ] [d ] [p ] [1]"); + PrintAndLog("Usage: lf t55xx write [b ] [d ] [p ] [1]"); PrintAndLog("Options:"); PrintAndLog(" b - block number to write. Between 0-7"); PrintAndLog(" d - 4 bytes of data to write (8 hex characters)"); @@ -84,8 +84,8 @@ int usage_t55xx_write(){ PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wr b 3 d 11223344 - write 11223344 to block 3"); - PrintAndLog(" lf t55xx wr b 3 d 11223344 p feedbeef - write 11223344 to block 3 password feedbeef"); + PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); + PrintAndLog(" lf t55xx write b 3 d 11223344 p feedbeef - write 11223344 to block 3 password feedbeef"); PrintAndLog(""); return 0; } From 88e85bde41e6a5409cf3ca52536726740e54ed96 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 29 Feb 2016 17:05:02 -0500 Subject: [PATCH 02/20] refactor gProxII demod... add 0 spacer to ... ... parity functions (remove, add) make MAX_GRAPH_TRACE_LEN match with client side --- client/cmddata.c | 67 ++++++++++++++++++++++-------------------------- client/proxgui.h | 2 +- common/lfdemod.c | 24 +++++++++-------- 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index f2d4d883..2a2a0dc1 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -592,7 +592,7 @@ int Cmdaskbiphdemod(const char *Cmd) int CmdG_Prox_II_Demod(const char *Cmd) { if (!ASKbiphaseDemod(Cmd, FALSE)){ - if (g_debugMode) PrintAndLog("ASKbiphaseDemod failed 1st try"); + if (g_debugMode) PrintAndLog("Error gProxII: ASKbiphaseDemod failed 1st try"); return 0; } size_t size = DemodBufferLen; @@ -602,46 +602,32 @@ int CmdG_Prox_II_Demod(const char *Cmd) if (g_debugMode) PrintAndLog("Error gProxII_Demod"); return 0; } - //got a good demod - uint32_t ByteStream[65] = {0x00}; + //got a good demod of 96 bits + uint32_t ByteStream[8] = {0x00}; uint8_t xorKey=0; - uint8_t keyCnt=0; - uint8_t bitCnt=0; - uint8_t ByteCnt=0; - size_t startIdx = ans + 6; //start after preamble - for (size_t idx = 0; idx>2; uint32_t FC = 0; uint32_t Card = 0; + //get raw 96 bits to print uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans,32); uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer+ans+64, 32); @@ -649,13 +635,22 @@ int CmdG_Prox_II_Demod(const char *Cmd) if (fmtLen==36){ FC = ((ByteStream[3] & 0x7F)<<7) | (ByteStream[4]>>1); Card = ((ByteStream[4]&1)<<19) | (ByteStream[5]<<11) | (ByteStream[6]<<3) | (ByteStream[7]>>5); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d", fmtLen, FC, Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else if(fmtLen==26){ FC = ((ByteStream[3] & 0x7F)<<1) | (ByteStream[4]>>7); Card = ((ByteStream[4]&0x7F)<<9) | (ByteStream[5]<<1) | (ByteStream[6]>>7); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d",(unsigned int)fmtLen,FC,Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else { PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",(int)fmtLen); + PrintAndLog("Decoded Raw: %02x%02x%02x%02x%02x%02x%02x%02x", + ByteStream[0], + ByteStream[1], + ByteStream[2], + ByteStream[3], + ByteStream[4], + ByteStream[5], + ByteStream[6], + ByteStream[7]); } PrintAndLog("Raw: %08x%08x%08x", raw1,raw2,raw3); setDemodBuf(DemodBuffer+ans, 96, 0); diff --git a/client/proxgui.h b/client/proxgui.h index 6fcf4d0a..94b47acd 100644 --- a/client/proxgui.h +++ b/client/proxgui.h @@ -19,7 +19,7 @@ void MainGraphics(void); void InitGraphics(int argc, char **argv); void ExitGraphics(void); -#define MAX_GRAPH_TRACE_LEN (1024*128) +#define MAX_GRAPH_TRACE_LEN (40000*8) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; extern int GraphTraceLen; extern double CursorScaleFactor; diff --git a/common/lfdemod.c b/common/lfdemod.c index 7398f1b2..665bad89 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -68,7 +68,7 @@ uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType) // by marshmellow // takes a array of binary values, start position, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 for Always 1's; 3 for Always 0's), and binary Length (length to run) size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen) { uint32_t parityWd = 0; @@ -80,10 +80,11 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p } j--; // overwrite parity with next data // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - if (!BitStream[j]) return 0; - } else { - if (parityTest(parityWd, pLen, pType) == 0) return 0; + switch (pType) { + case 3: if (BitStream[j]==1) return 0; break; //should be 0 spacer bit + case 2: if (BitStream[j]==0) return 0; break; //should be 1 spacer bit + default: //test parity + if (parityTest(parityWd, pLen, pType) == 0) return 0; break; } bitCnt+=(pLen-1); parityWd = 0; @@ -95,7 +96,8 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p // by marshmellow // takes a array of binary values, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) +// Make sure *dest is long enough to store original sourceLen + #_of_parities_to_be_added size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType) { uint32_t parityWd = 0; @@ -106,10 +108,12 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p dest[j++] = (BitSource[word+bit]); } // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - dest[j++]=1; - } else { - dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + switch (pType) { + case 3: dest[j++]=0; break; // marker bit which should be a 0 + case 2: dest[j++]=1; break; // marker bit which should be a 1 + default: + dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + break; } bitCnt += pLen; parityWd = 0; From 39611e3d68fd067229797b9e18be57f3bbc9f3b2 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 29 Feb 2016 18:05:47 -0500 Subject: [PATCH 03/20] fix ask/Biphase sim bug --- armsrc/lfops.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c8924007..610781d2 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -642,6 +642,7 @@ static void biphaseSimBit(uint8_t c, int *n, uint8_t clock, uint8_t *phase) memset(dest+(*n), c ^ *phase, clock); *phase ^= 1; } + *n += clock; } // args clock, ask/man or askraw, invert, transmission separator @@ -659,7 +660,7 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) for (i=0; i Date: Mon, 29 Feb 2016 18:17:51 -0500 Subject: [PATCH 04/20] fix uint8 vs uint32 and use sprint_hex thanks @iceman1001 for the suggestion. --- client/cmddata.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 2a2a0dc1..801649ee 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -603,7 +603,7 @@ int CmdG_Prox_II_Demod(const char *Cmd) return 0; } //got a good demod of 96 bits - uint32_t ByteStream[8] = {0x00}; + uint8_t ByteStream[8] = {0x00}; uint8_t xorKey=0; size_t startIdx = ans + 6; //start after 6 bit preamble @@ -642,15 +642,7 @@ int CmdG_Prox_II_Demod(const char *Cmd) PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else { PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",(int)fmtLen); - PrintAndLog("Decoded Raw: %02x%02x%02x%02x%02x%02x%02x%02x", - ByteStream[0], - ByteStream[1], - ByteStream[2], - ByteStream[3], - ByteStream[4], - ByteStream[5], - ByteStream[6], - ByteStream[7]); + PrintAndLog("Decoded Raw: %s", sprint_hex(ByteStream, 8)); } PrintAndLog("Raw: %08x%08x%08x", raw1,raw2,raw3); setDemodBuf(DemodBuffer+ans, 96, 0); From 6923d3f14ff7c6439d708470f4da2edcc3eca854 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sat, 5 Mar 2016 23:45:28 -0500 Subject: [PATCH 05/20] Add @iceman1001 s presco and pyramid functions + plus comment some includes. fix indala error checking bugs cmddata.h previously relied on several headers being included prior to cmddata.h, now self contained. --- client/Makefile | 2 + client/cmddata.c | 49 +++++----- client/cmddata.h | 6 ++ client/cmdlf.c | 37 +++---- client/cmdlfpresco.c | 223 ++++++++++++++++++++++++++++++++++++++++++ client/cmdlfpresco.h | 30 ++++++ client/cmdlfpyramid.c | 185 +++++++++++++++++++++++++++++++++++ client/cmdlfpyramid.h | 30 ++++++ client/util.h | 5 +- common/lfdemod.c | 13 +++ common/lfdemod.h | 6 +- 11 files changed, 538 insertions(+), 48 deletions(-) create mode 100644 client/cmdlfpresco.c create mode 100644 client/cmdlfpresco.h create mode 100644 client/cmdlfpyramid.c create mode 100644 client/cmdlfpyramid.h diff --git a/client/Makefile b/client/Makefile index 0972f441..7f9c4c84 100644 --- a/client/Makefile +++ b/client/Makefile @@ -99,6 +99,8 @@ CMDSRCS = nonce2key/crapto1.c\ cmdlft55xx.c \ cmdlfpcf7931.c\ cmdlfviking.c\ + cmdlfpresco.c\ + cmdlfpyramid.c\ pm3_binlib.c\ scripting.c\ cmdscript.c\ diff --git a/client/cmddata.c b/client/cmddata.c index 801649ee..9854ccfa 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -8,23 +8,22 @@ // Data and Graph commands //----------------------------------------------------------------------------- -#include -#include -#include -#include -#include "proxmark3.h" -#include "data.h" -#include "ui.h" -#include "graph.h" -#include "cmdparser.h" +#include // also included in util.h +#include // also included in util.h +#include // for CmdNorm INT_MIN && INT_MAX +#include "data.h" // also included in util.h +#include "cmddata.h" #include "util.h" #include "cmdmain.h" -#include "cmddata.h" -#include "lfdemod.h" -#include "usb_cmd.h" -#include "crc.h" -#include "crc16.h" -#include "loclass/cipherutils.h" +#include "proxmark3.h" +#include "ui.h" // for show graph controls +#include "graph.h" // for graph data +#include "cmdparser.h"// already included in cmdmain.h +#include "usb_cmd.h" // already included in cmdmain.h and proxmark3.h +#include "lfdemod.h" // for demod code +#include "crc.h" // for pyramid checksum maxim +#include "crc16.h" // for FDXB demod checksum +#include "loclass/cipherutils.h" // for decimating samples in getsamples uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t g_debugMode=0; @@ -1265,7 +1264,7 @@ int CmdFSKdemodAWID(const char *Cmd) //get binary from fsk wave int idx = AWIDdemodFSK(BitStream, &size); if (idx<=0){ - if (g_debugMode==1){ + if (g_debugMode){ if (idx == -1) PrintAndLog("DEBUG: Error - not enough samples"); else if (idx == -2) @@ -1303,7 +1302,7 @@ int CmdFSKdemodAWID(const char *Cmd) size = removeParity(BitStream, idx+8, 4, 1, 88); if (size != 66){ - if (g_debugMode==1) PrintAndLog("DEBUG: Error - at parity check-tag size does not match AWID format"); + if (g_debugMode) PrintAndLog("DEBUG: Error - at parity check-tag size does not match AWID format"); return 0; } // ok valid card found! @@ -1363,7 +1362,7 @@ int CmdFSKdemodPyramid(const char *Cmd) //get binary from fsk wave int idx = PyramiddemodFSK(BitStream, &size); if (idx < 0){ - if (g_debugMode==1){ + if (g_debugMode){ if (idx == -5) PrintAndLog("DEBUG: Error - not enough samples"); else if (idx == -1) @@ -1419,7 +1418,7 @@ int CmdFSKdemodPyramid(const char *Cmd) size = removeParity(BitStream, idx+8, 8, 1, 120); if (size != 105){ - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("DEBUG: Error at parity check - tag size does not match Pyramid format, SIZE: %d, IDX: %d, hi3: %x",size, idx, rawHi3); return 0; } @@ -1642,21 +1641,21 @@ int CmdIndalaDecode(const char *Cmd) } if (!ans){ - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("Error1: %d",ans); return 0; } uint8_t invert=0; size_t size = DemodBufferLen; - size_t startIdx = indala26decode(DemodBuffer, &size, &invert); - if (startIdx < 1 || size > 224) { - if (g_debugMode==1) + int startIdx = indala26decode(DemodBuffer, &size, &invert); + if (startIdx < 0 || size > 224) { + if (g_debugMode) PrintAndLog("Error2: %d",ans); return -1; } - setDemodBuf(DemodBuffer, size, startIdx); + setDemodBuf(DemodBuffer, size, (size_t)startIdx); if (invert) - if (g_debugMode==1) + if (g_debugMode) PrintAndLog("Had to invert bits"); PrintAndLog("BitLen: %d",DemodBufferLen); diff --git a/client/cmddata.h b/client/cmddata.h index 20bdbd2b..9b9f2da9 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -11,6 +11,12 @@ #ifndef CMDDATA_H__ #define CMDDATA_H__ +#include //size_t +#include //uint_32+ +#include //bool + +#include "cmdparser.h" // for command_t + command_t * CmdDataCommands(); int CmdData(const char *Cmd); diff --git a/client/cmdlf.c b/client/cmdlf.c index 9d23d97c..22bceda4 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -13,24 +13,25 @@ #include #include #include "proxmark3.h" -#include "data.h" -#include "graph.h" -#include "ui.h" -#include "cmdparser.h" -#include "cmdmain.h" -#include "cmddata.h" -#include "util.h" #include "cmdlf.h" -#include "cmdlfhid.h" -#include "cmdlfawid.h" -#include "cmdlfti.h" -#include "cmdlfem4x.h" -#include "cmdlfhitag.h" -#include "cmdlft55xx.h" -#include "cmdlfpcf7931.h" -#include "cmdlfio.h" -#include "cmdlfviking.h" -#include "lfdemod.h" +#include "util.h" // for parsing cli command utils +#include "ui.h" // for show graph controls +#include "graph.h" // for graph data +#include "cmdparser.h" // for getting cli commands included in cmdmain.h +#include "cmdmain.h" // for sending cmds to device +#include "data.h" // for GetFromBigBuf +#include "cmddata.h" // for `lf search` +#include "cmdlfawid.h" // for awid menu +#include "cmdlfem4x.h" // for em4x menu +#include "cmdlfhid.h" // for hid menu +#include "cmdlfhitag.h" // for hitag menu +#include "cmdlfio.h" // for ioprox menu +#include "cmdlft55xx.h" // for t55xx menu +#include "cmdlfti.h" // for ti menu +#include "cmdlfpresco.h" // for presco menu +#include "cmdlfpcf7931.h"// for pcf7931 menu +#include "cmdlfpyramid.h"// for pyramid menu +#include "cmdlfviking.h" // for viking menu static int CmdHelp(const char *Cmd); @@ -1220,7 +1221,9 @@ static command_t CommandTable[] = {"hid", CmdLFHID, 1, "{ HID RFIDs... }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"}, {"io", CmdLFIO, 1, "{ ioProx tags... }"}, + {"presco", CmdLFPresco, 1, "{ Presco RFIDs... }"}, {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 RFIDs... }"}, + {"pyramid", CmdLFPyramid, 1, "{ Farpointe/Pyramid RFIDs... }"}, {"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"}, {"ti", CmdLFTI, 1, "{ TI RFIDs... }"}, {"viking", CmdLFViking, 1, "{ Viking tags... }"}, diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c new file mode 100644 index 00000000..20b42bc1 --- /dev/null +++ b/client/cmdlfpresco.c @@ -0,0 +1,223 @@ +//----------------------------------------------------------------------------- +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// Low frequency Presco tag commands +//----------------------------------------------------------------------------- +#include +#include +#include "cmdlfpresco.h" +static int CmdHelp(const char *Cmd); + +int usage_lf_presco_clone(void){ + PrintAndLog("clone a Presco tag to a T55x7 tag."); + PrintAndLog("Usage: lf presco clone "); + PrintAndLog("Options :"); + PrintAndLog(" : 9 digit presco card number"); + //PrintAndLog(" : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLog(""); + PrintAndLog("Sample : lf presco clone 123456789"); + return 0; +} + +int usage_lf_presco_sim(void) { + PrintAndLog("Enables simulation of presco card with specified card number."); + PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLog("Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); + PrintAndLog(""); + PrintAndLog("Usage: lf presco sim "); + PrintAndLog("Options :"); + PrintAndLog(" : 9 digit presco card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf presco sim 123456789"); + return 0; +} + +// calc checksum +int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode) { + + uint8_t val = 0; + for (int index =0; index < strlen(id); ++index) { + + // Get value from number string. + if ( id[index] == '*' ) val = 10; + if ( id[index] == '#') val = 11; + if ( id[index] >= 0x30 && id[index] <= 0x39 ) + val = id[index] - 0x30; + + *sitecode += val; + + // last digit is only added, not multipled. + if ( index < strlen(id)-1 ) + *sitecode *= 12; + } + *usercode = *sitecode % 65536; + *sitecode /= 16777216; + return 0; +} + +int GetPrescoBits(uint32_t sitecode, uint32_t usercode, uint8_t *prescoBits) { + uint8_t pre[66]; + memset(pre, 0, sizeof(pre)); + prescoBits[7]=1; + num_to_bytebits(26, 8, pre); + + uint8_t wiegand[24]; + num_to_bytebits(sitecode, 8, wiegand); + num_to_bytebits(usercode, 16, wiegand+8); + + wiegand_add_parity(pre+8, wiegand, 24); + size_t bitLen = addParity(pre, prescoBits+8, 66, 4, 1); + + if (bitLen != 88) return 0; + return 1; +} +//see ASKDemod for what args are accepted +int CmdPrescoDemod(const char *Cmd) { + if (!ASKDemod(Cmd, false, false, 1)) { + if (g_debugMode) PrintAndLog("ASKDemod failed"); + return 0; + } + size_t size = DemodBufferLen; + //call lfdemod.c demod for Viking + int ans = PrescoDemod(DemodBuffer, &size); + if (ans < 0) { + if (g_debugMode) PrintAndLog("Error Presco_Demod %d", ans); + return 0; + } + //got a good demod + uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans, 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); + uint32_t cardid = bytebits_to_byte(DemodBuffer+ans+24, 32); + PrintAndLog("Presco Tag Found: Card ID %08X", cardid); + PrintAndLog("Raw: %08X%08X", raw1,raw2); + setDemodBuf(DemodBuffer+ans, 64, 0); + + // uint32_t sitecode = 0, usercode = 0; + // GetWiegandFromPresco(id, &sitecode, &usercode); + // PrintAndLog8("SiteCode %d | UserCode %d", sitecode, usercode); + + return 1; +} + +//see ASKDemod for what args are accepted +int CmdPrescoRead(const char *Cmd) { + // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 + + // read lf silently + CmdLFRead("s"); + // get samples silently + getSamples("30000",false); + // demod and output Presco ID + return CmdPrescoDemod(Cmd); +} + +int CmdPrescoClone(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_presco_clone(); + + uint32_t sitecode=0, usercode=0; + uint8_t bits[96]; + uint8_t *bs = bits; + memset(bs,0,sizeof(bits)); + uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4<> 32),(uint32_t) (rawID & 0xFFFFFFFF)); + + // UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; + // num_to_bytebits(rawID, size, c.d.asBytes); + // clearCommandBuffer(); + // SendCommand(&c); + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"read", CmdPrescoRead, 0, "Attempt to read and Extract tag data"}, + {"clone", CmdPrescoClone, 0, "<8 digit ID number> clone presco tag"}, +// {"sim", CmdPrescoSim, 0, "<8 digit ID number> simulate presco tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFPresco(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfpresco.h b/client/cmdlfpresco.h new file mode 100644 index 00000000..f9cfbd95 --- /dev/null +++ b/client/cmdlfpresco.h @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// Low frequency T55xx commands +//----------------------------------------------------------------------------- +#ifndef CMDLFPRESCO_H__ +#define CMDLFPRESCO_H__ +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +int CmdLFPresco(const char *Cmd); +int CmdPrescoClone(const char *Cmd); +//int CmdPrescoSim(const char *Cmd); + +int usage_lf_presco_clone(void); +int usage_lf_presco_sim(void); + +int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode); +#endif + diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c new file mode 100644 index 00000000..990dccbb --- /dev/null +++ b/client/cmdlfpyramid.c @@ -0,0 +1,185 @@ +//----------------------------------------------------------------------------- +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// Low frequency Farpoint / Pyramid tag commands +//----------------------------------------------------------------------------- +#include +#include +#include "cmdlfpyramid.h" +static int CmdHelp(const char *Cmd); + +int usage_lf_pyramid_clone(void){ + PrintAndLog("clone a Farpointe/Pyramid tag to a T55x7 tag."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf pyramid clone "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf pyramid clone 123 11223"); + return 0; +} + +int usage_lf_pyramid_sim(void) { + PrintAndLog("Enables simulation of Farpointe/Pyramid card with specified card number."); + PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf pyramid sim "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf pyramid sim 123 11223"); + return 0; +} + +// Works for 26bits. +int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { + + uint8_t pre[128]; + memset(pre, 0x00, sizeof(pre)); + + // format start bit + pre[79] = 1; + + // Get 26 wiegand from FacilityCode, CardNumber + uint8_t wiegand[24]; + memset(wiegand, 0x00, sizeof(wiegand)); + num_to_bytebits(fc, 8, wiegand); + num_to_bytebits(cn, 16, wiegand+8); + + // add wiegand parity bits (dest, source, len) + wiegand_add_parity(pre+80, wiegand, 24); + + // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) + addParity(pre+8, pyramidBits+8, 102, 8, 1); + + // add checksum + uint8_t csBuff[13]; + for (uint8_t i = 0; i < 13; i++) + csBuff[i] = bytebits_to_byte(pyramidBits + 16 + (i*8), 8); + + uint32_t crc = CRC8Maxim(csBuff, 13); + num_to_bytebits(crc, 8, pyramidBits+120); + return 1; +} + +int CmdPyramidRead(const char *Cmd) { + CmdLFRead("s"); + getSamples("30000",false); + return CmdFSKdemodPyramid(""); +} + +int CmdPyramidClone(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); + + uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; + uint32_t blocks[5]; + uint8_t i; + uint8_t bs[128]; + memset(bs, 0x00, sizeof(bs)); + + if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_pyramid_clone(); + + facilitycode = (fc & 0x000000FF); + cardnumber = (cn & 0x0000FFFF); + + if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { + PrintAndLog("Error with tag bitstream generation."); + return 1; + } + +// if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') +// blocks[0] = T5555_MODULATION_FSK2 | 50< clone pyramid tag"}, + {"sim", CmdPyramidSim, 0, " simulate pyramid tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFPyramid(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfpyramid.h b/client/cmdlfpyramid.h new file mode 100644 index 00000000..d00b7d06 --- /dev/null +++ b/client/cmdlfpyramid.h @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// Low frequency T55xx commands +//----------------------------------------------------------------------------- +#ifndef CMDLFPYRAMID_H__ +#define CMDLFPYRAMID_H__ +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "crc.h" + +int CmdLFPyramid(const char *Cmd); +int CmdPyramidClone(const char *Cmd); +int CmdPyramidSim(const char *Cmd); + +int usage_lf_pyramid_clone(void); +int usage_lf_pyramid_sim(void); +#endif + diff --git a/client/util.h b/client/util.h index 5674adcf..dc5dcfa0 100644 --- a/client/util.h +++ b/client/util.h @@ -9,13 +9,12 @@ //----------------------------------------------------------------------------- #include -#include -#include +#include included in data.h #include #include #include #include -#include "data.h" +#include "data.h" //for FILE_PATH_SIZE #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) diff --git a/common/lfdemod.c b/common/lfdemod.c index 665bad89..d6c024fa 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -684,6 +684,19 @@ int VikingDemod_AM(uint8_t *dest, size_t *size) { return (int) startIdx; } +// find presco preamble 0x10D in already demoded data +int PrescoDemod(uint8_t *dest, size_t *size) { + //make sure buffer has data + if (*size < 64*2) return -2; + + size_t startIdx = 0; + uint8_t preamble[] = {1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -4; //preamble not found + //return start position + return (int) startIdx; +} + // Ask/Biphase Demod then try to locate an ISO 11784/85 ID // BitStream must contain previously askrawdemod and biphasedemoded data int FDXBdemodBI(uint8_t *dest, size_t *size) diff --git a/common/lfdemod.h b/common/lfdemod.h index d4a1fda0..56c758ae 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -13,8 +13,8 @@ #ifndef LFDEMOD_H__ #define LFDEMOD_H__ -#include -#include "common.h" //for bool +#include // for uint_32+ +#include // for bool //generic size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType); @@ -54,5 +54,5 @@ int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert); int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); int PyramiddemodFSK(uint8_t *dest, size_t *size); int VikingDemod_AM(uint8_t *dest, size_t *size); - +int PrescoDemod(uint8_t *dest, size_t *size); #endif From e3c992a92ff3b910727890a55d8d1a7e689f5249 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sat, 5 Mar 2016 23:46:34 -0500 Subject: [PATCH 06/20] fix comment typo error --- client/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/util.h b/client/util.h index dc5dcfa0..fd48a26f 100644 --- a/client/util.h +++ b/client/util.h @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- #include -#include included in data.h +#include //included in data.h #include #include #include From 29ada8fc08807d8b279afee69862c22b71aaad8f Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 7 Mar 2016 01:01:40 -0500 Subject: [PATCH 07/20] add ST to ask/manchester sim, finish presco... ...as it is currently understood - need to add base 12 printed ID to demod output... add Q5 option to pyramid fix missing include I mistakenly removed in cmdlf --- armsrc/lfops.c | 18 ++- client/cmdlf.c | 3 +- client/cmdlfpresco.c | 254 ++++++++++++++++++++++++------------------ client/cmdlfpresco.h | 20 ++-- client/cmdlfpyramid.c | 52 +++++---- client/cmdlfpyramid.h | 11 -- client/util.h | 2 +- 7 files changed, 206 insertions(+), 154 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 610781d2..2079f263 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -645,6 +645,18 @@ static void biphaseSimBit(uint8_t c, int *n, uint8_t clock, uint8_t *phase) *n += clock; } +static void stAskSimBit(int *n, uint8_t clock) { + uint8_t *dest = BigBuf_get_addr(); + uint8_t halfClk = clock/2; + //ST = .5 high .5 low 1.5 high .5 low 1 high + memset(dest+(*n), 1, halfClk); + memset(dest+(*n) + halfClk, 0, halfClk); + memset(dest+(*n) + clock, 1, clock + halfClk); + memset(dest+(*n) + clock*2 + halfClk, 0, halfClk); + memset(dest+(*n) + clock*3, 1, clock); + *n += clock*4; +} + // args clock, ask/man or askraw, invert, transmission separator void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) { @@ -675,8 +687,10 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) } } } - - if (separator==1) Dbprintf("sorry but separator option not yet available"); + if (separator==1 && encoding == 1) + stAskSimBit(&n, clk); + else if (separator==1) + Dbprintf("sorry but separator option not yet available"); Dbprintf("Simulating with clk: %d, invert: %d, encoding: %d, separator: %d, n: %d",clk, invert, encoding, separator, n); //DEBUG diff --git a/client/cmdlf.c b/client/cmdlf.c index 22bceda4..245eb224 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -14,6 +14,7 @@ #include #include "proxmark3.h" #include "cmdlf.h" +#include "lfdemod.h" // for psk2TOpsk1 #include "util.h" // for parsing cli command utils #include "ui.h" // for show graph controls #include "graph.h" // for graph data @@ -664,7 +665,7 @@ int usage_lf_simask(void) PrintAndLog(" b sim ask/biphase"); PrintAndLog(" m sim ask/manchester - Default"); PrintAndLog(" r sim ask/raw"); - PrintAndLog(" s TBD- -to enable a gap between playback repetitions - default: no gap"); + PrintAndLog(" s add t55xx Sequence Terminator gap - default: no gaps (only manchester)"); PrintAndLog(" d Data to sim as hex - omit to sim from DemodBuffer"); return 0; } diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index 20b42bc1..abae165d 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -9,16 +9,28 @@ #include #include #include "cmdlfpresco.h" +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest + static int CmdHelp(const char *Cmd); int usage_lf_presco_clone(void){ PrintAndLog("clone a Presco tag to a T55x7 tag."); - PrintAndLog("Usage: lf presco clone "); + PrintAndLog("Usage: lf presco clone d H "); PrintAndLog("Options :"); - PrintAndLog(" : 9 digit presco card number"); - //PrintAndLog(" : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLog(" d : 9 digit presco card ID"); + PrintAndLog(" H : 8 digit hex card number"); + PrintAndLog(" : specify write to Q5 (t5555 instead of t55x7)"); PrintAndLog(""); - PrintAndLog("Sample : lf presco clone 123456789"); + PrintAndLog("Sample : lf presco clone d 123456789"); return 0; } @@ -27,53 +39,88 @@ int usage_lf_presco_sim(void) { PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); PrintAndLog("Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); PrintAndLog(""); - PrintAndLog("Usage: lf presco sim "); + PrintAndLog("Usage: lf presco sim d or H "); PrintAndLog("Options :"); - PrintAndLog(" : 9 digit presco card number"); + PrintAndLog(" d : 9 digit presco card number"); + PrintAndLog(" H : 8 digit hex card number"); PrintAndLog(""); - PrintAndLog("Sample : lf presco sim 123456789"); + PrintAndLog("Sample : lf presco sim d 123456789"); return 0; } -// calc checksum -int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode) { - +// convert base 12 ID to sitecode & usercode & 8 bit other unknown code +int GetWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) { + uint8_t val = 0; - for (int index =0; index < strlen(id); ++index) { - - // Get value from number string. - if ( id[index] == '*' ) val = 10; - if ( id[index] == '#') val = 11; - if ( id[index] >= 0x30 && id[index] <= 0x39 ) - val = id[index] - 0x30; - - *sitecode += val; - - // last digit is only added, not multipled. - if ( index < strlen(id)-1 ) - *sitecode *= 12; + bool hex = false, errors = false; + uint8_t cmdp = 0; + char id[11]; + int stringlen = 0; + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + return -1; + case 'H': + hex = true; + //get hex + *fullcode = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp+=2; + break; + case 'P': + case 'p': + //param get string int param_getstr(const char *line, int paramnum, char * str) + stringlen = param_getstr(Cmd, cmdp+1, id); + if (stringlen < 2) return -1; + cmdp+=2; + break; + case 'Q': + case 'q': + *Q5 = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = 1; + break; + } + if(errors) break; } - *usercode = *sitecode % 65536; - *sitecode /= 16777216; + // No args + if(cmdp == 0) errors = 1; + + //Validations + if(errors) return -1; + + if (!hex) { + for (int index =0; index < strlen(id); ++index) { + // Get value from number string. + if ( id[index] == '*' ) val = 10; + if ( id[index] == '#') val = 11; + if ( id[index] >= 0x30 && id[index] <= 0x39 ) + val = id[index] - 0x30; + + *fullcode += val; + + // last digit is only added, not multipled. + if ( index < strlen(id)-1 ) + *fullcode *= 12; + } + } + + *usercode = *fullcode & 0x0000FFFF; //% 65566 + *sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216; return 0; } -int GetPrescoBits(uint32_t sitecode, uint32_t usercode, uint8_t *prescoBits) { - uint8_t pre[66]; - memset(pre, 0, sizeof(pre)); - prescoBits[7]=1; - num_to_bytebits(26, 8, pre); - - uint8_t wiegand[24]; - num_to_bytebits(sitecode, 8, wiegand); - num_to_bytebits(usercode, 16, wiegand+8); - - wiegand_add_parity(pre+8, wiegand, 24); - size_t bitLen = addParity(pre, prescoBits+8, 66, 4, 1); - - if (bitLen != 88) return 0; +// calc not certain - intended to get bitstream for programming / sim +int GetPrescoBits(uint32_t fullcode, uint8_t *prescoBits) { + num_to_bytebits(0x10D00000, 32, prescoBits); + num_to_bytebits(0x00000000, 32, prescoBits+32); + num_to_bytebits(0x00000000, 32, prescoBits+64); + num_to_bytebits(fullcode , 32, prescoBits+96); return 1; } + //see ASKDemod for what args are accepted int CmdPrescoDemod(const char *Cmd) { if (!ASKDemod(Cmd, false, false, 1)) { @@ -90,21 +137,26 @@ int CmdPrescoDemod(const char *Cmd) { //got a good demod uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans, 32); uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); - uint32_t cardid = bytebits_to_byte(DemodBuffer+ans+24, 32); + uint32_t raw3 = bytebits_to_byte(DemodBuffer+ans+64, 32); + uint32_t raw4 = bytebits_to_byte(DemodBuffer+ans+96, 32); + uint32_t cardid = raw4; PrintAndLog("Presco Tag Found: Card ID %08X", cardid); - PrintAndLog("Raw: %08X%08X", raw1,raw2); - setDemodBuf(DemodBuffer+ans, 64, 0); - - // uint32_t sitecode = 0, usercode = 0; - // GetWiegandFromPresco(id, &sitecode, &usercode); - // PrintAndLog8("SiteCode %d | UserCode %d", sitecode, usercode); + PrintAndLog("Raw: %08X%08X%08X%08X", raw1,raw2,raw3,raw4); + setDemodBuf(DemodBuffer+ans, 128, 0); + uint32_t sitecode = 0, usercode = 0, fullcode = 0; + bool Q5=false; + char cmd[12] = {0}; + sprintf(cmd, "H %08X", cardid); + GetWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); + PrintAndLog("SiteCode %u, UserCode %u, FullCode, %08X", sitecode, usercode, fullcode); + return 1; } //see ASKDemod for what args are accepted int CmdPrescoRead(const char *Cmd) { - // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 + // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 // read lf silently CmdLFRead("s"); @@ -114,23 +166,20 @@ int CmdPrescoRead(const char *Cmd) { return CmdPrescoDemod(Cmd); } +// takes base 12 ID converts to hex +// Or takes 8 digit hex ID int CmdPrescoClone(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_presco_clone(); - - uint32_t sitecode=0, usercode=0; - uint8_t bits[96]; - uint8_t *bs = bits; - memset(bs,0,sizeof(bits)); + bool Q5 = false; + uint32_t sitecode=0, usercode=0, fullcode=0; uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4<=0; i--) { + c.arg[0] = blocks[i]; + c.arg[1] = i; + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ + PrintAndLog("Error occurred, device did not respond during write operation."); + return -1; + } + } + return 0; } +// takes base 12 ID converts to hex +// Or takes 8 digit hex ID int CmdPrescoSim(const char *Cmd) { - // uint32_t id = 0; - // uint64_t rawID = 0; - // uint8_t clk = 32, encoding = 1, separator = 0, invert = 0; + uint32_t sitecode=0, usercode=0, fullcode=0; + bool Q5=false; + // get wiegand from printed number. + if (GetWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == -1) return usage_lf_presco_sim(); - // char cmdp = param_getchar(Cmd, 0); - // if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_presco_sim(); + uint8_t clk = 32, encoding = 1, separator = 1, invert = 0; + uint16_t arg1, arg2; + size_t size = 128; + arg1 = clk << 8 | encoding; + arg2 = invert << 8 | separator; - // id = param_get32ex(Cmd, 0, 0, 16); - // if (id == 0) return usage_lf_presco_sim(); + PrintAndLog("Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X",sitecode, usercode, fullcode); - //rawID = getVikingBits(id); - - // uint16_t arg1, arg2; - // size_t size = 64; - // arg1 = clk << 8 | encoding; - // arg2 = invert << 8 | separator; - - // PrintAndLog("Simulating - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); - - // UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; - // num_to_bytebits(rawID, size, c.d.asBytes); - // clearCommandBuffer(); - // SendCommand(&c); + UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; + GetPrescoBits(fullcode, c.d.asBytes); + clearCommandBuffer(); + SendCommand(&c); return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"read", CmdPrescoRead, 0, "Attempt to read and Extract tag data"}, - {"clone", CmdPrescoClone, 0, "<8 digit ID number> clone presco tag"}, -// {"sim", CmdPrescoSim, 0, "<8 digit ID number> simulate presco tag"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"read", CmdPrescoRead, 0, "Attempt to read and Extract tag data"}, + {"clone", CmdPrescoClone, 0, "d <9 digit ID> or h [Q5] clone presco tag"}, + {"sim", CmdPrescoSim, 0, "d <9 digit ID> or h simulate presco tag"}, + {NULL, NULL, 0, NULL} }; int CmdLFPresco(const char *Cmd) { diff --git a/client/cmdlfpresco.h b/client/cmdlfpresco.h index f9cfbd95..801df8a9 100644 --- a/client/cmdlfpresco.h +++ b/client/cmdlfpresco.h @@ -8,23 +8,17 @@ //----------------------------------------------------------------------------- #ifndef CMDLFPRESCO_H__ #define CMDLFPRESCO_H__ -#include "proxmark3.h" -#include "ui.h" -#include "util.h" -#include "graph.h" -#include "cmdparser.h" -#include "cmddata.h" -#include "cmdmain.h" -#include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest + +#include //uint_32+ +#include //bool + int CmdLFPresco(const char *Cmd); int CmdPrescoClone(const char *Cmd); -//int CmdPrescoSim(const char *Cmd); +int CmdPrescoSim(const char *Cmd); + +int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5); int usage_lf_presco_clone(void); int usage_lf_presco_sim(void); - -int GetWiegandFromPresco(const char *id, uint32_t *sitecode, uint32_t *usercode); #endif diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 990dccbb..7c19fbdb 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -9,6 +9,18 @@ #include #include #include "cmdlfpyramid.h" +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "crc.h" + static int CmdHelp(const char *Cmd); int usage_lf_pyramid_clone(void){ @@ -20,6 +32,7 @@ int usage_lf_pyramid_clone(void){ PrintAndLog("Options :"); PrintAndLog(" : 8-bit value facility code"); PrintAndLog(" : 16-bit value card number"); + PrintAndLog(" Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); PrintAndLog(""); PrintAndLog("Sample : lf pyramid clone 123 11223"); return 0; @@ -96,13 +109,14 @@ int CmdPyramidClone(const char *Cmd) { if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { PrintAndLog("Error with tag bitstream generation."); return 1; - } - -// if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') -// blocks[0] = T5555_MODULATION_FSK2 | 50< clone pyramid tag"}, - {"sim", CmdPyramidSim, 0, " simulate pyramid tag"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"read", CmdPyramidRead, 0, "Attempt to read and extract tag data"}, + {"clone", CmdPyramidClone, 0, " clone pyramid tag"}, + {"sim", CmdPyramidSim, 0, " simulate pyramid tag"}, + {NULL, NULL, 0, NULL} }; int CmdLFPyramid(const char *Cmd) { clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable); + return 0; } diff --git a/client/cmdlfpyramid.h b/client/cmdlfpyramid.h index d00b7d06..73e8338a 100644 --- a/client/cmdlfpyramid.h +++ b/client/cmdlfpyramid.h @@ -8,17 +8,6 @@ //----------------------------------------------------------------------------- #ifndef CMDLFPYRAMID_H__ #define CMDLFPYRAMID_H__ -#include "proxmark3.h" -#include "ui.h" -#include "util.h" -#include "graph.h" -#include "cmdparser.h" -#include "cmddata.h" -#include "cmdmain.h" -#include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest -#include "crc.h" int CmdLFPyramid(const char *Cmd); int CmdPyramidClone(const char *Cmd); diff --git a/client/util.h b/client/util.h index fd48a26f..34e821bf 100644 --- a/client/util.h +++ b/client/util.h @@ -14,7 +14,7 @@ #include #include #include -#include "data.h" //for FILE_PATH_SIZE +#include "data.h" //for FILE_PATH_SIZE #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) From cf194819cc71d7e0121e896e71989efc6dbfc280 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sat, 19 Mar 2016 00:09:58 -0400 Subject: [PATCH 08/20] simplify some code, add comments ABS simplification from Iceman1001 --- armsrc/appmain.c | 10 ++++----- armsrc/iso14443b.c | 14 +++++++++---- armsrc/iso15693.c | 52 ++++------------------------------------------ armsrc/pcf7931.c | 11 ++++------ common/lfdemod.c | 37 +++++++++++++++++++-------------- include/common.h | 4 ++++ 6 files changed, 47 insertions(+), 81 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 782c57fa..d20b08b2 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -36,8 +36,6 @@ #include "iso14443a.h" #endif -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - //============================================================================= // A buffer where we can queue things up to be sent through the FPGA, for // any purpose (fake tag, as reader, whatever). We go MSB first, since that @@ -841,7 +839,7 @@ void ListenReaderField(int limit) if (limit != HF_ONLY) { if(mode == 1) { - if (abs(lf_av - lf_baseline) > REPORT_CHANGE) + if (ABS(lf_av - lf_baseline) > REPORT_CHANGE) LED_D_ON(); else LED_D_OFF(); @@ -849,7 +847,7 @@ void ListenReaderField(int limit) lf_av_new = AvgAdc(ADC_CHAN_LF); // see if there's a significant change - if(abs(lf_av - lf_av_new) > REPORT_CHANGE) { + if(ABS(lf_av - lf_av_new) > REPORT_CHANGE) { Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10); lf_av = lf_av_new; if (lf_av > lf_max) @@ -859,7 +857,7 @@ void ListenReaderField(int limit) if (limit != LF_ONLY) { if (mode == 1){ - if (abs(hf_av - hf_baseline) > REPORT_CHANGE) + if (ABS(hf_av - hf_baseline) > REPORT_CHANGE) LED_B_ON(); else LED_B_OFF(); @@ -867,7 +865,7 @@ void ListenReaderField(int limit) hf_av_new = AvgAdc(ADC_CHAN_HF); // see if there's a significant change - if(abs(hf_av - hf_av_new) > REPORT_CHANGE) { + if(ABS(hf_av - hf_av_new) > REPORT_CHANGE) { Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10); hf_av = hf_av_new; if (hf_av > hf_max) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 82e5dd6a..22227e74 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -547,15 +547,20 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } */ // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) + + //note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow #define CHECK_FOR_SUBCARRIER() { \ + v = MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2); \ + } + /* if(ci < 0) { \ - if(cq < 0) { /* ci < 0, cq < 0 */ \ + if(cq < 0) { \ // ci < 0, cq < 0 if (cq < ci) { \ v = -cq - (ci >> 1); \ } else { \ v = -ci - (cq >> 1); \ } \ - } else { /* ci < 0, cq >= 0 */ \ + } else { \ // ci < 0, cq >= 0 if (cq < -ci) { \ v = -ci + (cq >> 1); \ } else { \ @@ -563,13 +568,13 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } \ } \ } else { \ - if(cq < 0) { /* ci >= 0, cq < 0 */ \ + if(cq < 0) { \ // ci >= 0, cq < 0 if (-cq < ci) { \ v = ci - (cq >> 1); \ } else { \ v = -cq + (ci >> 1); \ } \ - } else { /* ci >= 0, cq >= 0 */ \ + } else { \ // ci >= 0, cq >= 0 if (cq < ci) { \ v = ci + (cq >> 1); \ } else { \ @@ -578,6 +583,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } \ } \ } + */ switch(Demod.state) { case DEMOD_UNSYNCD: diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e7145c5c..9a6ef9f0 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -319,18 +319,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - int8_t r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -468,18 +457,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - int8_t r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -648,18 +626,7 @@ void AcquireRawAdcSamplesIso15693(void) // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - int8_t r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; @@ -713,18 +680,7 @@ void RecordRawAdcSamplesIso15693(void) // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - int8_t r; - - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } + int8_t r = ABS(b) + ABS(prev); dest[c++] = (uint8_t)r; diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 165319ca..f9f33c53 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -7,9 +7,6 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -#define abs(x) ( ((x)<0) ? -(x) : (x) ) -#define max(x,y) ( x=30) //large jump up - BitStream[i]=127; + BitStream[i]=255; else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down - BitStream[i]=-127; + BitStream[i]=0; } return; } @@ -464,10 +464,10 @@ int gProxII_Demod(uint8_t BitStream[], size_t *size) //return start position return (int) startIdx; } - return -5; + return -5; //spacer bits not found - not a valid gproxII } -//translate wave to 11111100000 (1 for each short wave 0 for each long wave) +//translate wave to 11111100000 (1 for each short wave [higher freq] 0 for each long wave [lower freq]) size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow) { size_t last_transition = 0; @@ -491,6 +491,7 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8) // or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10 + // (could also be fc/5 && fc/7 for fsk1 = 4-9) for(idx = 161; idx < size-20; idx++) { // threshold current value @@ -498,23 +499,24 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow else dest[idx] = 1; // Check for 0->1 transition - if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition + if (dest[idx-1] < dest[idx]) { preLastSample = LastSample; LastSample = currSample; currSample = idx-last_transition; - if (currSample < (fclow-2)){ //0-5 = garbage noise (or 0-3) + if (currSample < (fclow-2)) { //0-5 = garbage noise (or 0-3) //do nothing with extra garbage - } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves or 3-6 = 5 + } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves (or 3-6 = 5) + //correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5) if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample == 0 )){ - dest[numBits-1]=1; //correct previous 9 wave surrounded by 8 waves + dest[numBits-1]=1; } dest[numBits++]=1; - } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = garbage + } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage //do nothing with beginning garbage - } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's + } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's) dest[numBits++]=1; - } else { //9+ = 10 sample waves + } else { //9+ = 10 sample waves (or 6+ = 7) dest[numBits++]=0; } last_transition = idx; @@ -524,6 +526,7 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow } //translate 11111100000 to 10 +//rfLen = clock, fchigh = larger field clock, fclow = smaller field clock size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) { @@ -533,8 +536,9 @@ size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint32_t n=1; for( idx=1; idx < size; idx++) { n++; - if (dest[idx]==lastval) continue; + if (dest[idx]==lastval) continue; //skip until we hit a transition + //find out how many bits (n) we collected //if lastval was 1, we have a 1->0 crossing if (dest[idx-1]==1) { n = (n * fclow + rfLen/2) / rfLen; @@ -543,6 +547,7 @@ size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, } if (n == 0) n = 1; + //add to our destination the bits we collected memset(dest+numBits, dest[idx-1]^invert , n); numBits += n; n=0; @@ -1495,8 +1500,8 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert) numBits += (firstFullWave / *clock); //set start of wave as clock align lastClkBit = firstFullWave; - //PrintAndLog("DEBUG: firstFullWave: %d, waveLen: %d",firstFullWave,fullWaveLen); - //PrintAndLog("DEBUG: clk: %d, lastClkBit: %d", *clock, lastClkBit); + if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen); + if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc); waveStart = 0; dest[numBits++] = curPhase; //set first read bit for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){ @@ -1679,7 +1684,7 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { i=0; // warning - overwriting buffer given with raw wave data with ST removed... while ( dataloc < bufsize-(clk/2) ) { - //compensate for long high at end of ST not being high... (we cut out the high part) + //compensate for long high at end of ST not being high due to signal loss... (and we cut out the start of wave high part) if (buffer[dataloc]low && buffer[dataloc+3]low) { for(i=0; i < clk/2-tol; ++i) { buffer[dataloc+i] = high+5; @@ -1694,7 +1699,7 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { } } newloc += i; - //skip next ST + //skip next ST - we just assume it will be there from now on... dataloc += clk*4; } *size = newloc; diff --git a/include/common.h b/include/common.h index feed109c..998db64d 100644 --- a/include/common.h +++ b/include/common.h @@ -24,6 +24,10 @@ typedef unsigned char byte_t; #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef ABS +# define ABS(a) ( ((a)<0) ? -(a) : (a) ) +#endif + #define RAMFUNC __attribute((long_call, section(".ramfunc"))) From de53156e1ea6982f03a6c39adf1ae17a57056132 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sun, 19 Jun 2016 23:44:54 -0400 Subject: [PATCH 09/20] Fix the AskEdgeDetect cleaning tool somehow it got broken. (maybe i had an incomplete pull request once upon a time) --- client/cmddata.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 9854ccfa..ba161dd8 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -879,13 +879,15 @@ int CmdGraphShiftZero(const char *Cmd) int CmdAskEdgeDetect(const char *Cmd) { int thresLen = 25; + int Last = 0; sscanf(Cmd, "%i", &thresLen); for(int i = 1; i=thresLen) //large jump up - GraphBuffer[i-1] = 127; + Last = 127; else if(GraphBuffer[i]-GraphBuffer[i-1]<=-1*thresLen) //large jump down - GraphBuffer[i-1] = -127; + Last = -127; + GraphBuffer[i-1] = Last; } RepaintGraphWindow(); return 0; From 8f2268397d48fe9477eaf3784680b4114d36dcac Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 20 Jun 2016 00:28:26 -0400 Subject: [PATCH 10/20] fix bug in viking clone/sim from @iceman1001 --- client/cmdlfviking.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 45e4b1d5..fa073df1 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -47,8 +47,8 @@ int usage_lf_viking_sim(void) { uint64_t getVikingBits(uint32_t id) { //calc checksum - uint8_t checksum = (id>>24) ^ ((id>>16) & 0xFF) ^ ((id>>8) & 0xFF) ^ (id & 0xFF) ^ 0xF2 ^ 0xA8; - return ((uint64_t)0xF2 << 56) | (id << 8) | checksum; + uint8_t checksum = ((id>>24) & 0xFF) ^ ((id>>16) & 0xFF) ^ ((id>>8) & 0xFF) ^ (id & 0xFF) ^ 0xF2 ^ 0xA8; + return ((uint64_t)0xF2 << 56) | ((uint64_t)id << 8) | checksum; } //by marshmellow //see ASKDemod for what args are accepted From 16ea2b8ca301b008e109528a96fd9ba12815b7a9 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 20 Jun 2016 00:42:03 -0400 Subject: [PATCH 11/20] fix askAmp again... must have been something i missed before. this function wasn't complete. --- common/lfdemod.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/lfdemod.c b/common/lfdemod.c index cf11b25b..a6e979a2 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -260,11 +260,14 @@ int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int //by marshmellow void askAmp(uint8_t *BitStream, size_t size) { + uint8_t Last = 128; for(size_t i = 1; i=30) //large jump up - BitStream[i]=255; - else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down - BitStream[i]=0; + Last = 255; + else if(BitStream[i-1]-BitStream[i]>=20) //large jump down + Last = 0; + + BitStream[i-1] = Last; } return; } From 79dcb9e0900d51edf30d8cf863aca7be2f257ff4 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Wed, 22 Jun 2016 11:03:37 -0400 Subject: [PATCH 12/20] improve hf mf sim x reader attack can now directly extract multiple keys for multiple sectors --- armsrc/BigBuf.h | 2 + armsrc/iso14443a.c | 110 ++++++++++++++++++++++++++++----------------- client/cmdhfmf.c | 61 ++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 41 deletions(-) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 11e02c7a..928c50c4 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -12,6 +12,8 @@ #ifndef __BIGBUF_H #define __BIGBUF_H +#include // for bool +#include "common.h" // for ramfunc #define BIGBUF_SIZE 40000 #define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 27574dad..4f0a990f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2307,6 +2307,18 @@ void ReaderMifare(bool first_try) set_tracing(FALSE); } +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; +} nonces_t; + /** *MIFARE 1K simulate. * @@ -2353,12 +2365,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2 + //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 // This can be used in a reader-only attack. // (it can also be retrieved via 'hf 14a list', but hey... - uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0}; - uint8_t ar_nr_collected = 0; + + //allow collecting up to 4 sets of nonces to allow recovery of 4 keys (2 keyA & 2 keyB) + // must be set in multiples of 2 (for 1 keyA and 1 keyB) + #define ATTACK_KEY_COUNT 4 + nonces_t ar_nr_resp[ATTACK_KEY_COUNT]; + memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); + uint8_t ar_nr_collected[ATTACK_KEY_COUNT]; + memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); // Authenticate response - nonce uint32_t nonce = bytes_to_num(rAUTH_NT, 4); @@ -2506,16 +2524,35 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t ar = bytes_to_num(receivedCmd, 4); uint32_t nr = bytes_to_num(&receivedCmd[4], 4); - - //Collect AR/NR - if(ar_nr_collected < 2){ - if(ar_nr_responses[2] != ar) - {// Avoid duplicates... probably not necessary, ar should vary. - ar_nr_responses[ar_nr_collected*4] = cuid; - ar_nr_responses[ar_nr_collected*4+1] = nonce; - ar_nr_responses[ar_nr_collected*4+2] = ar; - ar_nr_responses[ar_nr_collected*4+3] = nr; - ar_nr_collected++; + + //Collect AR/NR per key/sector + if(flags & FLAG_NR_AR_ATTACK) { + for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if(cardAUTHKEY > 0 && i < (ATTACK_KEY_COUNT/2) ) { + i=ATTACK_KEY_COUNT/2; //keyB skip to keyB + } else if (cardAUTHKEY == 0 && i == ATTACK_KEY_COUNT/2) { + break; //should not get here - quit + } + // if first auth for sector, or matches sector of previous auth + if ( ar_nr_collected[i]==0 || (cardAUTHSC == ar_nr_resp[i].sector && ar_nr_collected[i] > 0) ) { + if(ar_nr_collected[i] < 2) { + if(ar_nr_resp[ar_nr_collected[i]].ar != ar) + {// Avoid duplicates... probably not necessary, ar should vary. + if (ar_nr_collected[i]==0) { + ar_nr_resp[i].cuid = cuid; + ar_nr_resp[i].sector = cardAUTHSC; + ar_nr_resp[i].nonce = nonce; + ar_nr_resp[i].ar = ar; + ar_nr_resp[i].nr = nr; + } else { + ar_nr_resp[i].ar2 = ar; + ar_nr_resp[i].nr2 = nr; + } + ar_nr_collected[i]++; + break; + } + } + } } } @@ -2537,6 +2574,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } + //auth successful ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); num_to_bytes(ans, 4, rAUTH_AT); @@ -2780,37 +2818,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); + if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) + { + for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if (ar_nr_collected[i] == 2) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); + if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK { //May just aswell send the collected ar_nr in the response aswell - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4); + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp)); } - - if(flags & FLAG_NR_AR_ATTACK) - { - if(ar_nr_collected > 1) { - Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:"); - Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3], //NR1 - ar_nr_responses[6], //AR2 - ar_nr_responses[7] //NR2 - ); - } else { - Dbprintf("Failed to obtain two AR/NR pairs!"); - if(ar_nr_collected >0) { - Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x", - ar_nr_responses[0], // UID - ar_nr_responses[1], //NT - ar_nr_responses[2], //AR1 - ar_nr_responses[3] //NR1 - ); - } - } - } - if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 48e78b1c..df504416 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" +#include "./nonce2key/nonce2key.h" static int CmdHelp(const char *Cmd); @@ -28,7 +29,7 @@ int CmdHF14AMifare(const char *Cmd) printf("-------------------------------------------------------------------------\n"); -start: + start: clearCommandBuffer(); SendCommand(&c); @@ -1079,6 +1080,64 @@ int CmdHF14AMf1kSim(const char *Cmd) //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } + //got a response + if (flags & FLAG_NR_AR_ATTACK) { + typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; + } nonces_t; + nonces_t ar_resp[4]; + //uint32_t ar_responses[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint64_t key = 0; + //uint64_t keyB = 0; + //uint8_t arnr_len = 8; + memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp)); + + for (uint8_t i = 0; i<4; i++) { + if (ar_resp[i].ar2 > 0) { + key = mfkey32(ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (key>0) { + PrintAndLog("\nFound Key%s for sector %d: [%04x%08x]", (i<2) ? "A" : "B", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + //set emulator memory for key + } + } + } + /* + if (ar_resp[1] && ar_responses[2] && ar_responses[3] && ar_responses[6] && ar_responses[7]) { + keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); + if (keyA>0) { + PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); + //set emulator memory for key + } else { + keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); + if (keyA>0) { + PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); + //set emulator memory for key + } + } + } else { + PrintAndLog("keyA response error: %d %d %d %d %d",ar_responses[1] , ar_responses[2] , ar_responses[3] , ar_responses[6] , ar_responses[7]); + } + if (ar_responses[1] && ar_responses[2+arnr_len] && ar_responses[3+arnr_len] && ar_responses[6+arnr_len] && ar_responses[7+arnr_len]) { + keyB = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2+arnr_len],ar_responses[3+arnr_len],ar_responses[6+arnr_len],ar_responses[7+arnr_len]); + if (keyB>0) { + PrintAndLog("\nFound KeyB: [%04x%08x]\n\n", (uint32_t) (keyB>>32), (uint32_t) (keyB & 0xFFFFFFFF)); + //set emulator memory for key + } + } + if (keyA || keyB) { + //TODO retry sim with new keys in emulator memory? (somehow flag to check that to see if new key has successful auth now?) + // to validate key is correct + } + */ + } } return 0; From 7314995a5a3979452d5a104dc243460dfa945ffd Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Wed, 22 Jun 2016 11:26:11 -0400 Subject: [PATCH 13/20] hf mf sim x reader attack add-ons forgot to include the mfkey32 attack --- client/nonce2key/nonce2key.c | 42 ++++++++++++++++++++++++++++++++++++ client/nonce2key/nonce2key.h | 1 + 2 files changed, 43 insertions(+) diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 70d874fe..9abc814b 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -149,3 +149,45 @@ int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_ return 1; } + +// 32 bit recover key from 2 nonces +uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc) { + struct Crypto1State *s,*t; + uint64_t key=0; // recovered key + /*uint32_t uid; // serial number + uint32_t nt; // tag challenge + uint32_t nr0_enc; // first encrypted reader challenge + uint32_t ar0_enc; // first encrypted reader response + uint32_t nr1_enc; // second encrypted reader challenge + uint32_t ar1_enc; // second encrypted reader response + */ + uint8_t found=0; + //uint32_t ks2; // keystream used to encrypt reader response + + // Generate lfsr succesors of the tag challenge + prng_successor(nt, 64); + prng_successor(nt, 96); + + // Extract the keystream from the messages + //ks2 = ar0_enc ^ prng_successor(nt, 64); + + s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, nr0_enc, 1); + lfsr_rollback_word(t, uid ^ nt, 0); + crypto1_get_lfsr(t, &key); + crypto1_word(t, uid ^ nt, 0); + crypto1_word(t, nr1_enc, 1); + if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) { + //printf("\nFound Key: [%012"llx"]\n\n",key); + found = 1; + break; + } + } + free(s); + + if (found) return key; + return 0; +} diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key/nonce2key.h index e7d5f431..b00a85dc 100644 --- a/client/nonce2key/nonce2key.h +++ b/client/nonce2key/nonce2key.h @@ -19,5 +19,6 @@ #include "common.h" int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key); +uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc); #endif From c872d8c1773591e976a508755ce43664f4083da6 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Fri, 24 Jun 2016 01:31:27 -0400 Subject: [PATCH 14/20] update hf mf sim x attack mode - start 10byte uid.. ..support (some from @iceman1001) (sim reader attack currently testing std mfkey32 vs mfkey32_moebius version...) possibly will remove one later. --- armsrc/iso14443a.c | 316 ++++++++++++++++++++++++++--------- armsrc/mifareutil.h | 17 +- client/cmdhfmf.c | 193 ++++++++++++--------- client/nonce2key/nonce2key.c | 137 +++++++++++++-- client/nonce2key/nonce2key.h | 20 ++- client/util.c | 3 + client/util.h | 1 + common/protocols.h | 15 +- include/usb_cmd.h | 9 +- 9 files changed, 513 insertions(+), 198 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 4f0a990f..7b7314dd 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -15,12 +15,13 @@ #include "util.h" #include "string.h" #include "cmd.h" - #include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" #include "BigBuf.h" +#include "protocols.h" + static uint32_t iso14a_timeout; int rsamples = 0; uint8_t trigger = 0; @@ -2324,14 +2325,17 @@ typedef struct { * *@param flags : * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK - * 4B_FLAG_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that - * 7B_FLAG_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that + * FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that + * FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that + * FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later - *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite + *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... + * (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) */ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) { int cardSTATE = MFEMUL_NOFIELD; + int _UID_LEN = 0; // 4, 7, 10 int _7BUID = 0; int vHf = 0; // in mV int res; @@ -2359,24 +2363,31 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! + uint8_t rUIDBCC3[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; + uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; uint8_t rSAK1[] = {0x04, 0xda, 0x17}; + uint8_t rSAK2[] = {0x04, 0xda, 0x17}; //need to look up uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 - // This can be used in a reader-only attack. - // (it can also be retrieved via 'hf 14a list', but hey... - - //allow collecting up to 4 sets of nonces to allow recovery of 4 keys (2 keyA & 2 keyB) - // must be set in multiples of 2 (for 1 keyA and 1 keyB) - #define ATTACK_KEY_COUNT 4 - nonces_t ar_nr_resp[ATTACK_KEY_COUNT]; + // This will be used in the reader-only attack. + + //allow collecting up to 8 sets of nonces to allow recovery of 8 keys + #define ATTACK_KEY_COUNT 8 + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - uint8_t ar_nr_collected[ATTACK_KEY_COUNT]; + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); + bool collectMoebius = false; + uint8_t nonce1_count = 0; + uint8_t nonce2_count = 0; + uint8_t moebius_n_count = 0; + uint8_t mM = 0; //moebius_modifier for collection storage + // Authenticate response - nonce uint32_t nonce = bytes_to_num(rAUTH_NT, 4); @@ -2388,45 +2399,98 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 4B uid comes from data-portion of packet memcpy(rUIDBCC1,datain,4); rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - + _UID_LEN = 4; } else if (flags & FLAG_7B_UID_IN_DATA) { // 7B uid comes from data-portion of packet memcpy(&rUIDBCC1[1],datain,3); memcpy(rUIDBCC2, datain+3, 4); _7BUID = true; + _UID_LEN = 7; + } else if (flags & FLAG_10B_UID_IN_DATA) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(&rUIDBCC2[1], datain+3, 3); + memcpy( rUIDBCC3, datain+6, 4); + _UID_LEN = 10; } else { - // get UID from emul memory + // get UID from emul memory - guess at length emlGetMemBt(receivedCmd, 7, 1); _7BUID = !(receivedCmd[0] == 0x00); if (!_7BUID) { // ---------- 4BUID emlGetMemBt(rUIDBCC1, 0, 4); + _UID_LEN = 4; } else { // ---------- 7BUID emlGetMemBt(&rUIDBCC1[1], 0, 3); emlGetMemBt(rUIDBCC2, 3, 4); + _UID_LEN = 7; } } - /* - * Regardless of what method was used to set the UID, set fifth byte and modify - * the ATQA for 4 or 7-byte UID - */ - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (_7BUID) { - rATQA[0] = 0x44; - rUIDBCC1[0] = 0x88; - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - } + switch (_UID_LEN) { + case 4: + // save CUID + cuid = bytes_to_num(rUIDBCC1, 4); + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + if (MF_DBGLEVEL >= 2) { + Dbprintf("4B UID: %02x%02x%02x%02x", + rUIDBCC1[0], + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3] + ); + } + break; + case 7: + rATQA[0] |= 0x40; + // save CUID + cuid = bytes_to_num(rUIDBCC2, 4); + // CascadeTag, CT + rUIDBCC1[0] = 0x88; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (MF_DBGLEVEL >= 2) { + Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3], + rUIDBCC2[0], + rUIDBCC2[1], + rUIDBCC2[2], + rUIDBCC2[3] + ); + } + break; + case 10: + rATQA[0] |= 0x80; + //sak_10[0] &= 0xFB; + // save CUID + cuid = bytes_to_num(rUIDBCC3, 4); + // CascadeTag, CT + rUIDBCC1[0] = 0x88; + rUIDBCC2[0] = 0x88; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3]; - if (MF_DBGLEVEL >= 1) { - if (!_7BUID) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); - } else { - Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], - rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]); - } + if (MF_DBGLEVEL >= 2) { + Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], + rUIDBCC1[2], + rUIDBCC1[3], + rUIDBCC2[1], + rUIDBCC2[2], + rUIDBCC2[3], + rUIDBCC3[0], + rUIDBCC3[1], + rUIDBCC3[2], + rUIDBCC3[3] + ); + } + break; + default: + break; } // We need to listen to the high-frequency, peak-detected path. @@ -2439,9 +2503,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * clear_trace(); set_tracing(TRUE); - bool finished = FALSE; - while (!BUTTON_PRESS() && !finished) { + while (!BUTTON_PRESS() && !finished && !usb_poll_validate_length()) { WDT_HIT(); // find reader field @@ -2452,10 +2515,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * LED_A_ON(); } } - if(cardSTATE == MFEMUL_NOFIELD) continue; + if (cardSTATE == MFEMUL_NOFIELD) continue; //Now, get data - res = EmGetCmd(receivedCmd, &len, receivedCmd_par); if (res == 2) { //Field is off! cardSTATE = MFEMUL_NOFIELD; @@ -2466,9 +2528,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } // REQ or WUP request in ANY state and WUP in HALTED state - if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) { + if (len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { selTimer = GetTickCount(); - EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52)); + EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == ISO14443A_CMD_WUPA)); cardSTATE = MFEMUL_SELECT1; // init crypto block @@ -2499,21 +2561,54 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); } // select card + // check correct sak values... (marshmellow) if (len == 9 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { - EmSendCmd(_7BUID?rSAK1:rSAK, _7BUID?sizeof(rSAK1):sizeof(rSAK)); - cuid = bytes_to_num(rUIDBCC1, 4); - if (!_7BUID) { - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); - break; - } else { - cardSTATE = MFEMUL_SELECT2; + switch(_UID_LEN) { + case 4: + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); + EmSendCmd(rSAK, sizeof(rSAK)); + break; + case 7: + cardSTATE = MFEMUL_SELECT2; + EmSendCmd(rSAK1, sizeof(rSAK1)); + break; + case 10: + cardSTATE = MFEMUL_SELECT2; + EmSendCmd(rSAK2, sizeof(rSAK2)); + break; + default:break; } + } else { + cardSTATE_TO_IDLE(); } break; } + case MFEMUL_SELECT3:{ + if (!len) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); + break; + } + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x20)) { + EmSendCmd(rUIDBCC3, sizeof(rUIDBCC3)); + break; + } + if (len == 9 && + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && + receivedCmd[1] == 0x70 && + memcmp(&receivedCmd[2], rUIDBCC3, 4) == 0) ) { + + EmSendCmd(rSAK2, sizeof(rSAK2)); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol3 time: %d", GetTickCount() - selTimer); + break; + } + cardSTATE_TO_IDLE(); + break; + } case MFEMUL_AUTH1:{ if( len != 8) { @@ -2522,43 +2617,67 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } - uint32_t ar = bytes_to_num(receivedCmd, 4); - uint32_t nr = bytes_to_num(&receivedCmd[4], 4); + uint32_t nr = bytes_to_num(receivedCmd, 4); + uint32_t ar = bytes_to_num(&receivedCmd[4], 4); - //Collect AR/NR per key/sector + //Collect AR/NR per keytype & sector if(flags & FLAG_NR_AR_ATTACK) { for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - if(cardAUTHKEY > 0 && i < (ATTACK_KEY_COUNT/2) ) { - i=ATTACK_KEY_COUNT/2; //keyB skip to keyB - } else if (cardAUTHKEY == 0 && i == ATTACK_KEY_COUNT/2) { - break; //should not get here - quit - } - // if first auth for sector, or matches sector of previous auth - if ( ar_nr_collected[i]==0 || (cardAUTHSC == ar_nr_resp[i].sector && ar_nr_collected[i] > 0) ) { - if(ar_nr_collected[i] < 2) { - if(ar_nr_resp[ar_nr_collected[i]].ar != ar) - {// Avoid duplicates... probably not necessary, ar should vary. - if (ar_nr_collected[i]==0) { - ar_nr_resp[i].cuid = cuid; - ar_nr_resp[i].sector = cardAUTHSC; - ar_nr_resp[i].nonce = nonce; - ar_nr_resp[i].ar = ar; - ar_nr_resp[i].nr = nr; - } else { - ar_nr_resp[i].ar2 = ar; - ar_nr_resp[i].nr2 = nr; + if ( ar_nr_collected[i+mM]==0 || (cardAUTHSC == ar_nr_resp[i+mM].sector && cardAUTHKEY == ar_nr_resp[i+mM].keytype && ar_nr_collected[i+mM] > 0) ) { + // if first auth for sector, or matches sector and keytype of previous auth + if (ar_nr_collected[i+mM] < 2) { + // if we haven't already collected 2 nonces for this sector + if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { + // Avoid duplicates... probably not necessary, ar should vary. + if (ar_nr_collected[i+mM]==0) { + // first nonce collect + ar_nr_resp[i+mM].cuid = cuid; + ar_nr_resp[i+mM].sector = cardAUTHSC; + ar_nr_resp[i+mM].keytype = cardAUTHKEY; + ar_nr_resp[i+mM].nonce = nonce; + ar_nr_resp[i+mM].nr = nr; + ar_nr_resp[i+mM].ar = ar; + nonce1_count++; + //add this nonce to first moebius nonce + ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid; + ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC; + ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY; + ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce; + ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr; + ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar; + ar_nr_collected[i+ATTACK_KEY_COUNT]++; + } else { //second nonce collect (std and moebius) + ar_nr_resp[i+mM].nonce2 = nonce; + ar_nr_resp[i+mM].nr2 = nr; + ar_nr_resp[i+mM].ar2 = ar; + if (!collectMoebius) { + nonce2_count++; + //check if this was the last second nonce we need for std attack + if ( nonce2_count == nonce1_count ) { + //done collecting std test switch to moebius + collectMoebius = true; + mM = ATTACK_KEY_COUNT; + nonce = nonce*7; + } + } else { + moebius_n_count++; + //if we've collected all the nonces we need - finish. + if (nonce1_count == moebius_n_count) finished = true; + } } - ar_nr_collected[i]++; + ar_nr_collected[i+mM]++; break; } + } else { //already collected 2 nonces for sector - reader looping? - quit + //finished = true; } } } } - + // --- crypto - crypto1_word(pcs, ar , 1); - cardRr = nr ^ crypto1_word(pcs, 0, 0); + crypto1_word(pcs, nr , 1); + cardRr = ar ^ crypto1_word(pcs, 0, 0); // test if auth OK if (cardRr != prng_successor(nonce, 64)){ @@ -2600,11 +2719,19 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // select 2 card if (len == 9 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { + //which sak now? (marshmellow) EmSendCmd(rSAK, sizeof(rSAK)); - cuid = bytes_to_num(rUIDBCC2, 4); - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + switch(_UID_LEN) { + case 7: + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + break; + case 10: + cardSTATE = MFEMUL_SELECT3; + break; + default:break; + } break; } @@ -2632,11 +2759,20 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { + if (receivedCmd[1] >= 16 * 4) { + //is this the correct response to an auth on a out of range block? marshmellow + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + break; + } + authTimer = GetTickCount(); cardAUTHSC = receivedCmd[1] / 4; // received block num cardAUTHKEY = receivedCmd[0] - 0x60; crypto1_destroy(pcs);//Added by martin crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); + //uint64_t key=emlGetKey(cardAUTHSC, cardAUTHKEY); + //Dbprintf("key: %04x%08x",(uint32_t)(key>>32)&0xFFFF,(uint32_t)(key&0xFFFFFFFF)); if (!encrypted_data) { // first authentication if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY ); @@ -2826,19 +2962,33 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", ar_nr_resp[i].cuid, //UID ar_nr_resp[i].nonce, //NT - ar_nr_resp[i].ar, //AR1 ar_nr_resp[i].nr, //NR1 - ar_nr_resp[i].ar2, //AR2 - ar_nr_resp[i].nr2 //NR2 + ar_nr_resp[i].ar, //AR1 + ar_nr_resp[i].nr2, //NR2 + ar_nr_resp[i].ar2 //AR2 ); } } + for ( uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT*2; i++) { + if (ar_nr_collected[i] == 2) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK { - //May just aswell send the collected ar_nr in the response aswell + //Send the collected ar_nr in the response cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp)); } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 7a09ce64..3d4dd400 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -42,14 +42,15 @@ extern int MF_DBGLEVEL; #define MFEMUL_IDLE 1 #define MFEMUL_SELECT1 2 #define MFEMUL_SELECT2 3 -#define MFEMUL_AUTH1 4 -#define MFEMUL_AUTH2 5 -#define MFEMUL_WORK 6 -#define MFEMUL_WRITEBL2 7 -#define MFEMUL_INTREG_INC 8 -#define MFEMUL_INTREG_DEC 9 -#define MFEMUL_INTREG_REST 10 -#define MFEMUL_HALTED 11 +#define MFEMUL_SELECT3 4 +#define MFEMUL_AUTH1 5 +#define MFEMUL_AUTH2 6 +#define MFEMUL_WORK 7 +#define MFEMUL_WRITEBL2 8 +#define MFEMUL_INTREG_INC 9 +#define MFEMUL_INTREG_DEC 10 +#define MFEMUL_INTREG_REST 11 +#define MFEMUL_HALTED 12 #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index df504416..4b82e698 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1016,64 +1016,81 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } +int usage_hf14_mf1ksim(void){ + PrintAndLog("Usage: hf mf sim [h] u n i x"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" u (Optional) UID 4,7 bytes. If not specified, the UID 4b from emulator memory will be used"); + PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); + PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); + PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); + PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf sim u 0a0a0a0a"); + PrintAndLog(" hf mf sim u 11223344556677"); + //PrintAndLog(" hf mf sim u 112233445566778899AA"); + return 0; +} + int CmdHF14AMf1kSim(const char *Cmd) { - uint8_t uid[7] = {0, 0, 0, 0, 0, 0, 0}; + #define ATTACK_KEY_COUNT 8 + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; - - uint8_t cmdp = param_getchar(Cmd, 0); - - if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mf sim u n i x"); - PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID. If not specified, the UID from emulator memory will be used"); - PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); - PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); - PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); - PrintAndLog(""); - PrintAndLog(" sample: hf mf sim u 0a0a0a0a "); - return 0; - } + int uidlen = 0; uint8_t pnr = 0; - if (param_getchar(Cmd, pnr) == 'u') { - if(param_gethex(Cmd, pnr+1, uid, 8) == 0) - { - flags |= FLAG_4B_UID_IN_DATA; // UID from packet - } else if(param_gethex(Cmd,pnr+1,uid,14) == 0) { - flags |= FLAG_7B_UID_IN_DATA;// UID from packet - } else { - PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols"); - return 1; + bool setEmulatorMem = false; + + char cmdp = param_getchar(Cmd, pnr); + + if (cmdp == 'h' || cmdp == 'H') return usage_hf14_mf1ksim(); + + if (cmdp == 'u' || cmdp == 'U') { + param_gethex_ex(Cmd, pnr+1, uid, &uidlen); + switch(uidlen){ + //case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags = FLAG_7B_UID_IN_DATA; break; + case 8: flags = FLAG_4B_UID_IN_DATA; break; + default: return usage_hf14_mf1ksim(); } pnr +=2; } - if (param_getchar(Cmd, pnr) == 'n') { - exitAfterNReads = param_get8(Cmd,pnr+1); + + cmdp = param_getchar(Cmd, pnr); + if (cmdp == 'n' || cmdp == 'N') { + exitAfterNReads = param_get8(Cmd, pnr+1); pnr += 2; } - if (param_getchar(Cmd, pnr) == 'i' ) { - //Using a flag to signal interactiveness, least significant bit + + cmdp = param_getchar(Cmd, pnr); + if (cmdp == 'i' || cmdp == 'I' ) { flags |= FLAG_INTERACTIVE; pnr++; } - if (param_getchar(Cmd, pnr) == 'x' ) { - //Using a flag to signal interactiveness, least significant bit + cmdp = param_getchar(Cmd, pnr); + if (cmdp == 'x' || cmdp == 'X') { flags |= FLAG_NR_AR_ATTACK; } + + cmdp = param_getchar(Cmd, pnr); + if (cmdp == 'e' || cmdp == 'E') { + setEmulatorMem = true; + } + PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ", 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); UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); + clearCommandBuffer(); SendCommand(&c); - if(flags & FLAG_INTERACTIVE) - { + if(flags & FLAG_INTERACTIVE) { UsbCommand resp; PrintAndLog("Press pm3-button to abort simulation"); while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -1082,61 +1099,79 @@ int CmdHF14AMf1kSim(const char *Cmd) } //got a response if (flags & FLAG_NR_AR_ATTACK) { - typedef struct { - uint32_t cuid; - uint8_t sector; - uint8_t keytype; - uint32_t nonce; - uint32_t ar; - uint32_t nr; - uint32_t nonce2; - uint32_t ar2; - uint32_t nr2; - } nonces_t; - nonces_t ar_resp[4]; - //uint32_t ar_responses[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; uint64_t key = 0; - //uint64_t keyB = 0; - //uint8_t arnr_len = 8; memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp)); - - for (uint8_t i = 0; i<4; i++) { + typedef struct { + uint64_t keyA; + uint32_t security; + uint64_t keyB; + } st_t; + st_t sector_trailer[ATTACK_KEY_COUNT]; + memset(sector_trailer, 0x00, sizeof(sector_trailer)); + + 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)); + + for (uint8_t i = 0; i 0) { - key = mfkey32(ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); - if (key>0) { - PrintAndLog("\nFound Key%s for sector %d: [%04x%08x]", (i<2) ? "A" : "B", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); - //set emulator memory for key - } - } - } - /* - if (ar_resp[1] && ar_responses[2] && ar_responses[3] && ar_responses[6] && ar_responses[7]) { - keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); - if (keyA>0) { - PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); - //set emulator memory for key - } else { - keyA = mfkey32(ar_responses[0],ar_responses[1],ar_responses[2],ar_responses[3],ar_responses[6],ar_responses[7]); - if (keyA>0) { - PrintAndLog("\nFound KeyA: [%04x%08x]\n\n", (uint32_t) (keyA>>32), (uint32_t) (keyA &0xFFFFFFFF)); - //set emulator memory for key + //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (mfkey32(ar_resp[i], &key)) { + PrintAndLog("Found Key%s for sector %d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + + for (uint8_t ii = 0; ii0) { - PrintAndLog("\nFound KeyB: [%04x%08x]\n\n", (uint32_t) (keyB>>32), (uint32_t) (keyB & 0xFFFFFFFF)); - //set emulator memory for key + //set emulator memory for keys + if (setEmulatorMem) { + for (uint8_t i = 0; i0) { + //PrintAndLog ("block %d, keyA:%04x%08x, keyb:%04x%08x",stSector[i]*4+3, (uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); + uint8_t memBlock[16]; + memset(memBlock, 0x00, sizeof(memBlock)); + char cmd1[36]; + memset(cmd1,0x00,sizeof(cmd1)); + snprintf(cmd1,sizeof(cmd1),"%04x%08xFF078069%04x%08x",(uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); + //PrintAndLog("%s",cmd1); + if (param_gethex(cmd1, 0, memBlock, 32)) { + PrintAndLog("block data must include 32 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {(stSector[i]*4+3), 1, 0}}; + memcpy(c.d.asBytes, memBlock, 16); + clearCommandBuffer(); + SendCommand(&c); + } } } - if (keyA || keyB) { - //TODO retry sim with new keys in emulator memory? (somehow flag to check that to see if new key has successful auth now?) - // to validate key is correct + //moebius attack + for (uint8_t i = ATTACK_KEY_COUNT; i 0) { + if (tryMfk32_moebius(ar_resp[i], &key)) { + PrintAndLog("M-Found Key%s for sector %d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + } + } } - */ } } diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 9abc814b..3750366b 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -151,22 +151,24 @@ int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_ } // 32 bit recover key from 2 nonces -uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc) { +bool mfkey32(nonces_t data, uint64_t *outputkey) { struct Crypto1State *s,*t; + uint64_t outkey = 0; uint64_t key=0; // recovered key - /*uint32_t uid; // serial number - uint32_t nt; // tag challenge - uint32_t nr0_enc; // first encrypted reader challenge - uint32_t ar0_enc; // first encrypted reader response - uint32_t nr1_enc; // second encrypted reader challenge - uint32_t ar1_enc; // second encrypted reader response - */ - uint8_t found=0; - //uint32_t ks2; // keystream used to encrypt reader response - + uint32_t uid = data.cuid; + uint32_t nt = data.nonce; // first tag challenge (nonce) + uint32_t nr0_enc = data.nr; // first encrypted reader challenge + uint32_t ar0_enc = data.ar; // first encrypted reader response + uint32_t nr1_enc = data.nr2; // second encrypted reader challenge + uint32_t ar1_enc = data.ar2; // second encrypted reader response + clock_t t1 = clock(); + bool isSuccess = FALSE; + uint8_t counter=0; + //PrintAndLog("Enter mfkey32"); + //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, nr %08x, ar %08x, nr2 %08x, ar2 %08x",data.sector, uid, nt,nr0_enc,ar0_enc,nr1_enc,ar1_enc); // Generate lfsr succesors of the tag challenge - prng_successor(nt, 64); - prng_successor(nt, 96); + //prng_successor(nt, 64); + //prng_successor(nt, 96); // Extract the keystream from the messages //ks2 = ar0_enc ^ prng_successor(nt, 64); @@ -181,13 +183,112 @@ uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, crypto1_word(t, uid ^ nt, 0); crypto1_word(t, nr1_enc, 1); if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) { - //printf("\nFound Key: [%012"llx"]\n\n",key); - found = 1; - break; + //PrintAndLog("Found Key: [%012"llx"]",key); + outkey = key; + counter++; + if (counter==20) break; } } - free(s); + //free(s); + isSuccess = (counter == 1); + t1 = clock() - t1; + //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.0f ticks \nFound %d possible keys", (float)t1, counter); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "mfkey32,%d,%d,%s,%04x%08x,%.0Lf\r\n",counter,data.sector,(data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + return isSuccess; +} - if (found) return key; +bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s, *t; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + uint32_t uid = data.cuid; + uint32_t nt0 = data.nonce; // first tag challenge (nonce) + uint32_t nr0_enc = data.nr; // first encrypted reader challenge + uint32_t ar0_enc = data.ar; // first encrypted reader response + //uint32_t uid1 = le32toh(data+16); + uint32_t nt1 = data.nonce2; // second tag challenge (nonce) + uint32_t nr1_enc = data.nr2; // second encrypted reader challenge + uint32_t ar1_enc = data.ar2; // second encrypted reader response + bool isSuccess = FALSE; + int counter = 0; + + //PrintAndLog("Enter mfkey32_moebius"); + clock_t t1 = clock(); + + s = lfsr_recovery32(ar0_enc ^ prng_successor(nt0, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, nr0_enc, 1); + lfsr_rollback_word(t, uid ^ nt0, 0); + crypto1_get_lfsr(t, &key); + + crypto1_word(t, uid ^ nt1, 0); + crypto1_word(t, nr1_enc, 1); + if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt1, 64))) { + //PrintAndLog("Found Key: [%012"llx"]",key); + outkey=key; + ++counter; + if (counter==20) + break; + } + } + isSuccess = (counter == 1); + t1 = clock() - t1; + //if ( t1 > 0 ) PrintAndLog("Time in mfkey32_moebius: %.0f ticks \nFound %d possible keys", (float)t1,counter); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "moebius,%d,%d,%s,%04x%08x,%0.Lf\r\n",counter,data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + return isSuccess; +} + +int tryMfk64_ex(uint8_t *data, uint64_t *outputkey){ + uint32_t uid = le32toh(data); + uint32_t nt = le32toh(data+4); // tag challenge + uint32_t nr_enc = le32toh(data+8); // encrypted reader challenge + uint32_t ar_enc = le32toh(data+12); // encrypted reader response + uint32_t at_enc = le32toh(data+16); // encrypted tag response + return tryMfk64(uid, nt, nr_enc, ar_enc, at_enc, outputkey); +} + +int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey){ + uint64_t key = 0; // recovered key + uint32_t ks2; // keystream used to encrypt reader response + uint32_t ks3; // keystream used to encrypt tag response + struct Crypto1State *revstate; + + PrintAndLog("Enter mfkey64"); + clock_t t1 = clock(); + + // Extract the keystream from the messages + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + crypto1_get_lfsr(revstate, &key); + PrintAndLog("Found Key: [%012"llx"]", key); + crypto1_destroy(revstate); + *outputkey = key; + + t1 = clock() - t1; + if ( t1 > 0 ) PrintAndLog("Time in mfkey64: %.0f ticks \n", (float)t1); return 0; } + diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key/nonce2key.h index b00a85dc..fac9c151 100644 --- a/client/nonce2key/nonce2key.h +++ b/client/nonce2key/nonce2key.h @@ -17,8 +17,26 @@ #include #include "crapto1.h" #include "common.h" +//#include //for bool + +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; + } nonces_t; int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key); -uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc); +bool mfkey32(nonces_t data, uint64_t *outputkey); +bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey); +int tryMfk64_ex(uint8_t *data, uint64_t *outputkey); +int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey); + +//uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc); #endif diff --git a/client/util.c b/client/util.c index 9b99cdf1..e4add6c0 100644 --- a/client/util.c +++ b/client/util.c @@ -498,6 +498,9 @@ void xor(unsigned char *dst, unsigned char *src, size_t len) { int32_t le24toh (uint8_t data[3]) { return (data[2] << 16) | (data[1] << 8) | data[0]; } +uint32_t le32toh (uint8_t *data) { + return (uint32_t)( (data[3]<<24) | (data[2]<<16) | (data[1]<<8) | data[0]); +} // RotateLeft - Ultralight, Desfire, works on byte level // 00-01-02 >> 01-02-00 diff --git a/client/util.h b/client/util.h index 34e821bf..1b6b2fb1 100644 --- a/client/util.h +++ b/client/util.h @@ -70,4 +70,5 @@ void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length); void xor(unsigned char *dst, unsigned char *src, size_t len); int32_t le24toh(uint8_t data[3]); +uint32_t le32toh (uint8_t *data); void rol(uint8_t *data, const size_t len); diff --git a/common/protocols.h b/common/protocols.h index cdcf720b..b57c414f 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -109,20 +109,25 @@ NXP/Philips CUSTOM COMMANDS #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_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_ULC_WRITE 0xA2 //#define MIFARE_ULC__COMP_WRITE 0xA0 #define MIFARE_ULC_AUTH_1 0x1A diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 8448b06a..03a573d5 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -212,10 +212,11 @@ typedef struct{ //Mifare simulation flags -#define FLAG_INTERACTIVE 0x01 -#define FLAG_4B_UID_IN_DATA 0x02 -#define FLAG_7B_UID_IN_DATA 0x04 -#define FLAG_NR_AR_ATTACK 0x08 +#define FLAG_INTERACTIVE 0x01 +#define FLAG_4B_UID_IN_DATA 0x02 +#define FLAG_7B_UID_IN_DATA 0x04 +#define FLAG_10B_UID_IN_DATA 0x08 +#define FLAG_NR_AR_ATTACK 0x10 //Iclass reader flags From 6eae192c415b6c4455d67f6d8e7ae8fb5c70a8e5 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Fri, 24 Jun 2016 16:46:11 -0400 Subject: [PATCH 15/20] fix bug in moebius nonce collection - now finishes also cleaned up some comments note previous update added the creation of a stats.txt file to generate statistics of the differences between std mfkey32 and the moebius version. --- armsrc/iso14443a.c | 23 +++++++++++++++-------- client/cmdhfmf.c | 7 ++++--- client/nonce2key/nonce2key.c | 8 -------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 7b7314dd..6216fc4a 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2382,7 +2382,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - bool collectMoebius = false; + bool gettingMoebius = false; uint8_t nonce1_count = 0; uint8_t nonce2_count = 0; uint8_t moebius_n_count = 0; @@ -2623,7 +2623,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //Collect AR/NR per keytype & sector if(flags & FLAG_NR_AR_ATTACK) { for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - if ( ar_nr_collected[i+mM]==0 || (cardAUTHSC == ar_nr_resp[i+mM].sector && cardAUTHKEY == ar_nr_resp[i+mM].keytype && ar_nr_collected[i+mM] > 0) ) { + if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) { // if first auth for sector, or matches sector and keytype of previous auth if (ar_nr_collected[i+mM] < 2) { // if we haven't already collected 2 nonces for this sector @@ -2650,14 +2650,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * ar_nr_resp[i+mM].nonce2 = nonce; ar_nr_resp[i+mM].nr2 = nr; ar_nr_resp[i+mM].ar2 = ar; - if (!collectMoebius) { + if (!gettingMoebius) { nonce2_count++; //check if this was the last second nonce we need for std attack if ( nonce2_count == nonce1_count ) { //done collecting std test switch to moebius - collectMoebius = true; + //finish incrementing last sample + ar_nr_collected[i+mM]++; + //switch to moebius collection + gettingMoebius = true; mM = ATTACK_KEY_COUNT; nonce = nonce*7; + break; } } else { moebius_n_count++; @@ -2666,15 +2670,16 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } } ar_nr_collected[i+mM]++; - break; } - } else { //already collected 2 nonces for sector - reader looping? - quit + } else { //already collected 2 nonces for sector - dump out //finished = true; } + // we found right spot for this nonce stop looking + break; } } } - + // --- crypto crypto1_word(pcs, nr , 1); cardRr = ar ^ crypto1_word(pcs, 0, 0); @@ -2759,7 +2764,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { - if (receivedCmd[1] >= 16 * 4) { + + // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack + if (receivedCmd[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) { //is this the correct response to an auth on a out of range block? marshmellow EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 4b82e698..c565a7cf 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1072,6 +1072,7 @@ int CmdHF14AMf1kSim(const char *Cmd) cmdp = param_getchar(Cmd, pnr); if (cmdp == 'x' || cmdp == 'X') { flags |= FLAG_NR_AR_ATTACK; + pnr++; } cmdp = param_getchar(Cmd, pnr); @@ -1119,7 +1120,7 @@ int CmdHF14AMf1kSim(const char *Cmd) if (ar_resp[i].ar2 > 0) { //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); if (mfkey32(ar_resp[i], &key)) { - PrintAndLog("Found Key%s for sector %d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + PrintAndLog("Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); for (uint8_t ii = 0; ii>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); - //PrintAndLog("%s",cmd1); + PrintAndLog("Setting Emulator Memory Block %02d: [%s]",stSector[i]*4+3, cmd1); if (param_gethex(cmd1, 0, memBlock, 32)) { PrintAndLog("block data must include 32 HEX symbols"); return 1; @@ -1168,7 +1169,7 @@ int CmdHF14AMf1kSim(const char *Cmd) for (uint8_t i = ATTACK_KEY_COUNT; i 0) { if (tryMfk32_moebius(ar_resp[i], &key)) { - PrintAndLog("M-Found Key%s for sector %d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); } } } diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 3750366b..fcf34a73 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -164,14 +164,6 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { clock_t t1 = clock(); bool isSuccess = FALSE; uint8_t counter=0; - //PrintAndLog("Enter mfkey32"); - //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, nr %08x, ar %08x, nr2 %08x, ar2 %08x",data.sector, uid, nt,nr0_enc,ar0_enc,nr1_enc,ar1_enc); - // Generate lfsr succesors of the tag challenge - //prng_successor(nt, 64); - //prng_successor(nt, 96); - - // Extract the keystream from the messages - //ks2 = ar0_enc ^ prng_successor(nt, 64); s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0); From bbd118760ba7c244d64b8380de0072c6f95a6113 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Fri, 24 Jun 2016 23:43:53 -0400 Subject: [PATCH 16/20] allow mf1k reader attack from file full of UIDs also add UID to stats.txt collection. --- client/cmdhfmf.c | 345 ++++++++++++++++++++++------------- client/nonce2key/nonce2key.c | 4 +- 2 files changed, 224 insertions(+), 125 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c565a7cf..05202ac5 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1016,7 +1016,82 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } -int usage_hf14_mf1ksim(void){ +void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { + #define ATTACK_KEY_COUNT 8 + uint64_t key = 0; + typedef struct { + uint64_t keyA; + uint32_t security; + uint64_t keyB; + } st_t; + st_t sector_trailer[ATTACK_KEY_COUNT]; + memset(sector_trailer, 0x00, sizeof(sector_trailer)); + + 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)); + + for (uint8_t i = 0; i 0) { + //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (mfkey32(ar_resp[i], &key)) { + PrintAndLog("Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + + for (uint8_t ii = 0; ii0) { + //PrintAndLog ("block %d, keyA:%04x%08x, keyb:%04x%08x",stSector[i]*4+3, (uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); + uint8_t memBlock[16]; + memset(memBlock, 0x00, sizeof(memBlock)); + char cmd1[36]; + memset(cmd1,0x00,sizeof(cmd1)); + snprintf(cmd1,sizeof(cmd1),"%04x%08xFF078069%04x%08x",(uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); + PrintAndLog("Setting Emulator Memory Block %02d: [%s]",stSector[i]*4+3, cmd1); + if (param_gethex(cmd1, 0, memBlock, 32)) { + PrintAndLog("block data must include 32 HEX symbols"); + return; + } + + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {(stSector[i]*4+3), 1, 0}}; + memcpy(c.d.asBytes, memBlock, 16); + clearCommandBuffer(); + SendCommand(&c); + } + } + } + //moebius attack + for (uint8_t i = ATTACK_KEY_COUNT; i 0) { + if (tryMfk32_moebius(ar_resp[i], &key)) { + PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + } + } + } +} + +int usage_hf14_mf1ksim(void) { PrintAndLog("Usage: hf mf sim [h] u n i x"); PrintAndLog("options:"); PrintAndLog(" h this help"); @@ -1025,157 +1100,181 @@ int usage_hf14_mf1ksim(void){ PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory"); + PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f '"); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); - //PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim u 112233445566778899AA"); return 0; } -int CmdHF14AMf1kSim(const char *Cmd) -{ - #define ATTACK_KEY_COUNT 8 +int CmdHF14AMf1kSim(const char *Cmd) { uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; int uidlen = 0; uint8_t pnr = 0; bool setEmulatorMem = false; + bool attackFromFile = false; + FILE *f; + char filename[FILE_PATH_SIZE]; + memset(filename, 0x00, sizeof(filename)); + int len = 0; + char buf[64]; + uint8_t uidBuffer[64]; - char cmdp = param_getchar(Cmd, pnr); - - if (cmdp == 'h' || cmdp == 'H') return usage_hf14_mf1ksim(); + uint8_t cmdp = 0; + bool errors = false; - if (cmdp == 'u' || cmdp == 'U') { - param_gethex_ex(Cmd, pnr+1, uid, &uidlen); - switch(uidlen){ - //case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete - case 14: flags = FLAG_7B_UID_IN_DATA; break; - case 8: flags = FLAG_4B_UID_IN_DATA; break; - default: return usage_hf14_mf1ksim(); + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'e': + case 'E': + setEmulatorMem = true; + cmdp++; + break; + case 'f': + case 'F': + len = param_getstr(Cmd, cmdp+1, filename); + if (len < 1) { + PrintAndLog("error no filename found"); + return 0; + } + attackFromFile = true; + cmdp+=2; + break; + case 'h': + case 'H': + return usage_hf14_mf1ksim(); + case 'i': + case 'I': + flags |= FLAG_INTERACTIVE; + cmdp++; + break; + case 'n': + case 'N': + exitAfterNReads = param_get8(Cmd, pnr+1); + cmdp += 2; + break; + case 'u': + case 'U': + param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); + switch(uidlen) { + case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags = FLAG_7B_UID_IN_DATA; break; + case 8: flags = FLAG_4B_UID_IN_DATA; break; + default: return usage_hf14_mf1ksim(); + } + cmdp +=2; + break; + case 'x': + case 'X': + flags |= FLAG_NR_AR_ATTACK; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; } - pnr +=2; + if(errors) break; } + //Validations + if(errors) return usage_hf14_mf1ksim(); - cmdp = param_getchar(Cmd, pnr); - if (cmdp == 'n' || cmdp == 'N') { - exitAfterNReads = param_get8(Cmd, pnr+1); - pnr += 2; - } - - cmdp = param_getchar(Cmd, pnr); - if (cmdp == 'i' || cmdp == 'I' ) { - flags |= FLAG_INTERACTIVE; - pnr++; - } - - cmdp = param_getchar(Cmd, pnr); - if (cmdp == 'x' || cmdp == 'X') { - flags |= FLAG_NR_AR_ATTACK; - pnr++; - } - - cmdp = param_getchar(Cmd, pnr); - if (cmdp == 'e' || cmdp == 'E') { - setEmulatorMem = true; - } - - PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A" - , exitAfterNReads, flags,flags); - - + // attack from file implies nr ar attack... + if (!(flags & FLAG_NR_AR_ATTACK) && attackFromFile) flags |= FLAG_NR_AR_ATTACK; + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; - memcpy(c.d.asBytes, uid, sizeof(uid)); - clearCommandBuffer(); - SendCommand(&c); + UsbCommand resp; - if(flags & FLAG_INTERACTIVE) { - UsbCommand resp; - PrintAndLog("Press pm3-button to abort simulation"); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - //We're waiting only 1.5 s at a time, otherwise we get the - // annoying message about "Waiting for a response... " + //get uid from file + if (attackFromFile) { + int count = 0; + // open file + f = fopen(filename, "r"); + if (f == NULL) { + PrintAndLog("File %s not found or locked", filename); + return 1; } - //got a response - if (flags & FLAG_NR_AR_ATTACK) { - nonces_t ar_resp[ATTACK_KEY_COUNT*2]; - uint64_t key = 0; - memcpy (ar_resp, resp.d.asBytes, sizeof(ar_resp)); - typedef struct { - uint64_t keyA; - uint32_t security; - uint64_t keyB; - } st_t; - st_t sector_trailer[ATTACK_KEY_COUNT]; - memset(sector_trailer, 0x00, sizeof(sector_trailer)); + while(!feof(f)){ + memset(buf, 0, sizeof(buf)); + memset(uidBuffer, 0, sizeof(uidBuffer)); - 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)); + if (fgets(buf, sizeof(buf), f) == NULL) { + if (count > 0) break; + + PrintAndLog("File reading error."); + fclose(f); + return 2; + } + + if (strlen(buf) < uidlen) { + if(strlen(buf) && feof(f)) + break; + PrintAndLog("File content error. Block data must include %d HEX symbols", uidlen); + fclose(f); + return 2; + } + + for (uint8_t i = 0; i < uidlen; i += 2) { + sscanf(&buf[i], "%02x", (unsigned int *)&uidBuffer[i / 2]); + } + + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" + , exitAfterNReads, flags, flags); - for (uint8_t i = 0; i 0) { - //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); - if (mfkey32(ar_resp[i], &key)) { - PrintAndLog("Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + memcpy(c.d.asBytes, uid, sizeof(uid)); + clearCommandBuffer(); + SendCommand(&c); - for (uint8_t ii = 0; ii0) { - //PrintAndLog ("block %d, keyA:%04x%08x, keyb:%04x%08x",stSector[i]*4+3, (uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); - uint8_t memBlock[16]; - memset(memBlock, 0x00, sizeof(memBlock)); - char cmd1[36]; - memset(cmd1,0x00,sizeof(cmd1)); - snprintf(cmd1,sizeof(cmd1),"%04x%08xFF078069%04x%08x",(uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); - PrintAndLog("Setting Emulator Memory Block %02d: [%s]",stSector[i]*4+3, cmd1); - if (param_gethex(cmd1, 0, memBlock, 32)) { - PrintAndLog("block data must include 32 HEX symbols"); - return 1; - } - - UsbCommand c = {CMD_MIFARE_EML_MEMSET, {(stSector[i]*4+3), 1, 0}}; - memcpy(c.d.asBytes, memBlock, 16); - clearCommandBuffer(); - SendCommand(&c); - } - } + + count++; + } + fclose(f); + } else { + + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" + , exitAfterNReads, flags, flags); + + memcpy(c.d.asBytes, uid, sizeof(uid)); + clearCommandBuffer(); + SendCommand(&c); + + if(flags & FLAG_INTERACTIVE) { + PrintAndLog("Press pm3-button to abort simulation"); + while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + //We're waiting only 1.5 s at a time, otherwise we get the + // annoying message about "Waiting for a response... " } - //moebius attack - for (uint8_t i = ATTACK_KEY_COUNT; i 0) { - if (tryMfk32_moebius(ar_resp[i], &key)) { - PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); - } - } + //got a response + if (flags & FLAG_NR_AR_ATTACK) { + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; + memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); + readerAttack(ar_resp, setEmulatorMem); } } } - + return 0; } diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index fcf34a73..942ef78b 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -192,7 +192,7 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { PrintAndLog("Could not create file name stats.txt"); return 1; } - fprintf(fout, "mfkey32,%d,%d,%s,%04x%08x,%.0Lf\r\n",counter,data.sector,(data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); fclose(fout); return isSuccess; } @@ -243,7 +243,7 @@ bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { PrintAndLog("Could not create file name stats.txt"); return 1; } - fprintf(fout, "moebius,%d,%d,%s,%04x%08x,%0.Lf\r\n",counter,data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); fclose(fout); return isSuccess; } From 73ab92d14c8d80f1313f54d9a9b939cd9452b91b Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sat, 25 Jun 2016 00:53:53 -0400 Subject: [PATCH 17/20] mf 1k sim reader attack cleanup add abort options - keyboard & button press. --- armsrc/iso14443a.c | 6 +++-- client/cmdhfmf.c | 62 ++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6216fc4a..d76bddd5 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2504,7 +2504,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * set_tracing(TRUE); bool finished = FALSE; - while (!BUTTON_PRESS() && !finished && !usb_poll_validate_length()) { + bool button_pushed = BUTTON_PRESS(); + while (!button_pushed && !finished && !usb_poll_validate_length()) { WDT_HIT(); // find reader field @@ -2956,6 +2957,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } } + button_pushed = BUTTON_PRESS(); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -2996,7 +2998,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK { //Send the collected ar_nr in the response - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_resp,sizeof(ar_nr_resp)); + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); } } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 05202ac5..07d2ab26 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1100,7 +1100,7 @@ int usage_hf14_mf1ksim(void) { PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory"); - PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f '"); + PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f ' (implies x and i)"); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); @@ -1109,6 +1109,7 @@ int usage_hf14_mf1ksim(void) { } int CmdHF14AMf1kSim(const char *Cmd) { + UsbCommand resp; uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; @@ -1182,12 +1183,9 @@ int CmdHF14AMf1kSim(const char *Cmd) { //Validations if(errors) return usage_hf14_mf1ksim(); - // attack from file implies nr ar attack... - if (!(flags & FLAG_NR_AR_ATTACK) && attackFromFile) flags |= FLAG_NR_AR_ATTACK; + // attack from file implies nr ar attack and interactive... + if (!(flags & FLAG_NR_AR_ATTACK) && attackFromFile) flags |= FLAG_NR_AR_ATTACK | FLAG_INTERACTIVE; - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; - UsbCommand resp; - //get uid from file if (attackFromFile) { int count = 0; @@ -1197,7 +1195,8 @@ int CmdHF14AMf1kSim(const char *Cmd) { PrintAndLog("File %s not found or locked", filename); return 1; } - while(!feof(f)){ + PrintAndLog("Loading file and simulating. Press keyboard to abort"); + while(!feof(f) && !ukbhit()){ memset(buf, 0, sizeof(buf)); memset(uidBuffer, 0, sizeof(uidBuffer)); @@ -1208,43 +1207,47 @@ int CmdHF14AMf1kSim(const char *Cmd) { fclose(f); return 2; } - - if (strlen(buf) < uidlen) { - if(strlen(buf) && feof(f)) - break; - PrintAndLog("File content error. Block data must include %d HEX symbols", uidlen); - fclose(f); - return 2; + if(strlen(buf) && feof(f)) break; + + uidlen = strlen(buf); + switch(uidlen) { + case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags = FLAG_7B_UID_IN_DATA; break; + case 8: flags = FLAG_4B_UID_IN_DATA; break; + default: + PrintAndLog("uid in file wrong length at %d",count); + fclose(f); + return 2; } - + for (uint8_t i = 0; i < uidlen; i += 2) { sscanf(&buf[i], "%02x", (unsigned int *)&uidBuffer[i / 2]); } - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" , exitAfterNReads, flags, flags); + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); - if(flags & FLAG_INTERACTIVE) { - PrintAndLog("Press pm3-button to abort simulation"); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - //We're waiting only 1.5 s at a time, otherwise we get the - // annoying message about "Waiting for a response... " - } - //got a response - if (flags & FLAG_NR_AR_ATTACK) { - nonces_t ar_resp[ATTACK_KEY_COUNT*2]; - memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); - readerAttack(ar_resp, setEmulatorMem); - } + while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + //We're waiting only 1.5 s at a time, otherwise we get the + // annoying message about "Waiting for a response... " + } + //got a response + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; + memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); + readerAttack(ar_resp, setEmulatorMem); + if (resp.arg[1]) { + PrintAndLog("Device button pressed - quitting"); + fclose(f); + return 4; } - count++; } fclose(f); @@ -1256,6 +1259,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" , exitAfterNReads, flags, flags); + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); From 76ef5273d84d043288e22c91d941558e75fcb793 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 27 Jun 2016 00:09:40 -0400 Subject: [PATCH 18/20] hf mf sim code cleanup - update changelog --- CHANGELOG.md | 31 +++++++++++------ armsrc/iso14443a.c | 83 +++++++++++++++++++++------------------------- client/cmdhfmf.c | 36 +++++++++++--------- 3 files changed, 77 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7055d087..b50083ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] ### Added +- Added lf pyramid commands (iceman) +- Added lf presco commands - some bits not fully understood... (iceman) - Added experimental HitagS support (Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg) see https://media.ccc.de/v/32c3-7166-sicherheit_von_125khz_transpondern_am_beispiel_hitag_s English video available @@ -16,8 +18,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `lf t55xx wipe` - sets t55xx back to factory defaults - Added viking demod to `lf search` (marshmellow) - `data askvikingdemod` demod viking id tag from graphbuffer (marshmellow) -- `lf t55xx resetread` added reset then read command - should allow determining start -of stream transmissions (marshmellow) +- `lf t55xx resetread` added reset then read command - should allow determining start of stream transmissions (marshmellow) - `lf t55xx wakeup` added wake with password (AOR) to allow lf search or standard lf read after (iceman, marshmellow) - `hf iclass managekeys` to save, load and manage iclass keys. (adjusted most commands to accept a loaded key in memory) (marshmellow) - `hf iclass readblk` to select, authenticate, and read 1 block from an iclass card (marshmellow) @@ -35,21 +36,29 @@ of stream transmissions (marshmellow) - Added option c to 'hf list' (mark CRC bytes) (piwi) ### Changed -- Added `[l] ` option to data printdemodbuffer -- Adjusted lf awid clone to optionally clone to Q5 tags -- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7 -- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal) -- Adjusted lf pskindalademod to reduce false positive reads. -- Small adjustments to psk, nrz, and ask clock detect routines - more reliable. -- Adjusted lf em410x em410xsim to accept a clock argument +- Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow) +- Fixed bug in lf viking clone/sim (iceman) +- Fixed broken `data askedgedetect` (marshmellow) +- Adjusted hf mf sim command (marshmellow) + added auto run mfkey32 to extract all keys + also added f parameter to allow attacking with UIDs from a file (implies x and i parameters) + also added e parameter to allow adding the extracted keys to emulator memory for the next simulation + added 10 byte uid option +- Added `[l] ` option to data printdemodbuffer (marshmellow) +- Adjusted lf awid clone to optionally clone to Q5 tags (marshmellow) +- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7 (marshmellow) +- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal) (marshmellow) +- Adjusted lf pskindalademod to reduce false positive reads. (marshmellow) +- Small adjustments to psk, nrz, and ask clock detect routines - more reliable. (marshmellow) +- Adjusted lf em410x em410xsim to accept a clock argument (marshmellow) - Adjusted lf t55xx dump to allow overriding the safety check and warning text (marshmellow) - Adjusted lf t55xx write input variables (marshmellow) - Adjusted lf t55xx read with password safety check and warning text and adjusted the input variables (marshmellow & iceman) -- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. +- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. (marshmellow) - Adjusted timings for t55xx commands. more reliable now. (marshmellow & iceman) - `lf cmdread` adjusted input methods and added help text (marshmellow & iceman) - changed `lf config t ` to be 0 - 128 and will trigger on + or - threshold value (marshmellow) -- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) +- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) (marshmellow) - Revised workflow for StandAloneMode14a (Craig Young) - EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers) - 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d76bddd5..f47c8a79 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2336,7 +2336,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * { int cardSTATE = MFEMUL_NOFIELD; int _UID_LEN = 0; // 4, 7, 10 - int _7BUID = 0; int vHf = 0; // in mV int res; uint32_t selTimer = 0; @@ -2360,14 +2359,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t response[MAX_MIFARE_FRAME_SIZE]; uint8_t response_par[MAX_MIFARE_PARITY_SIZE]; - uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID + uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! uint8_t rUIDBCC3[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; - uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; - uint8_t rSAK1[] = {0x04, 0xda, 0x17}; - uint8_t rSAK2[] = {0x04, 0xda, 0x17}; //need to look up + uint8_t rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated + uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; @@ -2375,8 +2373,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 // This will be used in the reader-only attack. - //allow collecting up to 8 sets of nonces to allow recovery of 8 keys - #define ATTACK_KEY_COUNT 8 + //allow collecting up to 8 sets of nonces to allow recovery of up to 8 keys + #define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); @@ -2404,7 +2402,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 7B uid comes from data-portion of packet memcpy(&rUIDBCC1[1],datain,3); memcpy(rUIDBCC2, datain+3, 4); - _7BUID = true; _UID_LEN = 7; } else if (flags & FLAG_10B_UID_IN_DATA) { memcpy(&rUIDBCC1[1], datain, 3); @@ -2414,8 +2411,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } else { // get UID from emul memory - guess at length emlGetMemBt(receivedCmd, 7, 1); - _7BUID = !(receivedCmd[0] == 0x00); - if (!_7BUID) { // ---------- 4BUID + if (receivedCmd[0] == 0x00) { // ---------- 4BUID emlGetMemBt(rUIDBCC1, 0, 4); _UID_LEN = 4; } else { // ---------- 7BUID @@ -2550,27 +2546,25 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } case MFEMUL_SELECT1:{ - // select all - if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { + // select all - 0x93 0x20 + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received"); EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); break; } - if (MF_DBGLEVEL >= 4 && len == 9 && receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 ) - { - Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); - } - // select card - // check correct sak values... (marshmellow) - if (len == 9 && - (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { + // select card - 0x93 0x70 ... + if (len == 9 && + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { + if (MF_DBGLEVEL >= 4) + Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + switch(_UID_LEN) { case 4: cardSTATE = MFEMUL_WORK; LED_B_ON(); if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); - EmSendCmd(rSAK, sizeof(rSAK)); + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); break; case 7: cardSTATE = MFEMUL_SELECT2; @@ -2578,7 +2572,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; case 10: cardSTATE = MFEMUL_SELECT2; - EmSendCmd(rSAK2, sizeof(rSAK2)); + EmSendCmd(rSAK1, sizeof(rSAK1)); break; default:break; } @@ -2592,16 +2586,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } + // select all cl3 - 0x97 0x20 if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x20)) { EmSendCmd(rUIDBCC3, sizeof(rUIDBCC3)); break; } + // select card cl3 - 0x97 0x70 if (len == 9 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC3, 4) == 0) ) { - EmSendCmd(rSAK2, sizeof(rSAK2)); + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); cardSTATE = MFEMUL_WORK; LED_B_ON(); if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol3 time: %d", GetTickCount() - selTimer); @@ -2611,8 +2607,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * break; } case MFEMUL_AUTH1:{ - if( len != 8) - { + if( len != 8) { cardSTATE_TO_IDLE(); LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; @@ -2621,7 +2616,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t nr = bytes_to_num(receivedCmd, 4); uint32_t ar = bytes_to_num(&receivedCmd[4], 4); - //Collect AR/NR per keytype & sector + // Collect AR/NR per keytype & sector if(flags & FLAG_NR_AR_ATTACK) { for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) { @@ -2639,7 +2634,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * ar_nr_resp[i+mM].nr = nr; ar_nr_resp[i+mM].ar = ar; nonce1_count++; - //add this nonce to first moebius nonce + // add this nonce to first moebius nonce ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid; ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC; ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY; @@ -2647,18 +2642,18 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr; ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar; ar_nr_collected[i+ATTACK_KEY_COUNT]++; - } else { //second nonce collect (std and moebius) + } else { // second nonce collect (std and moebius) ar_nr_resp[i+mM].nonce2 = nonce; ar_nr_resp[i+mM].nr2 = nr; ar_nr_resp[i+mM].ar2 = ar; if (!gettingMoebius) { nonce2_count++; - //check if this was the last second nonce we need for std attack + // check if this was the last second nonce we need for std attack if ( nonce2_count == nonce1_count ) { - //done collecting std test switch to moebius - //finish incrementing last sample + // done collecting std test switch to moebius + // first finish incrementing last sample ar_nr_collected[i+mM]++; - //switch to moebius collection + // switch to moebius collection gettingMoebius = true; mM = ATTACK_KEY_COUNT; nonce = nonce*7; @@ -2666,14 +2661,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } } else { moebius_n_count++; - //if we've collected all the nonces we need - finish. + // if we've collected all the nonces we need - finish. if (nonce1_count == moebius_n_count) finished = true; } } ar_nr_collected[i+mM]++; } - } else { //already collected 2 nonces for sector - dump out - //finished = true; } // we found right spot for this nonce stop looking break; @@ -2716,24 +2709,25 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (!len) { LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; - } - if (len == 2 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x20)) { + } + // select all cl2 - 0x95 0x20 + if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); break; } - // select 2 card + // select cl2 card - 0x95 0x70 xxxxxxxxxxxx if (len == 9 && - (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { - //which sak now? (marshmellow) - EmSendCmd(rSAK, sizeof(rSAK)); + (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { switch(_UID_LEN) { case 7: + EmSendCmd(rSAKfinal, sizeof(rSAKfinal)); cardSTATE = MFEMUL_WORK; LED_B_ON(); if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); break; case 10: + EmSendCmd(rSAK1, sizeof(rSAK1)); cardSTATE = MFEMUL_SELECT3; break; default:break; @@ -2963,8 +2957,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) - { + if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) { for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { if (ar_nr_collected[i] == 2) { Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); - if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK - { + if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK //Send the collected ar_nr in the response cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); } @@ -3004,7 +2996,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } - //----------------------------------------------------------------------------- // MIFARE sniffer. // diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 07d2ab26..9f337a5b 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1017,11 +1017,10 @@ int CmdHF14AMfChk(const char *Cmd) } void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { - #define ATTACK_KEY_COUNT 8 + #define ATTACK_KEY_COUNT 8 // keep same as define in iso14443a.c -> Mifare1ksim() uint64_t key = 0; typedef struct { uint64_t keyA; - uint32_t security; uint64_t keyB; } st_t; st_t sector_trailer[ATTACK_KEY_COUNT]; @@ -1034,9 +1033,9 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { for (uint8_t i = 0; i 0) { - //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + //PrintAndLog("DEBUG: Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); if (mfkey32(ar_resp[i], &key)) { - PrintAndLog("Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + PrintAndLog(" Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); for (uint8_t ii = 0; ii0) { - //PrintAndLog ("block %d, keyA:%04x%08x, keyb:%04x%08x",stSector[i]*4+3, (uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); uint8_t memBlock[16]; memset(memBlock, 0x00, sizeof(memBlock)); char cmd1[36]; @@ -1092,19 +1090,22 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { } int usage_hf14_mf1ksim(void) { - PrintAndLog("Usage: hf mf sim [h] u n i x"); + PrintAndLog("Usage: hf mf sim h u n i x"); PrintAndLog("options:"); PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID 4,7 bytes. If not specified, the UID 4b from emulator memory will be used"); + PrintAndLog(" u (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used"); PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); - PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory"); + PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory (implies x and i)"); PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f ' (implies x and i)"); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); - PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim f uids.txt"); + PrintAndLog(" hf mf sim u 0a0a0a0a e"); + return 0; } @@ -1132,6 +1133,9 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 'e': case 'E': setEmulatorMem = true; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; cmdp++; break; case 'f': @@ -1142,7 +1146,10 @@ int CmdHF14AMf1kSim(const char *Cmd) { return 0; } attackFromFile = true; - cmdp+=2; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; + cmdp += 2; break; case 'h': case 'H': @@ -1166,7 +1173,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 8: flags = FLAG_4B_UID_IN_DATA; break; default: return usage_hf14_mf1ksim(); } - cmdp +=2; + cmdp += 2; break; case 'x': case 'X': @@ -1183,9 +1190,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { //Validations if(errors) return usage_hf14_mf1ksim(); - // attack from file implies nr ar attack and interactive... - if (!(flags & FLAG_NR_AR_ATTACK) && attackFromFile) flags |= FLAG_NR_AR_ATTACK | FLAG_INTERACTIVE; - //get uid from file if (attackFromFile) { int count = 0; @@ -1243,7 +1247,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { nonces_t ar_resp[ATTACK_KEY_COUNT*2]; memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); readerAttack(ar_resp, setEmulatorMem); - if (resp.arg[1]) { + if ((bool)resp.arg[1]) { PrintAndLog("Device button pressed - quitting"); fclose(f); return 4; @@ -1251,7 +1255,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { count++; } fclose(f); - } else { + } else { //not from file PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): From 91f4d5312344aa536c585e00f1a91646c8cd7784 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Tue, 28 Jun 2016 21:02:26 -0400 Subject: [PATCH 19/20] couple bug fixes - clean up --- armsrc/iso14443a.c | 11 +++++------ client/cmdhfmf.c | 17 ++++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f47c8a79..70dc54f1 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2375,15 +2375,15 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //allow collecting up to 8 sets of nonces to allow recovery of up to 8 keys #define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() - nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types (nml, moebius) memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; //*2 for 2nd attack type (moebius) memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - bool gettingMoebius = false; uint8_t nonce1_count = 0; uint8_t nonce2_count = 0; uint8_t moebius_n_count = 0; + bool gettingMoebius = false; uint8_t mM = 0; //moebius_modifier for collection storage // Authenticate response - nonce @@ -2511,7 +2511,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE_TO_IDLE(); LED_A_ON(); } - } + } if (cardSTATE == MFEMUL_NOFIELD) continue; //Now, get data @@ -2523,7 +2523,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } else if (res == 1) { break; //return value 1 means button press } - + // REQ or WUP request in ANY state and WUP in HALTED state if (len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { selTimer = GetTickCount(); @@ -2992,7 +2992,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //Send the collected ar_nr in the response cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); } - } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 9f337a5b..43eca8cb 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1123,7 +1123,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { memset(filename, 0x00, sizeof(filename)); int len = 0; char buf[64]; - uint8_t uidBuffer[64]; uint8_t cmdp = 0; bool errors = false; @@ -1202,7 +1201,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { PrintAndLog("Loading file and simulating. Press keyboard to abort"); while(!feof(f) && !ukbhit()){ memset(buf, 0, sizeof(buf)); - memset(uidBuffer, 0, sizeof(uidBuffer)); + memset(uid, 0, sizeof(uid)); if (fgets(buf, sizeof(buf), f) == NULL) { if (count > 0) break; @@ -1211,21 +1210,21 @@ int CmdHF14AMf1kSim(const char *Cmd) { fclose(f); return 2; } - if(strlen(buf) && feof(f)) break; + if(!strlen(buf) && feof(f)) break; - uidlen = strlen(buf); + uidlen = strlen(buf)-1; switch(uidlen) { - case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete - case 14: flags = FLAG_7B_UID_IN_DATA; break; - case 8: flags = FLAG_4B_UID_IN_DATA; break; + case 20: flags |= FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags |= FLAG_7B_UID_IN_DATA; break; + case 8: flags |= FLAG_4B_UID_IN_DATA; break; default: - PrintAndLog("uid in file wrong length at %d",count); + PrintAndLog("uid in file wrong length at %d (length: %d) [%s]",count, uidlen, buf); fclose(f); return 2; } for (uint8_t i = 0; i < uidlen; i += 2) { - sscanf(&buf[i], "%02x", (unsigned int *)&uidBuffer[i / 2]); + sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]); } PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", From ef3f88bca9fbf8f228781f7e7b41fb6435130d84 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Thu, 28 Jul 2016 12:52:18 -0400 Subject: [PATCH 20/20] disable extra attack - disable stats.txt Moebius attack didn't yield any better results in my testing so disabling it, but allowing it to be re-enabled at will. also disabled the auto logging of all keys with uid delimited file stats.txt - can be uncommented when needed --- client/cmdhfmf.c | 5 +++-- client/nonce2key/nonce2key.c | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 43eca8cb..36c8e6c3 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1079,14 +1079,15 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { } } } - //moebius attack + /* + //un-comment to use as well moebius attack for (uint8_t i = ATTACK_KEY_COUNT; i 0) { if (tryMfk32_moebius(ar_resp[i], &key)) { PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); } } - } + }*/ } int usage_hf14_mf1ksim(void) { diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 942ef78b..5647c424 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -181,12 +181,12 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { if (counter==20) break; } } - //free(s); isSuccess = (counter == 1); t1 = clock() - t1; //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.0f ticks \nFound %d possible keys", (float)t1, counter); *outputkey = ( isSuccess ) ? outkey : 0; crypto1_destroy(s); + /* //un-comment to save all keys to a stats.txt file FILE *fout; if ((fout = fopen("stats.txt","ab")) == NULL) { PrintAndLog("Could not create file name stats.txt"); @@ -194,6 +194,7 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { } fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); fclose(fout); + */ return isSuccess; } @@ -205,7 +206,6 @@ bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { uint32_t nt0 = data.nonce; // first tag challenge (nonce) uint32_t nr0_enc = data.nr; // first encrypted reader challenge uint32_t ar0_enc = data.ar; // first encrypted reader response - //uint32_t uid1 = le32toh(data+16); uint32_t nt1 = data.nonce2; // second tag challenge (nonce) uint32_t nr1_enc = data.nr2; // second encrypted reader challenge uint32_t ar1_enc = data.ar2; // second encrypted reader response @@ -238,6 +238,7 @@ bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { //if ( t1 > 0 ) PrintAndLog("Time in mfkey32_moebius: %.0f ticks \nFound %d possible keys", (float)t1,counter); *outputkey = ( isSuccess ) ? outkey : 0; crypto1_destroy(s); + /* // un-comment to output all keys to stats.txt FILE *fout; if ((fout = fopen("stats.txt","ab")) == NULL) { PrintAndLog("Could not create file name stats.txt"); @@ -245,6 +246,7 @@ bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) { } fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); fclose(fout); + */ return isSuccess; }