diff --git a/CHANGELOG.md b/CHANGELOG.md index bb2952b9..a7c5fcbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] ### Added +- Added lf cotag read, and added it to lf search (iceman) - Added hitag2 read UID only and added that to lf search (marshmellow) - Added lf pyramid commands (iceman) - Added lf presco commands - some bits not fully understood... (iceman) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index aaa41f4a..ec133c7a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1028,6 +1028,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_VIKING_CLONE_TAG: CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]); break; + case CMD_COTAG: + Cotag(c->arg[0]); + break; #endif #ifdef WITH_HITAG diff --git a/armsrc/apps.h b/armsrc/apps.h index 4d4c8083..cbe3b239 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -89,6 +89,7 @@ void TurnReadLFOn(); //void T55xxReadTrace(void); void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode); +void Cotag(uint32_t arg0); /// iso14443.h void SimulateIso14443bTag(void); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 70dc54f1..83907fce 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2329,6 +2329,7 @@ typedef struct { * 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 + * FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack) *@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) */ @@ -2387,7 +2388,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint8_t mM = 0; //moebius_modifier for collection storage // Authenticate response - nonce - uint32_t nonce = bytes_to_num(rAUTH_NT, 4); + uint32_t nonce; + if (flags & FLAG_RANDOM_NONCE) { + nonce = prand(); + } else { + nonce = bytes_to_num(rAUTH_NT, 4); + } //-- Determine the UID // Can be set from emulator memory, incoming data @@ -2535,6 +2541,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * LED_C_OFF(); crypto1_destroy(pcs); cardAUTHKEY = 0xff; + if (flags & FLAG_RANDOM_NONCE) { + nonce = prand(); + } continue; } @@ -2656,7 +2665,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // switch to moebius collection gettingMoebius = true; mM = ATTACK_KEY_COUNT; - nonce = nonce*7; + if (flags & FLAG_RANDOM_NONCE) { + nonce = prand(); + } else { + nonce = nonce*7; + } break; } } else { diff --git a/armsrc/lfops.c b/armsrc/lfops.c index d607b0fd..0a8ce3a9 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1672,3 +1672,62 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); } +/* +Reading a COTAG. + +COTAG needs the reader to send a startsequence and the card has an extreme slow datarate. +because of this, we can "sample" the data signal but we interpreate it to Manchester direct. + +READER START SEQUENCE: +burst 800 us, gap 2.2 msecs +burst 3.6 msecs gap 2.2 msecs +burst 800 us gap 2.2 msecs +pulse 3.6 msecs + +This triggers a COTAG tag to response +*/ +void Cotag(uint32_t arg0) { + +#define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } +#define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } + + uint8_t rawsignal = arg0 & 0xF; + + LED_A_ON(); + + // Switching to LF image on FPGA. This might empty BigBuff + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + // Set up FPGA, 132kHz to power up the tag + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // start clock - 1.5ticks is 1us + StartTicks(); + + //send COTAG start pulse + ON(740) OFF + ON(3330) OFF + ON(740) OFF + ON(1000) + + switch(rawsignal) { + case 0: doCotagAcquisition(50000); break; + case 1: doCotagAcquisitionManchester(); break; + case 2: DoAcquisition_config(TRUE); break; + } + + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 88df543f..72aabe00 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -10,8 +10,9 @@ #include "apps.h" #include "util.h" #include "string.h" -#include "usb_cdc.h" // for usb_poll_validate_length #include "lfsampling.h" +#include "usb_cdc.h" // for usb_poll_validate_length +//#include "ticks.h" // for StartTicks sample_config config = { 1, 8, 1, 95, 0 } ; @@ -140,7 +141,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag uint32_t sample_total_numbers =0 ; uint32_t sample_total_saved =0 ; - while(!BUTTON_PRESS()) { + while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { WDT_HIT(); if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -237,7 +238,9 @@ uint32_t ReadLF(bool activeField, bool silent) **/ uint32_t SampleLF(bool printCfg) { - return ReadLF(true, printCfg); + uint32_t ret = ReadLF(true, printCfg); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return ret; } /** * Initializes the FPGA for snoop-mode (field off), and acquires the samples. @@ -246,7 +249,9 @@ uint32_t SampleLF(bool printCfg) uint32_t SnoopLF() { - return ReadLF(false, true); + uint32_t ret = ReadLF(false, true); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return ret; } /** @@ -315,3 +320,125 @@ void doT55x7Acquisition(size_t sample_size) { } } } + +/** +* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384 +* and is Manchester?, we directly gather the manchester data into bigbuff +**/ +#define COTAG_T1 384 +#define COTAG_T2 (COTAG_T1>>1) +#define COTAG_ONE_THRESHOLD 128+30 +#define COTAG_ZERO_THRESHOLD 128-30 +#ifndef COTAG_BITS +#define COTAG_BITS 264 +#endif +void doCotagAcquisition(size_t sample_size) { + + uint8_t *dest = BigBuf_get_addr(); + uint16_t bufsize = BigBuf_max_traceLen(); + + if ( bufsize > sample_size ) + bufsize = sample_size; + + dest[0] = 0; + uint8_t sample = 0, firsthigh = 0, firstlow = 0; + uint16_t i = 0; + + while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) ) { + WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); + } + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + LED_D_OFF(); + + // find first peak + if ( !firsthigh ) { + if (sample < COTAG_ONE_THRESHOLD) + continue; + firsthigh = 1; + } + if ( !firstlow ){ + if (sample > COTAG_ZERO_THRESHOLD ) + continue; + firstlow = 1; + } + + ++i; + + if ( sample > COTAG_ONE_THRESHOLD) + dest[i] = 255; + else if ( sample < COTAG_ZERO_THRESHOLD) + dest[i] = 0; + else + dest[i] = dest[i-1]; + } + } +} + +uint32_t doCotagAcquisitionManchester() { + + uint8_t *dest = BigBuf_get_addr(); + uint16_t bufsize = BigBuf_max_traceLen(); + + if ( bufsize > COTAG_BITS ) + bufsize = COTAG_BITS; + + dest[0] = 0; + uint8_t sample = 0, firsthigh = 0, firstlow = 0; + uint16_t sample_counter = 0, period = 0; + uint8_t curr = 0, prev = 0; + + while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) ) { + WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); + } + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + LED_D_OFF(); + + // find first peak + if ( !firsthigh ) { + if (sample < COTAG_ONE_THRESHOLD) + continue; + firsthigh = 1; + } + + if ( !firstlow ){ + if (sample > COTAG_ZERO_THRESHOLD ) + continue; + firstlow = 1; + } + + // set sample 255, 0, or previous + if ( sample > COTAG_ONE_THRESHOLD){ + prev = curr; + curr = 1; + } + else if ( sample < COTAG_ZERO_THRESHOLD) { + prev = curr; + curr = 0; + } + else { + curr = prev; + } + + // full T1 periods, + if ( period > 0 ) { + --period; + continue; + } + + dest[sample_counter] = curr; + ++sample_counter; + period = COTAG_T1; + } + } + return sample_counter; +} diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index bd8ad1d0..ba4fc3f7 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -1,6 +1,13 @@ #ifndef LFSAMPLING_H #define LFSAMPLING_H +/** +* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 +* and is Manchester?, we directly gather the manchester data into bigbuff +**/ +void doCotagAcquisition(size_t sample_size); +uint32_t doCotagAcquisitionManchester(void); + /** * acquisition of T55x7 LF signal. Similart to other LF, but adjusted with @marshmellows thresholds * the data is collected in BigBuf. diff --git a/armsrc/util.c b/armsrc/util.c index 1dd8dc75..a0fa50d3 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -345,7 +345,7 @@ void StartCountUS() } uint32_t RAMFUNC GetCountUS(){ - return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); + return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10); } static uint32_t GlobalUsCounter = 0; @@ -418,8 +418,13 @@ void StartCountSspClk() // we can use the counter. while (AT91C_BASE_TC0->TC_CV < 0xFFF0); } - - +void ResetSspClk(void) { + //enable clock of timer and software trigger + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC2->TC_CV > 0); +} uint32_t RAMFUNC GetCountSspClk(){ uint32_t tmp_count; tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; @@ -431,3 +436,80 @@ uint32_t RAMFUNC GetCountSspClk(){ } } +// ------------------------------------------------------------------------- +// Timer for bitbanging, or LF stuff when you need a very precis timer +// 1us = 1.5ticks +// ------------------------------------------------------------------------- +void StartTicks(void){ + //initialization of the timer + // tc1 is higher 0xFFFF0000 + // tc0 is lower 0x0000FFFF + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 + AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR | + AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; + AT91C_BASE_TC0->TC_RA = 1; + AT91C_BASE_TC0->TC_RC = 0; + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from TC0 + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TCB->TCB_BCR = 1; + + // wait until timer becomes zero. + while (AT91C_BASE_TC1->TC_CV > 0); +} + +// Wait - Spindelay in ticks. +// if called with a high number, this will trigger the WDT... +void WaitTicks(uint32_t ticks){ + if ( ticks == 0 ) return; + ticks += GET_TICKS; + while (GET_TICKS < ticks); +} +// Wait / Spindelay in us (microseconds) +// 1us = 1.5ticks. +void WaitUS(uint16_t us){ + if ( us == 0 ) return; + WaitTicks( (uint32_t)(us * 1.5) ); +} +void WaitMS(uint16_t ms){ + if (ms == 0) return; + WaitTicks( (uint32_t)(ms * 1500) ); +} +// Starts Clock and waits until its reset +void ResetTicks(void){ + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC1->TC_CV > 0); +} +void ResetTimer(AT91PS_TC timer){ + timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while(timer->TC_CV > 0) ; +} +// stop clock +void StopTicks(void){ + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; +} + +static uint64_t next_random = 1; + +/* Generates a (non-cryptographically secure) 32-bit random number. + * + * We don't have an implementation of the "rand" function or a clock to seed it + * with, so we just call GetTickCount the first time to seed ourselves. + */ +uint32_t prand() { + if (next_random == 1) { + next_random = GetTickCount(); + } + + next_random = next_random * 6364136223846793005 + 1; + return (uint32_t)(next_random >> 32) % 0xffffffff; +} + diff --git a/armsrc/util.h b/armsrc/util.h index bf5d0cc8..0148e1dd 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -36,14 +36,20 @@ void rol(uint8_t *data, const size_t len); void lsl (uint8_t *data, size_t len); int32_t le24toh (uint8_t data[3]); -void SpinDelay(int ms); -void SpinDelayUs(int us); void LED(int led, int ms); void LEDsoff(); int BUTTON_CLICKED(int ms); int BUTTON_HELD(int ms); void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); +//iceman's ticks.h +#ifndef GET_TICKS +# define GET_TICKS (uint32_t)((AT91C_BASE_TC1->TC_CV << 16) | AT91C_BASE_TC0->TC_CV) +#endif + +void SpinDelay(int ms); +void SpinDelayUs(int us); + void StartTickCount(); uint32_t RAMFUNC GetTickCount(); @@ -52,6 +58,18 @@ uint32_t RAMFUNC GetCountUS(); uint32_t RAMFUNC GetDeltaCountUS(); void StartCountSspClk(); +void ResetSspClk(void); uint32_t RAMFUNC GetCountSspClk(); +extern void StartTicks(void); +extern void WaitTicks(uint32_t ticks); +extern void WaitUS(uint16_t us); +extern void WaitMS(uint16_t ms); +extern void ResetTicks(); +extern void ResetTimer(AT91PS_TC timer); +extern void StopTicks(void); +// end iceman's ticks.h + +uint32_t prand(); + #endif diff --git a/client/Makefile b/client/Makefile index 8dd8ddef..7f5ba2f3 100644 --- a/client/Makefile +++ b/client/Makefile @@ -19,6 +19,7 @@ CFLAGS = -std=c99 -I. -I../include -I../common -I../zlib -I/opt/local/include -I LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) + CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw @@ -102,6 +103,7 @@ CMDSRCS = nonce2key/crapto1.c\ cmdlfviking.c\ cmdlfpresco.c\ cmdlfpyramid.c\ + cmdlfcotag.c\ pm3_binlib.c\ scripting.c\ cmdscript.c\ diff --git a/client/cmddata.c b/client/cmddata.c index 86dac423..2db1f8eb 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -317,7 +317,7 @@ int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, int clk=0; int maxErr=100; int maxLen=0; - uint8_t askAmp = 0; + uint8_t askamp = 0; char amp = param_getchar(Cmd, 0); uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; sscanf(Cmd, "%i %i %i %i %c", &clk, &invert, &maxErr, &maxLen, &); @@ -330,12 +330,15 @@ int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, invert=1; clk=0; } - if (amp == 'a' || amp == 'A') askAmp=1; size_t BitLen = getFromGraphBuf(BitStream); if (g_debugMode) PrintAndLog("DEBUG: Bitlen from grphbuff: %d",BitLen); if (BitLen < 255) return 0; if (maxLen < BitLen && maxLen != 0) BitLen = maxLen; int foundclk = 0; + //amp before ST check + if (amp == 'a' || amp == 'A') { + askAmp(BitStream, BitLen); + } bool st = false; if (*stCheck) st = DetectST(BitStream, &BitLen, &foundclk); if (st) { @@ -343,7 +346,7 @@ int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, clk = (clk == 0) ? foundclk : clk; if (verbose || g_debugMode) PrintAndLog("\nFound Sequence Terminator"); } - int errCnt = askdemod(BitStream, &BitLen, &clk, &invert, maxErr, askAmp, askType); + int errCnt = askdemod(BitStream, &BitLen, &clk, &invert, maxErr, askamp, askType); if (errCnt<0 || BitLen<16){ //if fatal error (or -1) if (g_debugMode) PrintAndLog("DEBUG: no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); return 0; @@ -383,7 +386,7 @@ int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) { int Cmdaskmandemod(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 45 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); PrintAndLog(" ['s'] optional, check for Sequence Terminator"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); @@ -678,7 +681,7 @@ int CmdVikingDemod(const char *Cmd) int Cmdaskrawdemod(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 35 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod ar [clock] [maxError] [maxLen] [amplify]"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); PrintAndLog(" , 1 to invert output"); @@ -1012,7 +1015,7 @@ int FSKrawDemod(const char *Cmd, bool verbose) int CmdFSKrawdemod(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 20 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod fs [clock] [fchigh] [fclow]"); PrintAndLog(" [set clock as integer] optional, omit for autodetect."); PrintAndLog(" , 1 for invert output, can be used even if the clock is omitted"); @@ -1769,7 +1772,7 @@ int NRZrawDemod(const char *Cmd, bool verbose) int CmdNRZrawDemod(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod nr [clock] <0|1> [maxError]"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); PrintAndLog(" , 1 for invert output"); @@ -1793,7 +1796,7 @@ int CmdPSK1rawDemod(const char *Cmd) { int ans; char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod p1 [clock] <0|1> [maxError]"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); PrintAndLog(" , 1 for invert output"); @@ -1825,7 +1828,7 @@ int CmdPSK2rawDemod(const char *Cmd) { int ans=0; char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data rawdemod p2 [clock] <0|1> [maxError]"); PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); PrintAndLog(" , 1 for invert output"); @@ -1855,7 +1858,7 @@ int CmdRawDemod(const char *Cmd) { char cmdp = Cmd[0]; //param_getchar(Cmd, 0); - if (strlen(Cmd) > 20 || cmdp == 'h' || cmdp == 'H' || strlen(Cmd)<2) { + if (strlen(Cmd) > 35 || cmdp == 'h' || cmdp == 'H' || strlen(Cmd)<2) { PrintAndLog("Usage: data rawdemod [modulation] |"); PrintAndLog(" [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); PrintAndLog(" 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 36c8e6c3..cdac6476 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1016,7 +1016,7 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } -void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { +void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { #define ATTACK_KEY_COUNT 8 // keep same as define in iso14443a.c -> Mifare1ksim() uint64_t key = 0; typedef struct { @@ -1034,7 +1034,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { for (uint8_t i = 0; i 0) { //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)) { + if (doStandardAttack && 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; ii' (implies x and i)"); + PrintAndLog(" r (Optional) Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works."); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); @@ -1164,6 +1193,11 @@ int CmdHF14AMf1kSim(const char *Cmd) { exitAfterNReads = param_get8(Cmd, pnr+1); cmdp += 2; break; + case 'r': + case 'R': + flags |= FLAG_RANDOM_NONCE; + cmdp++; + break; case 'u': case 'U': param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); @@ -1246,7 +1280,8 @@ int CmdHF14AMf1kSim(const char *Cmd) { //got a response nonces_t ar_resp[ATTACK_KEY_COUNT*2]; memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); - readerAttack(ar_resp, setEmulatorMem); + // We can skip the standard attack if we have RANDOM_NONCE set. + readerAttack(ar_resp, setEmulatorMem, !(flags & FLAG_RANDOM_NONCE)); if ((bool)resp.arg[1]) { PrintAndLog("Device button pressed - quitting"); fclose(f); @@ -1278,7 +1313,8 @@ int CmdHF14AMf1kSim(const char *Cmd) { 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); + // We can skip the standard attack if we have RANDOM_NONCE set. + readerAttack(ar_resp, setEmulatorMem, !(flags & FLAG_RANDOM_NONCE)); } } } diff --git a/client/cmdlf.c b/client/cmdlf.c index 2000f6d0..34104518 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -33,6 +33,8 @@ #include "cmdlfpcf7931.h"// for pcf7931 menu #include "cmdlfpyramid.h"// for pyramid menu #include "cmdlfviking.h" // for viking menu +#include "cmdlfcotag.h" // for COTAG menu + static int CmdHelp(const char *Cmd); @@ -1080,6 +1082,7 @@ int CmdVchDemod(const char *Cmd) int CmdLFfind(const char *Cmd) { int ans=0; + size_t minLength = 1000; char cmdp = param_getchar(Cmd, 0); char testRaw = param_getchar(Cmd, 1); if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') { @@ -1098,7 +1101,7 @@ int CmdLFfind(const char *Cmd) if (!offline && (cmdp != '1')){ CmdLFRead("s"); getSamples("30000",false); - } else if (GraphTraceLen < 1000) { + } else if (GraphTraceLen < minLength) { PrintAndLog("Data in Graphbuffer was too small."); return 0; } @@ -1108,6 +1111,24 @@ int CmdLFfind(const char *Cmd) PrintAndLog("False Positives ARE possible\n"); PrintAndLog("\nChecking for known tags:\n"); + size_t testLen = minLength; + // only run if graphbuffer is just noise as it should be for hitag/cotag + if (graphJustNoise(GraphBuffer, testLen)) { + // only run these tests if we are in online mode + if (!offline && (cmdp != '1')){ + ans=CmdLFHitagReader("26"); + if (ans==0) { + return 1; + } + ans=CmdCOTAGRead(""); + if (ans>0){ + PrintAndLog("\nValid COTAG ID Found!"); + return 1; + } + } + return 0; + } + ans=CmdFSKdemodIO(""); if (ans>0) { PrintAndLog("\nValid IO Prox ID Found!"); @@ -1180,13 +1201,6 @@ int CmdLFfind(const char *Cmd) return 1; } - if (!offline && (cmdp != '1')){ - ans=CmdLFHitagReader("26"); - if (ans==0) { - return 1; - } - } - PrintAndLog("\nNo Known Tags Found!\n"); if (testRaw=='u' || testRaw=='U'){ //test unknown tag formats (raw mode) @@ -1224,6 +1238,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"awid", CmdLFAWID, 1, "{ AWID RFIDs... }"}, + {"cotag", CmdLFCOTAG, 1, "{ COTAG RFIDs... }"}, {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"}, {"hid", CmdLFHID, 1, "{ HID RFIDs... }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"}, diff --git a/client/cmdlfcotag.c b/client/cmdlfcotag.c new file mode 100644 index 00000000..f10516a6 --- /dev/null +++ b/client/cmdlfcotag.c @@ -0,0 +1,120 @@ +//----------------------------------------------------------------------------- +// Authored by Iceman +// +// 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 COTAG commands +//----------------------------------------------------------------------------- +#include "cmdlfcotag.h" // COTAG function declarations + +static int CmdHelp(const char *Cmd); + +int usage_lf_cotag_read(void){ + PrintAndLog("Usage: lf COTAG read [h] "); + PrintAndLog("Options:"); + PrintAndLog(" h : This help"); + PrintAndLog(" <0|1|2> : 0 - HIGH/LOW signal; maxlength bigbuff"); + PrintAndLog(" : 1 - translation of HI/LO into bytes with manchester 0,1"); + PrintAndLog(" : 2 - raw signal; maxlength bigbuff"); + PrintAndLog(""); + PrintAndLog("Sample:"); + PrintAndLog(" lf cotag read 0"); + PrintAndLog(" lf cotag read 1"); + return 0; +} + +// COTAG demod should be able to use GraphBuffer, +// when data load samples +int CmdCOTAGDemod(const char *Cmd) { + + uint8_t bits[COTAG_BITS] = {0}; + size_t bitlen = COTAG_BITS; + memcpy(bits, DemodBuffer, COTAG_BITS); + + int err = manrawdecode(bits, &bitlen, 1); + if (err){ + if (g_debugMode) PrintAndLog("DEBUG: Error - COTAG too many errors: %d", err); + return -1; + } + + setDemodBuf(bits, bitlen, 0); + + //got a good demod + uint16_t cn = bytebits_to_byteLSBF(bits+1, 16); + uint32_t fc = bytebits_to_byteLSBF(bits+1+16, 8); + + uint32_t raw1 = bytebits_to_byteLSBF(bits, 32); + uint32_t raw2 = bytebits_to_byteLSBF(bits+32, 32); + uint32_t raw3 = bytebits_to_byteLSBF(bits+64, 32); + uint32_t raw4 = bytebits_to_byteLSBF(bits+96, 32); + + /* + fc 161: 1010 0001 -> LSB 1000 0101 + cn 33593 1000 0011 0011 1001 -> LSB 1001 1100 1100 0001 + cccc cccc cccc cccc ffffffff + 0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000 + 1001 1100 1100 0001 10000101 + */ + PrintAndLog("COTAG Found: FC %u, CN: %u Raw: %08X%08X%08X%08X", fc, cn, raw1 ,raw2, raw3, raw4); + return 1; +} + +// When reading a COTAG. +// 0 = HIGH/LOW signal - maxlength bigbuff +// 1 = translation for HI/LO into bytes with manchester 0,1 - length 300 +// 2 = raw signal - maxlength bigbuff +int CmdCOTAGRead(const char *Cmd) { + + if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_lf_cotag_read(); + + uint32_t rawsignal = 1; + sscanf(Cmd, "%u", &rawsignal); + + UsbCommand c = {CMD_COTAG, {rawsignal, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + if ( !WaitForResponseTimeout(CMD_ACK, NULL, 7000) ) { + PrintAndLog("command execution time out"); + return -1; + } + + switch ( rawsignal ){ + case 0: + case 2: { + CmdPlot(""); + CmdGrid("384"); + getSamples("", true); break; + } + case 1: { + GetFromBigBuf(DemodBuffer, COTAG_BITS, 0); + DemodBufferLen = COTAG_BITS; + UsbCommand response; + if ( !WaitForResponseTimeout(CMD_ACK, &response, 1000) ) { + PrintAndLog("timeout while waiting for reply."); + return -1; + } + return CmdCOTAGDemod(""); + } + } + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdCOTAGDemod, 1, "Tries to decode a COTAG signal"}, + {"read", CmdCOTAGRead, 0, "Attempt to read and extract tag data"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFCOTAG(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfcotag.h b/client/cmdlfcotag.h new file mode 100644 index 00000000..c46348e4 --- /dev/null +++ b/client/cmdlfcotag.h @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Authored by Iceman +// +// 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 COTAG commands +//----------------------------------------------------------------------------- + +#ifndef CMDLFCOTAG_H__ +#define CMDLFCOTAG_H__ + +#include "proxmark3.h"// Definitions, USB controls, COTAG_BITS +#include "util.h" // FALSE / TRUE +#include "cmddata.h" // getSamples +#include "cmdparser.h"// CmdsParse, CmdsHelp +#include "cmdmain.h" +#include "ui.h" // PrintAndLog +#include "cmdlf.h" // Setconfig +#include "lfdemod.h" // manrawdecode, bytebits_tobyteLSBF + +#ifndef COTAG_BITS +#define COTAG_BITS 264 +#endif + +int CmdLFCOTAG(const char *Cmd); +int CmdCOTAGRead(const char *Cmd); +int CmdCOTAGDemod(const char *Cmd); + +int usage_lf_cotag_read(void); +#endif diff --git a/client/graph.c b/client/graph.c index 319cde39..d216a8f2 100644 --- a/client/graph.c +++ b/client/graph.c @@ -268,3 +268,13 @@ uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose) } return 1; } +bool graphJustNoise(int *BitStream, int size) +{ + static const uint8_t THRESHOLD = 15; //might not be high enough for noisy environments + //test samples are not just noise + bool justNoise1 = 1; + for(int idx=0; idx < size && justNoise1 ;idx++){ + justNoise1 = BitStream[idx] < THRESHOLD; + } + return justNoise1; +} diff --git a/client/graph.h b/client/graph.h index 8deeb386..6f3f600d 100644 --- a/client/graph.h +++ b/client/graph.h @@ -22,6 +22,7 @@ uint8_t GetPskCarrier(const char str[], bool printAns, bool verbose); uint8_t GetNrzClock(const char str[], bool printAns, bool verbose); uint8_t GetFskClock(const char str[], bool printAns, bool verbose); uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose); +bool graphJustNoise(int *BitStream, int size); void setGraphBuf(uint8_t *buff, size_t size); void save_restoreGB(uint8_t saveOpt); diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index bdf18912..ae1f0586 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -87,6 +87,7 @@ typedef struct { #define CMD_AWID_DEMOD_FSK 0x0221 #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 +#define CMD_COTAG 0x0225 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index fcf0f07c..2a97196a 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -58,6 +58,7 @@ local _commands = { CMD_AWID_DEMOD_FSK = 0x0221, CMD_VIKING_CLONE_TAG = 0x0223, CMD_T55XX_WAKEUP = 0x0224, + CMD_COTAG = 0x0225, --/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ --// For the 13.56 MHz tags diff --git a/common/lfdemod.c b/common/lfdemod.c index 7d40df3a..8324c440 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -270,7 +270,7 @@ void askAmp(uint8_t *BitStream, size_t size) } return; } - + //by marshmellow //attempts to demodulate ask modulations, askType == 0 for ask/raw, askType==1 for ask/manchester int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType) @@ -280,7 +280,7 @@ int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr if (*clk==0 || start < 0) return -3; if (*invert != 1) *invert = 0; if (amp==1) askAmp(BinStream, *size); - if (g_debugMode==2) prnt("DEBUG ASK: clk %d, beststart %d", *clk, start); + if (g_debugMode==2) prnt("DEBUG ASK: clk %d, beststart %d, amp %d", *clk, start, amp); uint8_t initLoopMax = 255; if (initLoopMax > *size) initLoopMax = *size; @@ -1555,8 +1555,8 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { int tol = 0; int i, j, skip, start, end, low, high, minClk, waveStart; bool complete = false; - int tmpbuff[bufsize / 64]; - int waveLen[bufsize / 64]; + int tmpbuff[bufsize / 32]; //guess rf/32 clock, if click is smaller we will only have room for a fraction of the samples captured + int waveLen[bufsize / 32]; // if clock is larger then we waste memory in array size that is not needed... size_t testsize = (bufsize < 512) ? bufsize : 512; int phaseoff = 0; high = low = 128; @@ -1588,7 +1588,7 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { waveStart = i; while ((buffer[i] > low) && (i < bufsize)) ++i; - if (j >= (bufsize/64)) { + if (j >= (bufsize/32)) { break; } waveLen[j] = i - waveStart; //first high to first low @@ -1634,6 +1634,8 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { if (start < 0) { if (g_debugMode==2) prnt("DEBUG STT: first STT not found - quitting"); return false; + } else { + if (g_debugMode==2) prnt("DEBUG STT: first STT found at: %d, j=%d",start, j); } if (waveLen[i+2] > clk*1+tol) phaseoff = 0; @@ -1647,7 +1649,7 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { end = skip; for (i += 3; i < j - 4; ++i) { end += tmpbuff[i]; - if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol) { //1 to 2 clocks depending on 2 bits prior + if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol && waveLen[i] < clk+tol) { //1 to 2 clocks depending on 2 bits prior if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol && waveLen[i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2 if (tmpbuff[i+2] >= (clk*3)/2-tol && tmpbuff[i+2] <= clk*2+tol && waveLen[i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave if (tmpbuff[i+3] >= clk*1-tol && tmpbuff[i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit @@ -1669,12 +1671,15 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { start = skip; size_t datalen = end - start; // check validity of datalen (should be even clock increments) - use a tolerance of up to 1/8th a clock - if (datalen % clk > clk/8) { + if ( clk - (datalen % clk) <= clk/8) { + // padd the amount off - could be problematic... but shouldn't happen often + datalen += clk - (datalen % clk); + } else if ( (datalen % clk) <= clk/8 ) { + // padd the amount off - could be problematic... but shouldn't happen often + datalen -= datalen % clk; + } else { if (g_debugMode==2) prnt("DEBUG STT: datalen not divisible by clk: %u %% %d = %d - quitting", datalen, clk, datalen % clk); return false; - } else { - // padd the amount off - could be problematic... but shouldn't happen often - datalen += datalen % clk; } // if datalen is less than one t55xx block - ERROR if (datalen/clk < 8*4) { @@ -1682,8 +1687,20 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { return false; } size_t dataloc = start; + if (buffer[dataloc-(clk*4)-(clk/8)] <= low && buffer[dataloc] <= low && buffer[dataloc-(clk*4)] >= high) { + //we have low drift (and a low just before the ST and a low just after the ST) - compensate by backing up the start + for ( i=0; i <= (clk/8); ++i ) { + if ( buffer[dataloc - (clk*4) - i] <= low ) { + dataloc -= i; + break; + } + } + } + size_t newloc = 0; i=0; + if (g_debugMode==2) prnt("DEBUG STT: Starting STT trim - start: %d, datalen: %d ",dataloc, datalen); + // 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 due to signal loss... (and we cut out the start of wave high part) @@ -1697,11 +1714,12 @@ bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { if (i+newloc < dataloc) buffer[i+newloc] = buffer[dataloc]; - dataloc++; + dataloc++; } } newloc += i; //skip next ST - we just assume it will be there from now on... + if (g_debugMode==2) prnt("DEBUG STT: skipping STT at %d to %d", dataloc, dataloc+(clk*4)); dataloc += clk*4; } *size = newloc; diff --git a/common/lfdemod.h b/common/lfdemod.h index 56c758ae..b988c1bf 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -19,6 +19,7 @@ //generic size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType); int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType); +void askAmp(uint8_t *BitStream, size_t size); int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert); uint32_t bytebits_to_byte(uint8_t* src, size_t numbits); uint32_t bytebits_to_byteLSBF(uint8_t* src, size_t numbits); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 66e6cf91..d3ff0ec6 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -101,6 +101,7 @@ typedef struct{ #define CMD_AWID_DEMOD_FSK 0x0221 #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 +#define CMD_COTAG 0x0225 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ @@ -217,6 +218,7 @@ typedef struct{ #define FLAG_7B_UID_IN_DATA 0x04 #define FLAG_10B_UID_IN_DATA 0x08 #define FLAG_NR_AR_ATTACK 0x10 +#define FLAG_RANDOM_NONCE 0x20 //Iclass reader flags