diff --git a/client/Makefile b/client/Makefile index 79e0cc31..ac7e6f98 100644 --- a/client/Makefile +++ b/client/Makefile @@ -58,7 +58,7 @@ CORESRCS = uart.c \ CMDSRCS = crapto1/crapto1.c\ crapto1/crypto1.c\ - nonce2key/nonce2key.c\ + nonce2key.c\ loclass/cipher.c \ loclass/cipherutils.c \ loclass/des.c \ diff --git a/client/cmddata.c b/client/cmddata.c index e07e7223..983edd72 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -29,6 +29,9 @@ uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t g_debugMode=0; size_t DemodBufferLen=0; +//size_t g_demodStartIdx=0; +//uint8_t g_demodClock=0; + static int CmdHelp(const char *Cmd); //set the demod buffer with given array of binary (one bit per byte) @@ -253,6 +256,7 @@ void printEM410x(uint32_t hi, uint64_t id) return; } +//should be moved to cmdlfem4x.c int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) { size_t idx = 0; @@ -274,7 +278,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) } return 0; } - +//should be moved to cmdlfem4x.c int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose) { bool st = true; @@ -282,6 +286,7 @@ int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose) return AskEm410xDecode(verbose, hi, lo); } +//should be moved to cmdlfem4x.c //by marshmellow //takes 3 arguments - clock, invert and maxErr as integers //attempts to demodulate ask while decoding manchester @@ -451,7 +456,8 @@ int Cmdmandecoderaw(const char *Cmd) sscanf(Cmd, "%i %i", &invert, &maxErr); size=i; - errCnt=manrawdecode(BitStream, &size, invert); + uint8_t alignPos = 0; + errCnt=manrawdecode(BitStream, &size, invert, &alignPos); if (errCnt>=maxErr){ PrintAndLog("Too many errors: %d",errCnt); return 0; @@ -590,6 +596,7 @@ int Cmdaskbiphdemod(const char *Cmd) return ASKbiphaseDemod(Cmd, true); } +//could be split to a gProxII file //by marshmellow //attempts to demodulate and identify a G_Prox_II verex/chubb card //WARNING: if it fails during some points it will destroy the DemodBuffer data @@ -655,6 +662,7 @@ int CmdG_Prox_II_Demod(const char *Cmd) return 1; } +//could be moved to a viking file //by marshmellow //see ASKDemod for what args are accepted int CmdVikingDemod(const char *Cmd) @@ -1038,6 +1046,7 @@ int CmdFSKrawdemod(const char *Cmd) return FSKrawDemod(Cmd, true); } +//move to cmdlfhid.c //by marshmellow (based on existing demod + holiman's refactor) //HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded) //print full HID Prox ID and some bit format details if found @@ -1124,6 +1133,7 @@ int CmdFSKdemodHID(const char *Cmd) return 1; } + //by marshmellow //Paradox Prox demod - FSK RF/50 with preamble of 00001111 (then manchester encoded) //print full Paradox Prox ID and some bit format details if found @@ -1751,7 +1761,8 @@ int NRZrawDemod(const char *Cmd, bool verbose) size_t BitLen = getFromGraphBuf(BitStream); if (BitLen==0) return 0; int errCnt=0; - errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert); + int clkStartIdx = 0; + errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert, &clkStartIdx); if (errCnt > maxErr){ if (g_debugMode) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); return 0; @@ -2264,13 +2275,13 @@ int CmdDirectionalThreshold(const char *Cmd) if (GraphBuffer[i] >= upThres && GraphBuffer[i] > lastValue) { lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it. - GraphBuffer[i] = 1; + GraphBuffer[i] = 127; } // Apply second threshold to samples heading down else if (GraphBuffer[i] <= downThres && GraphBuffer[i] < lastValue) { lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it. - GraphBuffer[i] = -1; + GraphBuffer[i] = -127; } else { diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index b3f7acb2..47660a6e 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -19,91 +19,35 @@ #include "ui.h" #include "mifarehost.h" #include "mifare.h" -#include "nonce2key/nonce2key.h" +#include "nonce2key.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up static int CmdHelp(const char *Cmd); + int CmdHF14AMifare(const char *Cmd) { - uint32_t uid = 0; - uint32_t nt = 0, nr = 0; - uint64_t par_list = 0, ks_list = 0, r_key = 0; - int16_t isOK = 0; + int isOK = 0; + uint64_t key = 0; - UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; - - // message - printf("-------------------------------------------------------------------------\n"); - printf("Executing command. Expected execution time: 25sec on average :-)\n"); - printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); - printf("-------------------------------------------------------------------------\n"); - - - start: - clearCommandBuffer(); - SendCommand(&c); - - //flush queue - while (ukbhit()) { - int c = getchar(); (void) c; - } - - // wait cycle - while (true) { - printf("."); - fflush(stdout); - if (ukbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { - isOK = resp.arg[0]; - uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); - nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); - par_list = bytes_to_num(resp.d.asBytes + 8, 8); - ks_list = bytes_to_num(resp.d.asBytes + 16, 8); - nr = bytes_to_num(resp.d.asBytes + 24, 4); - printf("\n\n"); - switch (isOK) { - case -1 : PrintAndLog("Button pressed. Aborted.\n"); break; - case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break; - case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break; - case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown"); - PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour.\n"); break; - default: ; - } - break; - } - } - - printf("\n"); - - // error - if (isOK != 1) return 1; - - // execute original function from util nonce2key - if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { - isOK = 2; - PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); - PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); - c.arg[0] = false; - goto start; - } else { - isOK = 0; - printf("------------------------------------------------------------------\n"); - PrintAndLog("Found valid key:%012" PRIx64 " \n", r_key); + isOK = mfDarkside(&key); + switch (isOK) { + case -1 : PrintAndLog("Button pressed. Aborted."); return 1; + case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)."); return 1; + case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable)."); return 1; + case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown"); + PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour."); return 1; + case -5 : PrintAndLog("Aborted via keyboard."); return 1; + default : PrintAndLog("Found valid key:%012" PRIx64 "\n", key); } PrintAndLog(""); return 0; } + int CmdHF14AMfWrBl(const char *Cmd) { uint8_t blockNo = 0; @@ -1090,7 +1034,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack } } } - } else if (tryMfk32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) { + } else if (mfkey32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) { uint8_t sectorNum = ar_resp[i+ATTACK_KEY_COUNT].sector; uint8_t keyType = ar_resp[i+ATTACK_KEY_COUNT].keytype; diff --git a/client/cmdlfcotag.c b/client/cmdlfcotag.c index 0f68064e..71f17115 100644 --- a/client/cmdlfcotag.c +++ b/client/cmdlfcotag.c @@ -43,7 +43,8 @@ int CmdCOTAGDemod(const char *Cmd) { size_t bitlen = COTAG_BITS; memcpy(bits, DemodBuffer, COTAG_BITS); - int err = manrawdecode(bits, &bitlen, 1); + uint8_t alignPos = 0; + int err = manrawdecode(bits, &bitlen, 1, &alignPos); if (err){ if (g_debugMode) PrintAndLog("DEBUG: Error - COTAG too many errors: %d", err); return -1; diff --git a/client/graph.c b/client/graph.c index f40f093a..995a32da 100644 --- a/client/graph.c +++ b/client/graph.c @@ -218,7 +218,8 @@ uint8_t GetNrzClock(const char str[], bool printAns, bool verbose) PrintAndLog("Failed to copy from graphbuffer"); return -1; } - clock = DetectNRZClock(grph, size, 0); + size_t clkStartIdx = 0; + clock = DetectNRZClock(grph, size, 0, &clkStartIdx); // Only print this message if we're not looping something if (printAns){ PrintAndLog("Auto-detected clock rate: %d", clock); diff --git a/client/mifarehost.c b/client/mifarehost.c index 411a44c1..cbd79cf7 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -33,7 +33,194 @@ #define TRACE_ERROR 0xFF -// MIFARE +static int compare_uint64(const void *a, const void *b) { + // didn't work: (the result is truncated to 32 bits) + //return (*(int64_t*)b - *(int64_t*)a); + + // better: + if (*(uint64_t*)b == *(uint64_t*)a) return 0; + else if (*(uint64_t*)b < *(uint64_t*)a) return 1; + else return -1; +} + + +// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned. +static uint32_t intersection(uint64_t *list1, uint64_t *list2) +{ + if (list1 == NULL || list2 == NULL) { + return 0; + } + uint64_t *p1, *p2, *p3; + p1 = p3 = list1; + p2 = list2; + + while ( *p1 != -1 && *p2 != -1 ) { + if (compare_uint64(p1, p2) == 0) { + *p3++ = *p1++; + p2++; + } + else { + while (compare_uint64(p1, p2) < 0) ++p1; + while (compare_uint64(p1, p2) > 0) ++p2; + } + } + *p3 = -1; + return p3 - list1; +} + + +// Darkside attack (hf mf mifare) +static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t **keys) { + struct Crypto1State *states; + uint32_t i, pos, rr; //nr_diff; + uint8_t bt, ks3x[8], par[8][8]; + uint64_t key_recovered; + static uint64_t *keylist; + rr = 0; + + // Reset the last three significant bits of the reader nonce + nr &= 0xffffff1f; + + for (pos=0; pos<8; pos++) { + ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f; + bt = (par_info >> (pos*8)) & 0xff; + for (i=0; i<8; i++) { + par[7-pos][i] = (bt >> i) & 0x01; + } + } + + states = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0)); + + if (states == NULL) { + *keys = NULL; + return 0; + } + + keylist = (uint64_t*)states; + + for (i = 0; keylist[i]; i++) { + lfsr_rollback_word(states+i, uid^nt, 0); + crypto1_get_lfsr(states+i, &key_recovered); + keylist[i] = key_recovered; + } + keylist[i] = -1; + + *keys = keylist; + return i; +} + + +int mfDarkside(uint64_t *key) +{ + uint32_t uid = 0; + uint32_t nt = 0, nr = 0; + uint64_t par_list = 0, ks_list = 0; + uint64_t *keylist = NULL, *last_keylist = NULL; + uint32_t keycount = 0; + int16_t isOK = 0; + + UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; + + // message + printf("-------------------------------------------------------------------------\n"); + printf("Executing command. Expected execution time: 25sec on average\n"); + printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); + printf("-------------------------------------------------------------------------\n"); + + + while (true) { + clearCommandBuffer(); + SendCommand(&c); + + //flush queue + while (ukbhit()) { + int c = getchar(); (void) c; + } + + // wait cycle + while (true) { + printf("."); + fflush(stdout); + if (ukbhit()) { + return -5; + break; + } + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { + isOK = resp.arg[0]; + if (isOK < 0) { + return isOK; + } + uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); + nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); + par_list = bytes_to_num(resp.d.asBytes + 8, 8); + ks_list = bytes_to_num(resp.d.asBytes + 16, 8); + nr = bytes_to_num(resp.d.asBytes + 24, 4); + break; + } + } + + if (par_list == 0 && c.arg[0] == true) { + PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication."); + PrintAndLog("Attack will take a few seconds longer because we need two consecutive successful runs."); + } + c.arg[0] = false; + + keycount = nonce2key(uid, nt, nr, par_list, ks_list, &keylist); + + if (keycount == 0) { + PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); + PrintAndLog("This is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); + continue; + } + + qsort(keylist, keycount, sizeof(*keylist), compare_uint64); + keycount = intersection(last_keylist, keylist); + if (keycount == 0) { + free(last_keylist); + last_keylist = keylist; + continue; + } + + if (keycount > 1) { + PrintAndLog("Found %u possible keys. Trying to authenticate with each of them ...\n", keycount); + } else { + PrintAndLog("Found a possible key. Trying to authenticate...\n"); + } + + *key = -1; + uint8_t keyBlock[USB_CMD_DATA_SIZE]; + int max_keys = USB_CMD_DATA_SIZE/6; + for (int i = 0; i < keycount; i += max_keys) { + int size = keycount - i > max_keys ? max_keys : keycount - i; + for (int j = 0; j < size; j++) { + if (last_keylist == NULL) { + num_to_bytes(keylist[i*max_keys + j], 6, keyBlock); + } else { + num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock); + } + } + if (!mfCheckKeys(0, 0, false, size, keyBlock, key)) { + break; + } + } + + if (*key != -1) { + free(last_keylist); + free(keylist); + break; + } else { + PrintAndLog("Authentication failed. Trying again..."); + free(last_keylist); + last_keylist = keylist; + } + } + + return 0; +} + + int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ *key = 0; @@ -49,16 +236,6 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key return 0; } -int compar_int(const void * a, const void * b) { - // didn't work: (the result is truncated to 32 bits) - //return (*(uint64_t*)b - *(uint64_t*)a); - - // better: - if (*(uint64_t*)b == *(uint64_t*)a) return 0; - else if (*(uint64_t*)b > *(uint64_t*)a) return 1; - else return -1; -} - // Compare 16 Bits out of cryptostate int Compare16Bits(const void * a, const void * b) { if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; @@ -100,7 +277,7 @@ void* nested_worker_thread(void *arg) return statelist->head.slhead; } -int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate) +int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) { uint16_t i; uint32_t uid; @@ -178,8 +355,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo while (Compare16Bits(p1, p2) == 1) p2++; } } - p3->even = 0; p3->odd = 0; - p4->even = 0; p4->odd = 0; + *(uint64_t*)p3 = -1; + *(uint64_t*)p4 = -1; statelists[0].len = p3 - statelists[0].head.slhead; statelists[1].len = p4 - statelists[1].head.slhead; statelists[0].tail.sltail=--p3; @@ -187,24 +364,9 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo // the statelists now contain possible keys. The key we are searching for must be in the // intersection of both lists. Create the intersection: - qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compar_int); - qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compar_int); - - uint64_t *p5, *p6, *p7; - p5 = p7 = statelists[0].head.keyhead; - p6 = statelists[1].head.keyhead; - while (p5 <= statelists[0].tail.keytail && p6 <= statelists[1].tail.keytail) { - if (compar_int(p5, p6) == 0) { - *p7++ = *p5++; - p6++; - } - else { - while (compar_int(p5, p6) == -1) p5++; - while (compar_int(p5, p6) == 1) p6++; - } - } - statelists[0].len = p7 - statelists[0].head.keyhead; - statelists[0].tail.keytail=--p7; + qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); + qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); + statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); memset(resultKey, 0, 6); // The list may still contain several key candidates. Test each of them with mfCheckKeys diff --git a/client/mifarehost.h b/client/mifarehost.h index e628ba3a..a9db4ec3 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -22,8 +22,9 @@ extern char logHexFileName[FILE_PATH_SIZE]; -extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); -extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); +extern int mfDarkside(uint64_t *key); +extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate); +extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key); extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); diff --git a/client/nonce2key.c b/client/nonce2key.c new file mode 100644 index 00000000..acd551e4 --- /dev/null +++ b/client/nonce2key.c @@ -0,0 +1,137 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Roel - Dec 2009 +// Unknown author +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Darkside hack +//----------------------------------------------------------------------------- + +#include "nonce2key.h" + +#include +#include +#include +#include "mifarehost.h" +#include "util.h" +#include "crapto1/crapto1.h" + +// recover key from 2 different reader responses on same tag challenge +bool mfkey32(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s,*t; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + bool isSuccess = false; + uint8_t counter = 0; + + uint64_t t1 = msclock(); + + s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, data.nr, 1); + lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(t, &key); + crypto1_word(t, data.cuid ^ data.nonce, 0); + crypto1_word(t, data.nr2, 1); + if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce, 64))) { + //PrintAndLog("Found Key: [%012" PRIx64 "]",key); + outkey = key; + counter++; + if (counter == 20) break; + } + } + isSuccess = (counter == 1); + t1 = msclock() - t1; + //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, 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"); + return 1; + } + 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; +} + +// recover key from 2 reader responses on 2 different tag challenges +bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s, *t; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + bool isSuccess = false; + int counter = 0; + + //PrintAndLog("Enter mfkey32_moebius"); + uint64_t t1 = msclock(); + + s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, data.nr, 1); + lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(t, &key); + + crypto1_word(t, data.cuid ^ data.nonce2, 0); + crypto1_word(t, data.nr2, 1); + if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce2, 64))) { + //PrintAndLog("Found Key: [%012" PRIx64 "]",key); + outkey=key; + ++counter; + if (counter==20) + break; + } + } + isSuccess = (counter == 1); + t1 = msclock() - t1; + // PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, 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"); + return 1; + } + 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; +} + +// recover key from reader response and tag response of one authentication sequence +int mfkey64(nonces_t data, 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"); + uint64_t t1 = msclock(); + + // Extract the keystream from the messages + ks2 = data.ar ^ prng_successor(data.nonce, 64); + ks3 = data.at ^ prng_successor(data.nonce, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, data.nr, 1); + lfsr_rollback_word(revstate, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(revstate, &key); + // PrintAndLog("Found Key: [%012" PRIx64 "]", key); + crypto1_destroy(revstate); + *outputkey = key; + + t1 = msclock() - t1; + // PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0); + return 0; +} diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key.h similarity index 65% rename from client/nonce2key/nonce2key.h rename to client/nonce2key.h index 07ad18c0..795f239d 100644 --- a/client/nonce2key/nonce2key.h +++ b/client/nonce2key.h @@ -23,17 +23,14 @@ typedef struct { uint32_t nonce; uint32_t ar; uint32_t nr; + uint32_t at; 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); 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); +bool mfkey32_moebius(nonces_t data, uint64_t *outputkey); +int mfkey64(nonces_t data, uint64_t *outputkey); #endif diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c deleted file mode 100644 index d146b723..00000000 --- a/client/nonce2key/nonce2key.c +++ /dev/null @@ -1,288 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011 -// Roel - Dec 2009 -// Unknown author -// -// 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. -//----------------------------------------------------------------------------- -// MIFARE Darkside hack -//----------------------------------------------------------------------------- - -#include "nonce2key.h" - -#include -#include -#include -#include "mifarehost.h" -#include "ui.h" -#include "util.h" -#include "crapto1/crapto1.h" - -int compar_state(const void * a, const void * b) { - // didn't work: (the result is truncated to 32 bits) - //return (*(int64_t*)b - *(int64_t*)a); - - // better: - if (*(int64_t*)b == *(int64_t*)a) return 0; - else if (*(int64_t*)b > *(int64_t*)a) return 1; - else return -1; -} - -int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key) { - struct Crypto1State *state; - uint32_t i, pos, rr, nr_diff, key_count;//, ks1, ks2; - uint8_t bt, ks3x[8], par[8][8]; - uint64_t key_recovered; - int64_t *state_s; - static uint32_t last_uid; - static int64_t *last_keylist; - rr = 0; - - if (last_uid != uid && last_keylist != NULL) - { - free(last_keylist); - last_keylist = NULL; - } - last_uid = uid; - - // Reset the last three significant bits of the reader nonce - nr &= 0xffffff1f; - - PrintAndLog("\nuid(%08x) nt(%08x) par(%016" PRIx64") ks(%016" PRIx64") nr(%08" PRIx32")\n\n",uid,nt,par_info,ks_info,nr); - - for (pos=0; pos<8; pos++) - { - ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f; - bt = (par_info >> (pos*8)) & 0xff; - for (i=0; i<8; i++) - { - par[7-pos][i] = (bt >> i) & 0x01; - } - } - - printf("|diff|{nr} |ks3|ks3^5|parity |\n"); - printf("+----+--------+---+-----+---------------+\n"); - for (i=0; i<8; i++) - { - nr_diff = nr | i << 5; - printf("| %02x |%08x|",i << 5, nr_diff); - printf(" %01x | %01x |",ks3x[i], ks3x[i]^5); - for (pos=0; pos<7; pos++) printf("%01x,", par[i][pos]); - printf("%01x|\n", par[i][7]); - } - - if (par_info == 0) - PrintAndLog("Parity is all zero, trying special attack! Just wait for few more seconds..."); - - state = lfsr_common_prefix(nr, rr, ks3x, par); - state_s = (int64_t*)state; - - //char filename[50] ; - //sprintf(filename, "nt_%08x_%d.txt", nt, nr); - //printf("name %s\n", filename); - //FILE* fp = fopen(filename,"w"); - for (i = 0; (state) && *(state_s + i); i++) - { - lfsr_rollback_word(state+i, uid^nt, 0); - crypto1_get_lfsr(state + i, &key_recovered); - *(state_s + i) = key_recovered; - //fprintf(fp, "%012" PRIx64 "\n",key_recovered); - } - //fclose(fp); - - if(!state) - return 1; - - qsort(state_s, i, sizeof(*state_s), compar_state); - *(state_s + i) = -1; - - //Create the intersection: - if (par_info == 0 ) { - if (last_keylist != NULL) { - int64_t *p1, *p2, *p3; - p1 = p3 = last_keylist; - p2 = state_s; - while ( *p1 != -1 && *p2 != -1 ) { - if (compar_state(p1, p2) == 0) { - printf("p1:%" PRIx64" p2:%" PRIx64 " p3:%" PRIx64" key:%012" PRIx64 "\n",(uint64_t)(p1-last_keylist),(uint64_t)(p2-state_s),(uint64_t)(p3-last_keylist),*p1); - *p3++ = *p1++; - p2++; - } - else { - while (compar_state(p1, p2) == -1) ++p1; - while (compar_state(p1, p2) == 1) ++p2; - } - } - key_count = p3 - last_keylist; - } else { - key_count = 0; - } - } else { - last_keylist = state_s; - key_count = i; - } - - printf("key_count:%d\n", key_count); - - // The list may still contain several key candidates. Test each of them with mfCheckKeys - for (i = 0; i < key_count; i++) { - uint8_t keyBlock[6]; - uint64_t key64; - key64 = *(last_keylist + i); - num_to_bytes(key64, 6, keyBlock); - key64 = 0; - if (!mfCheckKeys(0, 0, false, 1, keyBlock, &key64)) { - *key = key64; - free(last_keylist); - last_keylist = NULL; - if (par_info == 0) - free(state); - return 0; - } - } - - - free(last_keylist); - last_keylist = state_s; - - return 1; -} - -// 32 bit recover key from 2 nonces -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 = 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 - uint64_t t1 = msclock(); - bool isSuccess = false; - uint8_t counter=0; - - 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))) { - //PrintAndLog("Found Key: [%012" PRIx64 "]",key); - outkey = key; - counter++; - if (counter==20) break; - } - } - isSuccess = (counter == 1); - t1 = msclock() - t1; - //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, 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"); - return 1; - } - 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; -} - -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 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"); - uint64_t t1 = msclock(); - - 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" PRIx64 "]",key); - outkey=key; - ++counter; - if (counter==20) - break; - } - } - isSuccess = (counter == 1); - t1 = msclock() - t1; - //if ( t1 > 0 ) PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, 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"); - return 1; - } - 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; -} - -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"); - uint64_t t1 = msclock(); - - // 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" PRIx64 "]", key); - crypto1_destroy(revstate); - *outputkey = key; - - t1 = msclock() - t1; - if ( t1 > 0 ) PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0); - return 0; -} - diff --git a/client/obj/nonce2key/.dummy b/client/obj/nonce2key/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/client/scripting.c b/client/scripting.c index 0d491df7..d68adb3e 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -8,6 +8,8 @@ // Some lua scripting glue to proxmark core. //----------------------------------------------------------------------------- +#include "scripting.h" + #include #include #include @@ -15,9 +17,8 @@ #include "proxmark3.h" #include "usb_cmd.h" #include "cmdmain.h" -#include "scripting.h" #include "util.h" -#include "nonce2key/nonce2key.h" +#include "mifarehost.h" #include "../common/iso15693tools.h" #include "iso14443crc.h" #include "../common/crc16.h" @@ -125,49 +126,27 @@ static int returnToLuaWithError(lua_State *L, const char* fmt, ...) return 2; } -static int l_nonce2key(lua_State *L){ - - size_t size; - const char *p_uid = luaL_checklstring(L, 1, &size); - if(size != 4) return returnToLuaWithError(L,"Wrong size of uid, got %d bytes, expected 4", (int) size); - - const char *p_nt = luaL_checklstring(L, 2, &size); - if(size != 4) return returnToLuaWithError(L,"Wrong size of nt, got %d bytes, expected 4", (int) size); - - const char *p_nr = luaL_checklstring(L, 3, &size); - if(size != 4) return returnToLuaWithError(L,"Wrong size of nr, got %d bytes, expected 4", (int) size); - - const char *p_par_info = luaL_checklstring(L, 4, &size); - if(size != 8) return returnToLuaWithError(L,"Wrong size of par_info, got %d bytes, expected 8", (int) size); - - const char *p_pks_info = luaL_checklstring(L, 5, &size); - if(size != 8) return returnToLuaWithError(L,"Wrong size of ks_info, got %d bytes, expected 8", (int) size); - - - uint32_t uid = bytes_to_num(( uint8_t *)p_uid,4); - uint32_t nt = bytes_to_num(( uint8_t *)p_nt,4); - - uint32_t nr = bytes_to_num(( uint8_t*)p_nr,4); - uint64_t par_info = bytes_to_num(( uint8_t *)p_par_info,8); - uint64_t ks_info = bytes_to_num(( uint8_t *)p_pks_info,8); - - uint64_t key = 0; - - int retval = nonce2key(uid,nt, nr, par_info,ks_info, &key); +static int l_mfDarkside(lua_State *L){ + uint64_t key; + + int retval = mfDarkside(&key); + //Push the retval on the stack - lua_pushinteger(L,retval); + lua_pushinteger(L, retval); //Push the key onto the stack uint8_t dest_key[8]; - num_to_bytes(key,sizeof(dest_key),dest_key); + num_to_bytes(key, sizeof(dest_key), dest_key); //printf("Pushing to lua stack: %012" PRIx64 "\n",key); - lua_pushlstring(L,(const char *) dest_key,sizeof(dest_key)); + lua_pushlstring(L,(const char *)dest_key, sizeof(dest_key)); return 2; //Two return values } + //static int l_PrintAndLog(lua_State *L){ return CmdHF14AMfDump(luaL_checkstring(L, 1));} + static int l_clearCommandBuffer(lua_State *L){ clearCommandBuffer(); return 0; @@ -499,7 +478,7 @@ int set_pm3_libraries(lua_State *L) static const luaL_Reg libs[] = { {"SendCommand", l_SendCommand}, {"WaitForResponseTimeout", l_WaitForResponseTimeout}, - {"nonce2key", l_nonce2key}, + {"mfDarkside", l_mfDarkside}, //{"PrintAndLog", l_PrintAndLog}, {"foobar", l_foobar}, {"ukbhit", l_ukbhit}, diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index ce6db3c0..e68f7a75 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -8,7 +8,7 @@ author = "Martin Holst Swende" desc = [[ -This is a which automates cracking and dumping mifare classic cards. It sets itself into +This is a script which automates cracking and dumping mifare classic cards. It sets itself into 'listening'-mode, after which it cracks and dumps any mifare classic card that you place by the device. @@ -63,91 +63,6 @@ function wait_for_mifare() return nil, "Aborted by user" end -function mfcrack() - core.clearCommandBuffer() - -- Build the mifare-command - local cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 1} - - local retry = true - while retry do - core.SendCommand(cmd:getBytes()) - local key, errormessage = mfcrack_inner() - -- Success? - if key then return key end - -- Failure? - if errormessage then return nil, errormessage end - -- Try again..set arg1 to 0 this time. - - cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 0} - end - return nil, "Aborted by user" -end - - -function mfcrack_inner() - while not core.ukbhit() do - local result = core.WaitForResponseTimeout(cmds.CMD_ACK,1000) - if result then - - --[[ - I don't understand, they cmd and args are defined as uint32_t, however, - looking at the returned data, they all look like 64-bit things: - - print("result", bin.unpack("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", result)) - - FF 00 00 00 00 00 00 00 <-- 64 bits of data - FE FF FF FF 00 00 00 00 <-- 64 bits of data - 00 00 00 00 00 00 00 00 <-- 64 bits of data - 00 00 00 00 00 00 00 00 <-- 64 bits of data - 04 7F 12 E2 00 <-- this is where 'data' starts - - So below I use LI to pick out the "FEFF FFFF", don't know why it works.. - --]] - -- Unpacking the arg-parameters - local count,cmd,isOK = bin.unpack('LI',result) - --print("response", isOK)--FF FF FF FF - if isOK == 0xFFFFFFFF then - return nil, "Button pressed. Aborted." - elseif isOK == 0xFFFFFFFE then - return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." - elseif isOK == 0xFFFFFFFD then - return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." - elseif isOK == 0xFFFFFFFC then - return nil, "The card's random number generator behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." - elseif isOK ~= 1 then - return nil, "Error occurred" - end - - - -- The data-part is left - -- Starts 32 bytes in, at byte 33 - local data = result:sub(33) - - -- A little helper - local get = function(num) - local x = data:sub(1,num) - data = data:sub(num+1) - return x - end - - local uid,nt,pl = get(4),get(4),get(8) - local ks,nr = get(8),get(4) - - local status, key = core.nonce2key(uid,nt, nr, pl,ks) - if not status then return status,key end - - if status > 0 then - print("Key not found (lfsr_common_prefix problem)") - -- try again - return nil,nil - else - return key - end - end - end - return nil, "Aborted by user" -end - function nested(key,sak) local typ = 1 if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k @@ -209,8 +124,15 @@ function main(args) print("Card found, commencing crack", uid) -- Crack it local key, cnt - res,err = mfcrack() - if not res then return oops(err) end + err, res = core.mfDarkside() + if err == -1 then return oops("Button pressed. Aborted.") + elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).") + elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).") + elseif err == -4 then return oops([[ +Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown +generating polynomial with 16 effective bits only, but shows unexpected behaviour.]]) + elseif err == -5 then return oops("Aborted via keyboard.") + end -- The key is actually 8 bytes, so a -- 6-byte key is sent as 00XXXXXX -- This means we unpack it as first diff --git a/common/crapto1/crapto1.c b/common/crapto1/crapto1.c index 82c5b65b..01351731 100644 --- a/common/crapto1/crapto1.c +++ b/common/crapto1/crapto1.c @@ -465,18 +465,9 @@ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) */ static struct Crypto1State* check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], - uint32_t odd, uint32_t even, struct Crypto1State* sl) + uint32_t odd, uint32_t even, struct Crypto1State* sl, uint32_t no_par) { - uint32_t ks1, nr, ks2, rr, ks3, c, good = 1, no_par = 1; - - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 8; j++) { - if (parities[i][j] != 0) { - no_par = 0; - break; - } - } - } + uint32_t ks1, nr, ks2, rr, ks3, c, good = 1; for(c = 0; good && c < 8; ++c) { sl->odd = odd ^ fastfwd[1][c]; @@ -510,7 +501,7 @@ check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], * Implentation of the common prefix attack. */ struct Crypto1State* -lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) +lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par) { struct Crypto1State *statelist, *s; uint32_t *odd, *even, *o, *e, top; @@ -518,7 +509,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) odd = lfsr_prefix_ks(ks, 1); even = lfsr_prefix_ks(ks, 0); - s = statelist = malloc((sizeof *statelist) << 20); + s = statelist = malloc((sizeof *statelist) << 22); // was << 20. Need more for no_par special attack. Enough??? if(!s || !odd || !even) { free(statelist); statelist = 0; @@ -530,7 +521,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) for(top = 0; top < 64; ++top) { *o += 1 << 21; *e += (!(top & 7) + 1) << 21; - s = check_pfx_parity(pfx, rr, par, *o, *e, s); + s = check_pfx_parity(pfx, rr, par, *o, *e, s, no_par); } s->odd = s->even = 0; diff --git a/common/crapto1/crapto1.h b/common/crapto1/crapto1.h index aef59b03..e718b1f2 100644 --- a/common/crapto1/crapto1.h +++ b/common/crapto1/crapto1.h @@ -41,7 +41,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in); struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd); struct Crypto1State* -lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]); +lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par); uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); diff --git a/common/lfdemod.c b/common/lfdemod.c index 1b53c445..8307a890 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -5,16 +5,45 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Low frequency demod/decode commands +// Low frequency demod/decode commands - by marshmellow, holiman, iceman and +// many others who came before +// +// NOTES: +// LF Demod functions are placed here to allow the flexability to use client or +// device side. Most BUT NOT ALL of these functions are currenlty safe for +// device side use currently. (DetectST for example...) +// +// There are likely many improvements to the code that could be made, please +// make suggestions... +// +// we tried to include author comments so any questions could be directed to +// the source. +// +// There are 4 main sections of code below: +// Utilities Section: +// for general utilities used by multiple other functions +// Clock / Bitrate Detection Section: +// for clock detection functions for each modulation +// Modulation Demods &/or Decoding Section: +// for main general modulation demodulating and encoding decoding code. +// Tag format detection section: +// for detection of specific tag formats within demodulated data +// +// marshmellow //----------------------------------------------------------------------------- -#include -#include "lfdemod.h" -#include +#include // for memset, memcmp and size_t +#include // for uint_32+ +#include // for bool + +//********************************************************************************************** +//---------------------------------Utilities Section-------------------------------------------- +//********************************************************************************************** +#define LOWEST_DEFAULT_CLOCK 32 +#define FSK_PSK_THRESHOLD 123 //to allow debug print calls when used not on device void dummy(char *fmt, ...){} - #ifndef ON_DEVICE #include "ui.h" #include "cmdparser.h" @@ -25,21 +54,18 @@ void dummy(char *fmt, ...){} #define prnt dummy #endif -uint8_t justNoise(uint8_t *BitStream, size_t size) -{ - static const uint8_t THRESHOLD = 123; +uint8_t justNoise(uint8_t *BitStream, size_t size) { //test samples are not just noise uint8_t justNoise1 = 1; for(size_t idx=0; idx < size && justNoise1 ;idx++){ - justNoise1 = BitStream[idx] < THRESHOLD; + justNoise1 = BitStream[idx] < FSK_PSK_THRESHOLD; } return justNoise1; } //by marshmellow //get high and low values of a wave with passed in fuzz factor. also return noise test = 1 for passed or 0 for only noise -int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo) -{ +int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo) { *high=0; *low=255; // get high and low thresholds @@ -47,7 +73,7 @@ int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi if (BitStream[i] > *high) *high = BitStream[i]; if (BitStream[i] < *low) *low = BitStream[i]; } - if (*high < 123) return -1; // just noise + if (*high < FSK_PSK_THRESHOLD) return -1; // just noise *high = ((*high-128)*fuzzHi + 12800)/100; *low = ((*low-128)*fuzzLo + 12800)/100; return 1; @@ -56,8 +82,7 @@ int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi // by marshmellow // pass bits to be tested in bits, length bits passed in bitLen, and parity type (even=0 | odd=1) in pType // returns 1 if passed -uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType) -{ +uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType) { uint8_t ans = 0; for (uint8_t i = 0; i < bitLen; i++){ ans ^= ((bits >> i) & 1); @@ -69,8 +94,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 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) -{ +size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen) { uint32_t parityWd = 0; size_t j = 0, bitCnt = 0; for (int word = 0; word < (bLen); word+=pLen) { @@ -99,8 +123,7 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p // 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; 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) -{ +size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType) { uint32_t parityWd = 0; size_t j = 0, bitCnt = 0; for (int word = 0; word < sourceLen; word+=pLen-1) { @@ -124,8 +147,7 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p return bitCnt; } -uint32_t bytebits_to_byte(uint8_t *src, size_t numbits) -{ +uint32_t bytebits_to_byte(uint8_t *src, size_t numbits) { uint32_t num = 0; for(int i = 0 ; i < numbits ; i++) { @@ -136,8 +158,7 @@ uint32_t bytebits_to_byte(uint8_t *src, size_t numbits) } //least significant bit first -uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits) -{ +uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits) { uint32_t num = 0; for(int i = 0 ; i < numbits ; i++) { @@ -146,13 +167,6 @@ uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits) return num; } -//by marshmellow -//search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length -uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx) -{ - return (preambleSearchEx(BitStream, preamble, pLen, size, startIdx, false)) ? 1 : 0; -} - // search for given preamble in given BitStream and return success=1 or fail=0 and startIndex (where it was found) and length if not fineone // fineone does not look for a repeating preamble for em4x05/4x69 sends preamble once, so look for it once in the first pLen bits bool preambleSearchEx(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx, bool findone) { @@ -177,19 +191,25 @@ bool preambleSearchEx(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t return false; } +//by marshmellow +//search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length +uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx) { + return (preambleSearchEx(BitStream, preamble, pLen, size, startIdx, false)) ? 1 : 0; +} + // find start of modulating data (for fsk and psk) in case of beginning noise or slow chip startup. -size_t findModStart(uint8_t dest[], size_t size, uint8_t threshold_value, uint8_t expWaveSize) { +size_t findModStart(uint8_t dest[], size_t size, uint8_t expWaveSize) { size_t i = 0; size_t waveSizeCnt = 0; uint8_t thresholdCnt = 0; - bool isAboveThreshold = dest[i++] >= threshold_value; + bool isAboveThreshold = dest[i++] >= FSK_PSK_THRESHOLD; for (; i < size-20; i++ ) { - if(dest[i] < threshold_value && isAboveThreshold) { + if(dest[i] < FSK_PSK_THRESHOLD && isAboveThreshold) { thresholdCnt++; if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break; isAboveThreshold = false; waveSizeCnt = 0; - } else if (dest[i] >= threshold_value && !isAboveThreshold) { + } else if (dest[i] >= FSK_PSK_THRESHOLD && !isAboveThreshold) { thresholdCnt++; if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break; isAboveThreshold = true; @@ -203,94 +223,67 @@ size_t findModStart(uint8_t dest[], size_t size, uint8_t threshold_value, uint8_ return i; } -//by marshmellow -//takes 1s and 0s and searches for EM410x format - output EM ID -uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo) -{ - //sanity checks - if (*size < 64) return 0; - if (BitStream[1]>1) return 0; //allow only 1s and 0s +int getClosestClock(int testclk) { + uint8_t fndClk[] = {8,16,32,40,50,64,128}; - // 111111111 bit pattern represent start of frame - // include 0 in front to help get start pos - uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1}; - uint8_t errChk = 0; - uint8_t FmtLen = 10; // sets of 4 bits = end data - *startIdx = 0; - errChk = preambleSearch(BitStream, preamble, sizeof(preamble), size, startIdx); - if ( errChk == 0 || (*size != 64 && *size != 128) ) return 0; - if (*size == 128) FmtLen = 22; // 22 sets of 4 bits + for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) + if (testclk >= fndClk[clkCnt]-(fndClk[clkCnt]/8) && testclk <= fndClk[clkCnt]+1) + return fndClk[clkCnt]; - //skip last 4bit parity row for simplicity - *size = removeParity(BitStream, *startIdx + sizeof(preamble), 5, 0, FmtLen * 5); - if (*size == 40) { // std em410x format - *hi = 0; - *lo = ((uint64_t)(bytebits_to_byte(BitStream, 8)) << 32) | (bytebits_to_byte(BitStream + 8, 32)); - } else if (*size == 88) { // long em format - *hi = (bytebits_to_byte(BitStream, 24)); - *lo = ((uint64_t)(bytebits_to_byte(BitStream + 24, 32)) << 32) | (bytebits_to_byte(BitStream + 24 + 32, 32)); - } else { - return 0; - } - return 1; + return 0; } -//by marshmellow -//demodulates strong heavily clipped samples -int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low) -{ - size_t bitCnt=0, smplCnt=0, errCnt=0; - uint8_t waveHigh = 0; - for (size_t i=0; i < *size; i++){ - if (BinStream[i] >= high && waveHigh){ - smplCnt++; - } else if (BinStream[i] <= low && !waveHigh){ - smplCnt++; - } else { //transition - if ((BinStream[i] >= high && !waveHigh) || (BinStream[i] <= low && waveHigh)){ - if (smplCnt > clk-(clk/4)-1) { //full clock - if (smplCnt > clk + (clk/4)+1) { //too many samples - errCnt++; - if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); - BinStream[bitCnt++]=7; - } else if (waveHigh) { - BinStream[bitCnt++] = invert; - BinStream[bitCnt++] = invert; - } else if (!waveHigh) { - BinStream[bitCnt++] = invert ^ 1; - BinStream[bitCnt++] = invert ^ 1; - } - waveHigh ^= 1; - smplCnt = 0; - } else if (smplCnt > (clk/2) - (clk/4)-1) { - if (waveHigh) { - BinStream[bitCnt++] = invert; - } else if (!waveHigh) { - BinStream[bitCnt++] = invert ^ 1; - } - waveHigh ^= 1; - smplCnt = 0; - } else if (!bitCnt) { - //first bit - waveHigh = (BinStream[i] >= high); - smplCnt = 1; - } else { - smplCnt++; - //transition bit oops - } - } else { //haven't hit new high or new low yet - smplCnt++; - } +void getNextLow(uint8_t samples[], size_t size, int low, size_t *i) { + while ((samples[*i] > low) && (*i < size)) + *i+=1; +} + +void getNextHigh(uint8_t samples[], size_t size, int high, size_t *i) { + while ((samples[*i] < high) && (*i < size)) + *i+=1; +} + +// load wave counters +bool loadWaveCounters(uint8_t samples[], size_t size, int lowToLowWaveLen[], int highToLowWaveLen[], int *waveCnt, int *skip, int *minClk, int *high, int *low) { + size_t i=0, firstLow, firstHigh; + size_t testsize = (size < 512) ? size : 512; + + if ( getHiLo(samples, testsize, high, low, 80, 80) == -1 ) { + if (g_debugMode==2) prnt("DEBUG STT: just noise detected - quitting"); + return false; //just noise + } + + // get to first full low to prime loop and skip incomplete first pulse + getNextHigh(samples, size, *high, &i); + getNextLow(samples, size, *low, &i); + *skip = i; + + // populate tmpbuff buffer with pulse lengths + while (i < size) { + // measure from low to low + firstLow = i; + //find first high point for this wave + getNextHigh(samples, size, *high, &i); + firstHigh = i; + + getNextLow(samples, size, *low, &i); + + if (*waveCnt >= (size/LOWEST_DEFAULT_CLOCK)) + break; + + highToLowWaveLen[*waveCnt] = i - firstHigh; //first high to first low + lowToLowWaveLen[*waveCnt] = i - firstLow; + *waveCnt += 1; + if (i-firstLow < *minClk && i < size) { + *minClk = i - firstLow; } } - *size = bitCnt; - return errCnt; + return true; } //by marshmellow -//amplify based on ask edge detection -void askAmp(uint8_t *BitStream, size_t size) -{ +//amplify based on ask edge detection - not accurate enough to use all the time +void askAmp(uint8_t *BitStream, size_t size) { uint8_t Last = 128; for(size_t i = 1; i=30) //large jump up @@ -302,117 +295,6 @@ 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) -{ - if (*size==0) return -1; - int start = DetectASKClock(BinStream, *size, clk, maxErr); //clock default - 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, amp %d", *clk, start, amp); - - uint8_t initLoopMax = 255; - if (initLoopMax > *size) initLoopMax = *size; - // Detect high and lows - //25% clip in case highs and lows aren't clipped [marshmellow] - int high, low; - if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1) - return -2; //just noise - - size_t errCnt = 0; - // if clean clipped waves detected run alternate demod - if (DetectCleanAskWave(BinStream, *size, high, low)) { - if (g_debugMode==2) prnt("DEBUG ASK: Clean Wave Detected - using clean wave demod"); - errCnt = cleanAskRawDemod(BinStream, size, *clk, *invert, high, low); - if (askType) //askman - return manrawdecode(BinStream, size, 0); - else //askraw - return errCnt; - } - if (g_debugMode==2) prnt("DEBUG ASK: Weak Wave Detected - using weak wave demod"); - - int lastBit; //set first clock check - can go negative - size_t i, bitnum = 0; //output counter - uint8_t midBit = 0; - uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - size_t MaxBits = 3072; //max bits to collect - lastBit = start - *clk; - - for (i = start; i < *size; ++i) { - if (i-lastBit >= *clk-tol){ - if (BinStream[i] >= high) { - BinStream[bitnum++] = *invert; - } else if (BinStream[i] <= low) { - BinStream[bitnum++] = *invert ^ 1; - } else if (i-lastBit >= *clk+tol) { - if (bitnum > 0) { - if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); - BinStream[bitnum++]=7; - errCnt++; - } - } else { //in tolerance - looking for peak - continue; - } - midBit = 0; - lastBit += *clk; - } else if (i-lastBit >= (*clk/2-tol) && !midBit && !askType){ - if (BinStream[i] >= high) { - BinStream[bitnum++] = *invert; - } else if (BinStream[i] <= low) { - BinStream[bitnum++] = *invert ^ 1; - } else if (i-lastBit >= *clk/2+tol) { - BinStream[bitnum] = BinStream[bitnum-1]; - bitnum++; - } else { //in tolerance - looking for peak - continue; - } - midBit = 1; - } - if (bitnum >= MaxBits) break; - } - *size = bitnum; - return errCnt; -} - -//by marshmellow -//take 10 and 01 and manchester decode -//run through 2 times and take least errCnt -int manrawdecode(uint8_t * BitStream, size_t *size, uint8_t invert) -{ - uint16_t bitnum=0, MaxBits = 512, errCnt = 0; - size_t i, ii; - uint16_t bestErr = 1000, bestRun = 0; - if (*size < 16) return -1; - //find correct start position [alignment] - for (ii=0;ii<2;++ii){ - for (i=ii; i<*size-3; i+=2) - if (BitStream[i]==BitStream[i+1]) - errCnt++; - - if (bestErr>errCnt){ - bestErr=errCnt; - bestRun=ii; - } - errCnt=0; - } - //decode - for (i=bestRun; i < *size-3; i+=2){ - if(BitStream[i] == 1 && (BitStream[i+1] == 0)){ - BitStream[bitnum++]=invert; - } else if((BitStream[i] == 0) && BitStream[i+1] == 1){ - BitStream[bitnum++]=invert^1; - } else { - BitStream[bitnum++]=7; - } - if(bitnum>MaxBits) break; - } - *size=bitnum; - return bestErr; -} uint32_t manchesterEncode2Bytes(uint16_t datain) { uint32_t output = 0; @@ -426,381 +308,25 @@ uint32_t manchesterEncode2Bytes(uint16_t datain) { //by marshmellow //encode binary data into binary manchester -int ManchesterEncode(uint8_t *BitStream, size_t size) -{ - size_t modIdx=20000, i=0; - if (size>modIdx) return -1; +//NOTE: BitStream must have triple the size of "size" available in memory to do the swap +int ManchesterEncode(uint8_t *BitStream, size_t size) { + //allow up to 4K out (means BitStream must be at least 2048+4096 to handle the swap) + size = (size>2048) ? 2048 : size; + size_t modIdx = size; + size_t i; for (size_t idx=0; idx < size; idx++){ BitStream[idx+modIdx++] = BitStream[idx]; BitStream[idx+modIdx++] = BitStream[idx]^1; } - for (; i<(size*2); i++){ - BitStream[i] = BitStream[i+20000]; + for (i=0; i<(size*2); i++){ + BitStream[i] = BitStream[i+size]; } return i; } -//by marshmellow -//take 01 or 10 = 1 and 11 or 00 = 0 -//check for phase errors - should never have 111 or 000 should be 01001011 or 10110100 for 1010 -//decodes biphase or if inverted it is AKA conditional dephase encoding AKA differential manchester encoding -int BiphaseRawDecode(uint8_t *BitStream, size_t *size, int offset, int invert) -{ - uint16_t bitnum = 0; - uint16_t errCnt = 0; - size_t i = offset; - uint16_t MaxBits=512; - //if not enough samples - error - if (*size < 51) return -1; - //check for phase change faults - skip one sample if faulty - uint8_t offsetA = 1, offsetB = 1; - for (; i<48; i+=2){ - if (BitStream[i+1]==BitStream[i+2]) offsetA=0; - if (BitStream[i+2]==BitStream[i+3]) offsetB=0; - } - if (!offsetA && offsetB) offset++; - for (i=offset; i<*size-3; i+=2){ - //check for phase error - if (BitStream[i+1]==BitStream[i+2]) { - BitStream[bitnum++]=7; - errCnt++; - } - if((BitStream[i]==1 && BitStream[i+1]==0) || (BitStream[i]==0 && BitStream[i+1]==1)){ - BitStream[bitnum++]=1^invert; - } else if((BitStream[i]==0 && BitStream[i+1]==0) || (BitStream[i]==1 && BitStream[i+1]==1)){ - BitStream[bitnum++]=invert; - } else { - BitStream[bitnum++]=7; - errCnt++; - } - if(bitnum>MaxBits) break; - } - *size=bitnum; - return errCnt; -} - -// by marshmellow -// demod gProxIIDemod -// error returns as -x -// success returns start position in BitStream -// BitStream must contain previously askrawdemod and biphasedemoded data -int gProxII_Demod(uint8_t BitStream[], size_t *size) -{ - size_t startIdx=0; - uint8_t preamble[] = {1,1,1,1,1,0}; - - uint8_t errChk = preambleSearch(BitStream, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -3; //preamble not found - if (*size != 96) return -2; //should have found 96 bits - //check first 6 spacer bits to verify format - if (!BitStream[startIdx+5] && !BitStream[startIdx+10] && !BitStream[startIdx+15] && !BitStream[startIdx+20] && !BitStream[startIdx+25] && !BitStream[startIdx+30]){ - //confirmed proper separator bits found - //return start position - return (int) startIdx; - } - return -5; //spacer bits not found - not a valid gproxII -} - -//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; - size_t idx = 1; - if (fchigh==0) fchigh=10; - if (fclow==0) fclow=8; - //set the threshold close to 0 (graph) or 128 std to avoid static - uint8_t threshold_value = 123; - size_t preLastSample = 0; - size_t LastSample = 0; - size_t currSample = 0; - if ( size < 1024 ) return 0; // not enough samples - - //find start of modulating data in trace - idx = findModStart(dest, size, threshold_value, fchigh); - - // Need to threshold first sample - if(dest[idx] < threshold_value) dest[0] = 0; - else dest[0] = 1; - idx++; - - size_t numBits = 0; - // 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 < size-20; idx++) { - // threshold current value - - if (dest[idx] < threshold_value) dest[idx] = 0; - else dest[idx] = 1; - - // Check for 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) - //do nothing with extra garbage - } 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))){ - dest[numBits-1]=1; - } - dest[numBits++]=1; - - } else if (currSample > (fchigh+1) && numBits < 3) { //12 + and first two bit = unusable garbage - //do nothing with beginning garbage and reset.. should be rare.. - numBits = 0; - } 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 (or 6+ = 7) - dest[numBits++]=0; - } - last_transition = idx; - } - } - return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 -} - -//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) -{ - uint8_t lastval=dest[0]; - size_t idx=0; - size_t numBits=0; - uint32_t n=1; - for( idx=1; idx < size; idx++) { - n++; - 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; - } else {// 0->1 crossing - n = (n * fchigh + rfLen/2) / 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; - lastval=dest[idx]; - }//end for - // if valid extra bits at the end were all the same frequency - add them in - if (n > rfLen/fchigh) { - if (dest[idx-2]==1) { - n = (n * fclow + rfLen/2) / rfLen; - } else { - n = (n * fchigh + rfLen/2) / rfLen; - } - memset(dest+numBits, dest[idx-1]^invert , n); - numBits += n; - } - return numBits; -} - -//by marshmellow (from holiman's base) -// full fsk demod from GraphBuffer wave to decoded 1s and 0s (no mandemod) -int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) -{ - // FSK demodulator - size = fsk_wave_demod(dest, size, fchigh, fclow); - size = aggregate_bits(dest, size, rfLen, invert, fchigh, fclow); - return size; -} - -// loop to get raw HID waveform then FSK demodulate the TAG ID from it -int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) -{ - if (justNoise(dest, *size)) return -1; - - size_t numStart=0, size2=*size, startIdx=0; - // FSK demodulator - *size = fskdemod(dest, size2,50,1,10,8); //fsk2a - if (*size < 96*2) return -2; - // 00011101 bit pattern represent start of frame, 01 pattern represents a 0 and 10 represents a 1 - uint8_t preamble[] = {0,0,0,1,1,1,0,1}; - // find bitstring in array - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -3; //preamble not found - - numStart = startIdx + sizeof(preamble); - // final loop, go over previously decoded FSK data and manchester decode into usable tag ID - for (size_t idx = numStart; (idx-numStart) < *size - sizeof(preamble); idx+=2){ - if (dest[idx] == dest[idx+1]){ - return -4; //not manchester data - } - *hi2 = (*hi2<<1)|(*hi>>31); - *hi = (*hi<<1)|(*lo>>31); - //Then, shift in a 0 or one into low - if (dest[idx] && !dest[idx+1]) // 1 0 - *lo=(*lo<<1)|1; - else // 0 1 - *lo=(*lo<<1)|0; - } - return (int)startIdx; -} - -// loop to get raw paradox waveform then FSK demodulate the TAG ID from it -int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) -{ - if (justNoise(dest, *size)) return -1; - - size_t numStart=0, size2=*size, startIdx=0; - // FSK demodulator - *size = fskdemod(dest, size2,50,1,10,8); //fsk2a - if (*size < 96) return -2; - - // 00001111 bit pattern represent start of frame, 01 pattern represents a 0 and 10 represents a 1 - uint8_t preamble[] = {0,0,0,0,1,1,1,1}; - - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -3; //preamble not found - - numStart = startIdx + sizeof(preamble); - // final loop, go over previously decoded FSK data and manchester decode into usable tag ID - for (size_t idx = numStart; (idx-numStart) < *size - sizeof(preamble); idx+=2){ - if (dest[idx] == dest[idx+1]) - return -4; //not manchester data - *hi2 = (*hi2<<1)|(*hi>>31); - *hi = (*hi<<1)|(*lo>>31); - //Then, shift in a 0 or one into low - if (dest[idx] && !dest[idx+1]) // 1 0 - *lo=(*lo<<1)|1; - else // 0 1 - *lo=(*lo<<1)|0; - } - return (int)startIdx; -} - -int IOdemodFSK(uint8_t *dest, size_t size) -{ - if (justNoise(dest, size)) return -1; - //make sure buffer has data - if (size < 66*64) return -2; - // FSK demodulator - size = fskdemod(dest, size, 64, 1, 10, 8); // FSK2a RF/64 - if (size < 65) return -3; //did we get a good demod? - //Index map - //0 10 20 30 40 50 60 - //| | | | | | | - //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 - //----------------------------------------------------------------------------- - //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11 - // - //XSF(version)facility:codeone+codetwo - //Handle the data - size_t startIdx = 0; - uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,1}; - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), &size, &startIdx); - if (errChk == 0) return -4; //preamble not found - - if (!dest[startIdx+8] && dest[startIdx+17]==1 && dest[startIdx+26]==1 && dest[startIdx+35]==1 && dest[startIdx+44]==1 && dest[startIdx+53]==1){ - //confirmed proper separator bits found - //return start position - return (int) startIdx; - } - return -5; -} - -// by marshmellow -// find viking preamble 0xF200 in already demoded data -int VikingDemod_AM(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,1,1,1,0,0,1,0,0,0,0,0,0,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 - uint32_t checkCalc = bytebits_to_byte(dest+startIdx,8) ^ bytebits_to_byte(dest+startIdx+8,8) ^ bytebits_to_byte(dest+startIdx+16,8) - ^ bytebits_to_byte(dest+startIdx+24,8) ^ bytebits_to_byte(dest+startIdx+32,8) ^ bytebits_to_byte(dest+startIdx+40,8) - ^ bytebits_to_byte(dest+startIdx+48,8) ^ bytebits_to_byte(dest+startIdx+56,8); - if ( checkCalc != 0xA8 ) return -5; - if (*size != 64) return -6; - //return start position - 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) -{ - //make sure buffer has enough data - if (*size < 128) return -1; - - size_t startIdx = 0; - uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,1}; - - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -2; //preamble not found - return (int)startIdx; -} - -// by marshmellow -// FSK Demod then try to locate an AWID ID -int AWIDdemodFSK(uint8_t *dest, size_t *size) -{ - //make sure buffer has enough data - if (*size < 96*50) return -1; - - if (justNoise(dest, *size)) return -2; - - // FSK demodulator - *size = fskdemod(dest, *size, 50, 1, 10, 8); // fsk2a RF/50 - if (*size < 96) return -3; //did we get a good demod? - - uint8_t preamble[] = {0,0,0,0,0,0,0,1}; - size_t startIdx = 0; - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -4; //preamble not found - if (*size != 96) return -5; - return (int)startIdx; -} - -// by marshmellow -// FSK Demod then try to locate a Farpointe Data (pyramid) ID -int PyramiddemodFSK(uint8_t *dest, size_t *size) -{ - //make sure buffer has data - if (*size < 128*50) return -5; - - //test samples are not just noise - if (justNoise(dest, *size)) return -1; - - // FSK demodulator - *size = fskdemod(dest, *size, 50, 1, 10, 8); // fsk2a RF/50 - if (*size < 128) return -2; //did we get a good demod? - - uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; - size_t startIdx = 0; - uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); - if (errChk == 0) return -4; //preamble not found - if (*size != 128) return -3; - return (int)startIdx; -} - // by marshmellow // to detect a wave that has heavily clipped (clean) samples -uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low) -{ +uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low) { bool allArePeaks = true; uint16_t cntPeaks=0; size_t loopEnd = 512+160; @@ -816,31 +342,30 @@ uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t lo } return allArePeaks; } + +//********************************************************************************************** +//-------------------Clock / Bitrate Detection Section------------------------------------------ +//********************************************************************************************** + // by marshmellow // to help detect clocks on heavily clipped samples // based on count of low to low -int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low, int *clock) { - uint8_t fndClk[] = {8,16,32,40,50,64,128}; +int DetectStrongAskClock(uint8_t dest[], size_t size, int high, int low, int *clock) { size_t startwave; size_t i = 100; size_t minClk = 255; int shortestWaveIdx = 0; // get to first full low to prime loop and skip incomplete first pulse - while ((dest[i] < high) && (i < size)) - ++i; - while ((dest[i] > low) && (i < size)) - ++i; + getNextHigh(dest, size, high, &i); + getNextLow(dest, size, low, &i); // loop through all samples while (i < size) { // measure from low to low - while ((dest[i] > low) && (i < size)) - ++i; startwave = i; - while ((dest[i] < high) && (i < size)) - ++i; - while ((dest[i] > low) && (i < size)) - ++i; + + getNextHigh(dest, size, high, &i); + getNextLow(dest, size, low, &i); //get minimum measured distance if (i-startwave < minClk && i < size) { minClk = i - startwave; @@ -848,22 +373,19 @@ int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low, } } // set clock - if (g_debugMode==2) prnt("DEBUG ASK: detectstrongASKclk smallest wave: %d",minClk); - for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) { - if (minClk >= fndClk[clkCnt]-(fndClk[clkCnt]/8) && minClk <= fndClk[clkCnt]+1) { - *clock = fndClk[clkCnt]; - return shortestWaveIdx; - } - } - return 0; + if (g_debugMode==2) prnt("DEBUG ASK: DetectStrongAskClock smallest wave: %d",minClk); + *clock = getClosestClock(minClk); + if (*clock == 0) + return 0; + + return shortestWaveIdx; } // by marshmellow // not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) // maybe somehow adjust peak trimming value based on samples to fix? // return start index of best starting position for that clock and return clock (by reference) -int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) -{ +int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) { size_t i=1; uint8_t clk[] = {255,8,16,32,40,50,64,100,128,255}; uint8_t clkEnd = 9; @@ -959,109 +481,6 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) return bestStart[best]; } - -int DetectPSKClock(uint8_t dest[], size_t size, int clock) { - int firstPhaseShift = 0; - return DetectPSKClock_ext(dest, size, clock, &firstPhaseShift); -} - -//by marshmellow -//detect psk clock by reading each phase shift -// a phase shift is determined by measuring the sample length of each wave -int DetectPSKClock_ext(uint8_t dest[], size_t size, int clock, int *firstPhaseShift) { - uint8_t clk[]={255,16,32,40,50,64,100,128,255}; //255 is not a valid clock - uint16_t loopCnt = 4096; //don't need to loop through entire array... - if (size == 0) return 0; - if (size= dest[i+2]){ - if (waveStart == 0) { - waveStart = i+1; - //prnt("DEBUG: waveStart: %d",waveStart); - } else { - waveEnd = i+1; - //prnt("DEBUG: waveEnd: %d",waveEnd); - waveLenCnt = waveEnd-waveStart; - if (waveLenCnt > fc){ - firstFullWave = waveStart; - fullWaveLen=waveLenCnt; - break; - } - waveStart=0; - } - } - } - *firstPhaseShift = firstFullWave; - if (g_debugMode ==2) prnt("DEBUG PSK: firstFullWave: %d, waveLen: %d",firstFullWave,fullWaveLen); - //test each valid clock from greatest to smallest to see which lines up - for(clkCnt=7; clkCnt >= 1 ; clkCnt--){ - lastClkBit = firstFullWave; //set end of wave as clock align - waveStart = 0; - errCnt=0; - peakcnt=0; - if (g_debugMode == 2) prnt("DEBUG PSK: clk: %d, lastClkBit: %d",clk[clkCnt],lastClkBit); - - for (i = firstFullWave+fullWaveLen-1; i < loopCnt-2; i++){ - //top edge of wave = start of new wave - if (dest[i] < dest[i+1] && dest[i+1] >= dest[i+2]){ - if (waveStart == 0) { - waveStart = i+1; - waveLenCnt=0; - } else { //waveEnd - waveEnd = i+1; - waveLenCnt = waveEnd-waveStart; - if (waveLenCnt > fc){ - //if this wave is a phase shift - if (g_debugMode == 2) prnt("DEBUG PSK: phase shift at: %d, len: %d, nextClk: %d, i: %d, fc: %d",waveStart,waveLenCnt,lastClkBit+clk[clkCnt]-tol,i+1,fc); - if (i+1 >= lastClkBit + clk[clkCnt] - tol){ //should be a clock bit - peakcnt++; - lastClkBit+=clk[clkCnt]; - } else if (i lastClkBit + clk[clkCnt] + tol + fc){ - lastClkBit+=clk[clkCnt]; //no phase shift but clock bit - } - waveStart=i+1; - } - } - } - if (errCnt == 0){ - return clk[clkCnt]; - } - if (errCnt <= bestErr[clkCnt]) bestErr[clkCnt]=errCnt; - if (peakcnt > peaksdet[clkCnt]) peaksdet[clkCnt]=peakcnt; - } - //all tested with errors - //return the highest clk with the most peaks found - uint8_t best=7; - for (i=7; i>=1; i--){ - if (peaksdet[i] > peaksdet[best]) { - best = i; - } - if (g_debugMode == 2) prnt("DEBUG PSK: Clk: %d, peaks: %d, errs: %d, bestClk: %d",clk[i],peaksdet[i],bestErr[i],clk[best]); - } - return clk[best]; -} - int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){ //find shortest transition from high to low size_t i = 0; @@ -1091,15 +510,9 @@ int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){ return lowestTransition; } -int DetectNRZClock(uint8_t dest[], size_t size, int clock) { - size_t bestStart=0; - return DetectNRZClock_ext(dest, size, clock, &bestStart); -} - - //by marshmellow //detect nrz clock by reading #peaks vs no peaks(or errors) -int DetectNRZClock_ext(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx) { +int DetectNRZClock(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx) { size_t i=0; uint8_t clk[]={8,16,32,40,50,64,100,128,255}; size_t loopCnt = 4096; //don't need to loop through entire array... @@ -1215,98 +628,194 @@ int DetectNRZClock_ext(uint8_t dest[], size_t size, int clock, size_t *clockStar return clk[best]; } -// by marshmellow -// convert psk1 demod to psk2 demod -// only transition waves are 1s -void psk1TOpsk2(uint8_t *BitStream, size_t size) -{ - size_t i=1; - uint8_t lastBit=BitStream[0]; - for (; i BitStream[i-1] && BitStream[i] >= BitStream[i+1]) + break; + + for (; i < size-20; i++){ + if (BitStream[i] > BitStream[i-1] && BitStream[i] >= BitStream[i+1]){ + // new up transition + fcCounter++; + if (fskAdj){ + //if we had 5 and now have 9 then go back to 8 (for when we get a fc 9 instead of an 8) + if (lastFCcnt==5 && fcCounter==9) fcCounter--; + //if fc=9 or 4 add one (for when we get a fc 9 instead of 10 or a 4 instead of a 5) + if ((fcCounter==9) || fcCounter==4) fcCounter++; + // save last field clock count (fc/xx) + lastFCcnt = fcCounter; + } + // find which fcLens to save it to: + for (int ii=0; ii<15; ii++){ + if (fcLens[ii]==fcCounter){ + fcCnts[ii]++; + fcCounter=0; + break; + } + } + if (fcCounter>0 && fcLensFnd<15){ + //add new fc length + fcCnts[fcLensFnd]++; + fcLens[fcLensFnd++]=fcCounter; + } + fcCounter=0; } else { - BitStream[i]=0; + // count sample + fcCounter++; } } - return; -} - -// by marshmellow -// convert psk2 demod to psk1 demod -// from only transition waves are 1s to phase shifts change bit -void psk2TOpsk1(uint8_t *BitStream, size_t size) -{ - uint8_t phase=0; - for (size_t i=0; i*size) gLen = *size-20; - int high, low; - if (getHiLo(dest, gLen, &high, &low, 75, 75) < 1) return -3; //25% fuzz on high 25% fuzz on low - uint8_t bit=0; - //convert wave samples to 1's and 0's - for(i=20; i < *size-20; i++){ - if (dest[i] >= high) bit = 1; - if (dest[i] <= low) bit = 0; - dest[i] = bit; - } - //now demod based on clock (rf/32 = 32 1's for one 1 bit, 32 0's for one 0 bit) - size_t lastBit = 0; - size_t numBits = 0; - for(i=21; i < *size-20; i++) { - //if transition detected or large number of same bits - store the passed bits - if (dest[i] != dest[i-1] || (i-lastBit) == (10 * *clk)) { - memset(dest+numBits, dest[i-1] ^ *invert, (i - lastBit + (*clk/4)) / *clk); - numBits += (i - lastBit + (*clk/4)) / *clk; - lastBit = i-1; + uint8_t best1=14, best2=14, best3=14; + uint16_t maxCnt1=0; + // go through fclens and find which ones are bigest 2 + for (i=0; i<15; i++){ + // get the 3 best FC values + if (fcCnts[i]>maxCnt1) { + best3=best2; + best2=best1; + maxCnt1=fcCnts[i]; + best1=i; + } else if(fcCnts[i]>fcCnts[best2]){ + best3=best2; + best2=i; + } else if(fcCnts[i]>fcCnts[best3]){ + best3=i; } + if (g_debugMode==2) prnt("DEBUG countfc: FC %u, Cnt %u, best fc: %u, best2 fc: %u",fcLens[i],fcCnts[i],fcLens[best1],fcLens[best2]); } - *size = numBits; - return 0; + if (fcLens[best1]==0) return 0; + uint8_t fcH=0, fcL=0; + if (fcLens[best1]>fcLens[best2]){ + fcH=fcLens[best1]; + fcL=fcLens[best2]; + } else{ + fcH=fcLens[best2]; + fcL=fcLens[best1]; + } + if ((size-180)/fcH/3 > fcCnts[best1]+fcCnts[best2]) { + if (g_debugMode==2) prnt("DEBUG countfc: fc is too large: %u > %u. Not psk or fsk",(size-180)/fcH/3,fcCnts[best1]+fcCnts[best2]); + return 0; //lots of waves not psk or fsk + } + // TODO: take top 3 answers and compare to known Field clocks to get top 2 + + uint16_t fcs = (((uint16_t)fcH)<<8) | fcL; + if (fskAdj) return fcs; + return fcLens[best1]; } -uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow) { - int firstClockEdge = 0; - return detectFSKClk_ext(BitStream, size, fcHigh, fcLow, &firstClockEdge); +//by marshmellow +//detect psk clock by reading each phase shift +// a phase shift is determined by measuring the sample length of each wave +int DetectPSKClock_ext(uint8_t dest[], size_t size, int clock, int *firstPhaseShift) { + uint8_t clk[]={255,16,32,40,50,64,100,128,255}; //255 is not a valid clock + uint16_t loopCnt = 4096; //don't need to loop through entire array... + if (size == 0) return 0; + if (size= dest[i+2]){ + if (waveStart == 0) { + waveStart = i+1; + //prnt("DEBUG: waveStart: %d",waveStart); + } else { + waveEnd = i+1; + //prnt("DEBUG: waveEnd: %d",waveEnd); + waveLenCnt = waveEnd-waveStart; + if (waveLenCnt > fc){ + firstFullWave = waveStart; + fullWaveLen=waveLenCnt; + break; + } + waveStart=0; + } + } + } + *firstPhaseShift = firstFullWave; + if (g_debugMode ==2) prnt("DEBUG PSK: firstFullWave: %d, waveLen: %d",firstFullWave,fullWaveLen); + //test each valid clock from greatest to smallest to see which lines up + for(clkCnt=7; clkCnt >= 1 ; clkCnt--){ + lastClkBit = firstFullWave; //set end of wave as clock align + waveStart = 0; + errCnt=0; + peakcnt=0; + if (g_debugMode == 2) prnt("DEBUG PSK: clk: %d, lastClkBit: %d",clk[clkCnt],lastClkBit); + + for (i = firstFullWave+fullWaveLen-1; i < loopCnt-2; i++){ + //top edge of wave = start of new wave + if (dest[i] < dest[i+1] && dest[i+1] >= dest[i+2]){ + if (waveStart == 0) { + waveStart = i+1; + waveLenCnt=0; + } else { //waveEnd + waveEnd = i+1; + waveLenCnt = waveEnd-waveStart; + if (waveLenCnt > fc){ + //if this wave is a phase shift + if (g_debugMode == 2) prnt("DEBUG PSK: phase shift at: %d, len: %d, nextClk: %d, i: %d, fc: %d",waveStart,waveLenCnt,lastClkBit+clk[clkCnt]-tol,i+1,fc); + if (i+1 >= lastClkBit + clk[clkCnt] - tol){ //should be a clock bit + peakcnt++; + lastClkBit+=clk[clkCnt]; + } else if (i lastClkBit + clk[clkCnt] + tol + fc){ + lastClkBit+=clk[clkCnt]; //no phase shift but clock bit + } + waveStart=i+1; + } + } + } + if (errCnt == 0){ + return clk[clkCnt]; + } + if (errCnt <= bestErr[clkCnt]) bestErr[clkCnt]=errCnt; + if (peakcnt > peaksdet[clkCnt]) peaksdet[clkCnt]=peakcnt; + } + //all tested with errors + //return the highest clk with the most peaks found + uint8_t best=7; + for (i=7; i>=1; i--){ + if (peaksdet[i] > peaksdet[best]) { + best = i; + } + if (g_debugMode == 2) prnt("DEBUG PSK: Clk: %d, peaks: %d, errs: %d, bestClk: %d",clk[i],peaksdet[i],bestErr[i],clk[best]); + } + return clk[best]; +} + +int DetectPSKClock(uint8_t dest[], size_t size, int clock) { + int firstPhaseShift = 0; + return DetectPSKClock_ext(dest, size, clock, &firstPhaseShift); } //by marshmellow @@ -1417,297 +926,67 @@ uint8_t detectFSKClk_ext(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_ return clk[ii]; } -//by marshmellow -//countFC is to detect the field clock lengths. -//counts and returns the 2 most common wave lengths -//mainly used for FSK field clock detection -uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj) -{ - uint8_t fcLens[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - uint16_t fcCnts[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - uint8_t fcLensFnd = 0; - uint8_t lastFCcnt = 0; - uint8_t fcCounter = 0; - size_t i; - if (size < 180) return 0; - - // prime i to first up transition - for (i = 160; i < size-20; i++) - if (BitStream[i] > BitStream[i-1] && BitStream[i] >= BitStream[i+1]) - break; - - for (; i < size-20; i++){ - if (BitStream[i] > BitStream[i-1] && BitStream[i] >= BitStream[i+1]){ - // new up transition - fcCounter++; - if (fskAdj){ - //if we had 5 and now have 9 then go back to 8 (for when we get a fc 9 instead of an 8) - if (lastFCcnt==5 && fcCounter==9) fcCounter--; - //if fc=9 or 4 add one (for when we get a fc 9 instead of 10 or a 4 instead of a 5) - if ((fcCounter==9) || fcCounter==4) fcCounter++; - // save last field clock count (fc/xx) - lastFCcnt = fcCounter; - } - // find which fcLens to save it to: - for (int ii=0; ii<15; ii++){ - if (fcLens[ii]==fcCounter){ - fcCnts[ii]++; - fcCounter=0; - break; - } - } - if (fcCounter>0 && fcLensFnd<15){ - //add new fc length - fcCnts[fcLensFnd]++; - fcLens[fcLensFnd++]=fcCounter; - } - fcCounter=0; - } else { - // count sample - fcCounter++; - } - } - - uint8_t best1=14, best2=14, best3=14; - uint16_t maxCnt1=0; - // go through fclens and find which ones are bigest 2 - for (i=0; i<15; i++){ - // get the 3 best FC values - if (fcCnts[i]>maxCnt1) { - best3=best2; - best2=best1; - maxCnt1=fcCnts[i]; - best1=i; - } else if(fcCnts[i]>fcCnts[best2]){ - best3=best2; - best2=i; - } else if(fcCnts[i]>fcCnts[best3]){ - best3=i; - } - if (g_debugMode==2) prnt("DEBUG countfc: FC %u, Cnt %u, best fc: %u, best2 fc: %u",fcLens[i],fcCnts[i],fcLens[best1],fcLens[best2]); - } - if (fcLens[best1]==0) return 0; - uint8_t fcH=0, fcL=0; - if (fcLens[best1]>fcLens[best2]){ - fcH=fcLens[best1]; - fcL=fcLens[best2]; - } else{ - fcH=fcLens[best2]; - fcL=fcLens[best1]; - } - if ((size-180)/fcH/3 > fcCnts[best1]+fcCnts[best2]) { - if (g_debugMode==2) prnt("DEBUG countfc: fc is too large: %u > %u. Not psk or fsk",(size-180)/fcH/3,fcCnts[best1]+fcCnts[best2]); - return 0; //lots of waves not psk or fsk - } - // TODO: take top 3 answers and compare to known Field clocks to get top 2 - - uint16_t fcs = (((uint16_t)fcH)<<8) | fcL; - if (fskAdj) return fcs; - return fcLens[best1]; +uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow) { + int firstClockEdge = 0; + return detectFSKClk_ext(BitStream, size, fcHigh, fcLow, &firstClockEdge); } -//by marshmellow - demodulate PSK1 wave -//uses wave lengths (# Samples) -int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert) -{ - if (size == 0) return -1; - uint16_t loopCnt = 4096; //don't need to loop through entire array... - if (*size> 8; - if (fc2 == 10) return -1; //fsk found - quit - fc = fc & 0xFF; - if (fc!=2 && fc!=4 && fc!=8) return -1; - //PrintAndLog("DEBUG: FC: %d",fc); - *clock = DetectPSKClock(dest, *size, *clock); - if (*clock == 0) return -1; - - //find start of modulating data in trace - uint8_t threshold_value = 123; //-5 - i = findModStart(dest, *size, threshold_value, fc); - - //find first phase shift - int avgWaveVal=0, lastAvgWaveVal=0; - waveStart = i; - for (; i= dest[i+2]){ - waveEnd = i+1; - if (g_debugMode == 2) prnt("DEBUG PSK: waveEnd: %u, waveStart: %u",waveEnd, waveStart); - waveLenCnt = waveEnd-waveStart; - if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+3)){ //not first peak and is a large wave but not out of whack - lastAvgWaveVal = avgWaveVal/(waveLenCnt); - firstFullWave = waveStart; - fullWaveLen=waveLenCnt; - //if average wave value is > graph 0 then it is an up wave or a 1 (could cause inverting) - if (lastAvgWaveVal > threshold_value) curPhase ^= 1; - break; - } - waveStart = i+1; - avgWaveVal = 0; - } - avgWaveVal += dest[i+2]; - } - if (firstFullWave == 0) { - // no phase shift detected - could be all 1's or 0's - doesn't matter where we start - // so skip a little to ensure we are past any Start Signal - firstFullWave = 160; - memset(dest, curPhase, firstFullWave / *clock); - } else { - memset(dest, curPhase^1, firstFullWave / *clock); - } - //advance bits - numBits += (firstFullWave / *clock); - //set start of wave as clock align - lastClkBit = firstFullWave; - if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen); - if (g_debugMode==2) prnt("DEBUG PSK: 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++){ - //top edge of wave = start of new wave - if (dest[i]+fc < dest[i+1] && dest[i+1] >= dest[i+2]){ - if (waveStart == 0) { - waveStart = i+1; - waveLenCnt = 0; - avgWaveVal = dest[i+1]; - } else { //waveEnd - waveEnd = i+1; - waveLenCnt = waveEnd-waveStart; - lastAvgWaveVal = avgWaveVal/waveLenCnt; - if (waveLenCnt > fc){ - //PrintAndLog("DEBUG: avgWaveVal: %d, waveSum: %d",lastAvgWaveVal,avgWaveVal); - //this wave is a phase shift - //PrintAndLog("DEBUG: phase shift at: %d, len: %d, nextClk: %d, i: %d, fc: %d",waveStart,waveLenCnt,lastClkBit+*clock-tol,i+1,fc); - if (i+1 >= lastClkBit + *clock - tol){ //should be a clock bit - curPhase ^= 1; - dest[numBits++] = curPhase; - lastClkBit += *clock; - } else if (i < lastClkBit+10+fc){ - //noise after a phase shift - ignore - } else { //phase shift before supposed to based on clock - errCnt++; - dest[numBits++] = 7; +// look for Sequence Terminator - should be pulses of clk*(1 or 2), clk*2, clk*(1.5 or 2), by idx we mean graph position index... +bool findST(int *stStopLoc, int *stStartIdx, int lowToLowWaveLen[], int highToLowWaveLen[], int clk, int tol, int buffSize, size_t *i) { + for (; *i < buffSize - 4; *i+=1) { + *stStartIdx += lowToLowWaveLen[*i]; //caution part of this wave may be data and part may be ST.... to be accounted for in main function for now... + if (lowToLowWaveLen[*i] >= clk*1-tol && lowToLowWaveLen[*i] <= (clk*2)+tol && highToLowWaveLen[*i] < clk+tol) { //1 to 2 clocks depending on 2 bits prior + if (lowToLowWaveLen[*i+1] >= clk*2-tol && lowToLowWaveLen[*i+1] <= clk*2+tol && highToLowWaveLen[*i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2 + if (lowToLowWaveLen[*i+2] >= (clk*3)/2-tol && lowToLowWaveLen[*i+2] <= clk*2+tol && highToLowWaveLen[*i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave + if (lowToLowWaveLen[*i+3] >= clk*1-tol && lowToLowWaveLen[*i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit + *stStopLoc = *i + 3; + return true; } - } else if (i+1 > lastClkBit + *clock + tol + fc){ - lastClkBit += *clock; //no phase shift but clock bit - dest[numBits++] = curPhase; - } else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often) - errCnt2++; - if(errCnt2 > 101) return errCnt2; } - avgWaveVal = 0; - waveStart = i+1; } } - avgWaveVal += dest[i+1]; } - *size = numBits; - return errCnt; + return false; } - -bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { - size_t ststart = 0, stend = 0; - return DetectST_ext(buffer, size, foundclock, &ststart, &stend); -} - //by marshmellow //attempt to identify a Sequence Terminator in ASK modulated raw wave bool DetectST_ext(uint8_t buffer[], size_t *size, int *foundclock, size_t *ststart, size_t *stend) { size_t bufsize = *size; //need to loop through all samples and identify our clock, look for the ST pattern - uint8_t fndClk[] = {8,16,32,40,50,64,128}; int clk = 0; int tol = 0; - int i, j, skip, start, end, low, high, minClk, waveStart; - bool complete = false; - 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 j, high, low, skip, start, end, minClk=255; + size_t i = 0; + //probably should malloc... || test if memory is available ... handle device side? memory danger!!! [marshmellow] + int tmpbuff[bufsize / LOWEST_DEFAULT_CLOCK]; // low to low wave count //guess rf/32 clock, if click is smaller we will only have room for a fraction of the samples captured + int waveLen[bufsize / LOWEST_DEFAULT_CLOCK]; // high to low wave count //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; memset(tmpbuff, 0, sizeof(tmpbuff)); + memset(waveLen, 0, sizeof(waveLen)); - if ( getHiLo(buffer, testsize, &high, &low, 80, 80) == -1 ) { - if (g_debugMode==2) prnt("DEBUG STT: just noise detected - quitting"); - return false; //just noise - } - i = 0; - j = 0; - minClk = 255; - // get to first full low to prime loop and skip incomplete first pulse - while ((buffer[i] < high) && (i < bufsize)) - ++i; - while ((buffer[i] > low) && (i < bufsize)) - ++i; - skip = i; - - // populate tmpbuff buffer with pulse lengths - while (i < bufsize) { - // measure from low to low - while ((buffer[i] > low) && (i < bufsize)) - ++i; - start= i; - while ((buffer[i] < high) && (i < bufsize)) - ++i; - //first high point for this wave - waveStart = i; - while ((buffer[i] > low) && (i < bufsize)) - ++i; - if (j >= (bufsize/32)) { - break; - } - waveLen[j] = i - waveStart; //first high to first low - tmpbuff[j++] = i - start; - if (i-start < minClk && i < bufsize) { - minClk = i - start; - } - } + if (!loadWaveCounters(buffer, bufsize, tmpbuff, waveLen, &j, &skip, &minClk, &high, &low)) return false; // set clock - might be able to get this externally and remove this work... - if (!clk) { - for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) { - tol = fndClk[clkCnt]/8; - if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) { - clk=fndClk[clkCnt]; - break; - } - } - // clock not found - ERROR - if (!clk) { - if (g_debugMode==2) prnt("DEBUG STT: clock not found - quitting"); - return false; - } - } else tol = clk/8; - + clk = getClosestClock(minClk); + // clock not found - ERROR + if (clk == 0) { + if (g_debugMode==2) prnt("DEBUG STT: clock not found - quitting"); + return false; + } *foundclock = clk; - // look for Sequence Terminator - should be pulses of clk*(1 or 1.5), clk*2, clk*(1.5 or 2) - start = -1; - for (i = 0; i < j - 4; ++i) { - skip += tmpbuff[i]; - 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 - start = i + 3; - break; - } - } - } - } - } - // first ST not found - ERROR - if (start < 0) { + tol = clk/8; + if (!findST(&start, &skip, tmpbuff, waveLen, clk, tol, j, &i)) { + // first ST not found - ERROR 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 (g_debugMode==2) prnt("DEBUG STT: first STT found at wave: %i, skip: %i, j=%i", start, skip, j); } if (waveLen[i+2] > clk*1+tol) phaseoff = 0; @@ -1718,26 +997,15 @@ bool DetectST_ext(uint8_t buffer[], size_t *size, int *foundclock, size_t *ststa skip += clk*7/2; //3.5 clocks from tmpbuff[i] = end of st - also aligns for ending point // now do it again to find the end + int dummy1 = 0; end = skip; - for (i += 3; i < j - 4; ++i) { - end += tmpbuff[i]; - 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 - complete = true; - break; - } - } - } - } - } - end -= phaseoff; - //didn't find second ST - ERROR - if (!complete) { + i+=3; + if (!findST(&dummy1, &end, tmpbuff, waveLen, clk, tol, j, &i)) { + //didn't find second ST - ERROR if (g_debugMode==2) prnt("DEBUG STT: second STT not found - quitting"); return false; } + end -= phaseoff; if (g_debugMode==2) prnt("DEBUG STT: start of data: %d end of data: %d, datalen: %d, clk: %d, bits: %d, phaseoff: %d", skip, end, end-skip, clk, (end-skip)/clk, phaseoff); //now begin to trim out ST so we can use normal demod cmds start = skip; @@ -1806,6 +1074,822 @@ bool DetectST_ext(uint8_t buffer[], size_t *size, int *foundclock, size_t *ststa *size = newloc; return true; } +bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) { + size_t ststart = 0, stend = 0; + return DetectST_ext(buffer, size, foundclock, &ststart, &stend); +} + +//by marshmellow +//take 11 10 01 11 00 and make 01100 ... miller decoding +//check for phase errors - should never have half a 1 or 0 by itself and should never exceed 1111 or 0000 in a row +//decodes miller encoded binary +//NOTE askrawdemod will NOT demod miller encoded ask unless the clock is manually set to 1/2 what it is detected as! +int millerRawDecode(uint8_t *BitStream, size_t *size, int invert) { + if (*size < 16) return -1; + uint16_t MaxBits = 512, errCnt = 0; + size_t i, bitCnt=0; + uint8_t alignCnt = 0, curBit = BitStream[0], alignedIdx = 0; + uint8_t halfClkErr = 0; + //find alignment, needs 4 1s or 0s to properly align + for (i=1; i < *size-1; i++) { + alignCnt = (BitStream[i] == curBit) ? alignCnt+1 : 0; + curBit = BitStream[i]; + if (alignCnt == 4) break; + } + // for now error if alignment not found. later add option to run it with multiple offsets... + if (alignCnt != 4) { + if (g_debugMode) prnt("ERROR MillerDecode: alignment not found so either your bitstream is not miller or your data does not have a 101 in it"); + return -1; + } + alignedIdx = (i-1) % 2; + for (i=alignedIdx; i < *size-3; i+=2) { + halfClkErr = (uint8_t)((halfClkErr << 1 | BitStream[i]) & 0xFF); + if ( (halfClkErr & 0x7) == 5 || (halfClkErr & 0x7) == 2 || (i > 2 && (halfClkErr & 0x7) == 0) || (halfClkErr & 0x1F) == 0x1F) { + errCnt++; + BitStream[bitCnt++] = 7; + continue; + } + BitStream[bitCnt++] = BitStream[i] ^ BitStream[i+1] ^ invert; + + if (bitCnt > MaxBits) break; + } + *size = bitCnt; + return errCnt; +} + +//by marshmellow +//take 01 or 10 = 1 and 11 or 00 = 0 +//check for phase errors - should never have 111 or 000 should be 01001011 or 10110100 for 1010 +//decodes biphase or if inverted it is AKA conditional dephase encoding AKA differential manchester encoding +int BiphaseRawDecode(uint8_t *BitStream, size_t *size, int offset, int invert) { + uint16_t bitnum = 0; + uint16_t errCnt = 0; + size_t i = offset; + uint16_t MaxBits=512; + //if not enough samples - error + if (*size < 51) return -1; + //check for phase change faults - skip one sample if faulty + uint8_t offsetA = 1, offsetB = 1; + for (; i<48; i+=2){ + if (BitStream[i+1]==BitStream[i+2]) offsetA=0; + if (BitStream[i+2]==BitStream[i+3]) offsetB=0; + } + if (!offsetA && offsetB) offset++; + for (i=offset; i<*size-3; i+=2){ + //check for phase error + if (BitStream[i+1]==BitStream[i+2]) { + BitStream[bitnum++]=7; + errCnt++; + } + if((BitStream[i]==1 && BitStream[i+1]==0) || (BitStream[i]==0 && BitStream[i+1]==1)){ + BitStream[bitnum++]=1^invert; + } else if((BitStream[i]==0 && BitStream[i+1]==0) || (BitStream[i]==1 && BitStream[i+1]==1)){ + BitStream[bitnum++]=invert; + } else { + BitStream[bitnum++]=7; + errCnt++; + } + if(bitnum>MaxBits) break; + } + *size=bitnum; + return errCnt; +} + +//by marshmellow +//take 10 and 01 and manchester decode +//run through 2 times and take least errCnt +int manrawdecode(uint8_t * BitStream, size_t *size, uint8_t invert, uint8_t *alignPos) { + uint16_t bitnum=0, MaxBits = 512, errCnt = 0; + size_t i, ii; + uint16_t bestErr = 1000, bestRun = 0; + if (*size < 16) return -1; + //find correct start position [alignment] + for (ii=0;ii<2;++ii){ + for (i=ii; i<*size-3; i+=2) + if (BitStream[i]==BitStream[i+1]) + errCnt++; + + if (bestErr>errCnt){ + bestErr=errCnt; + bestRun=ii; + } + errCnt=0; + } + *alignPos=bestRun; + //decode + for (i=bestRun; i < *size-3; i+=2){ + if(BitStream[i] == 1 && (BitStream[i+1] == 0)){ + BitStream[bitnum++]=invert; + } else if((BitStream[i] == 0) && BitStream[i+1] == 1){ + BitStream[bitnum++]=invert^1; + } else { + BitStream[bitnum++]=7; + } + if(bitnum>MaxBits) break; + } + *size=bitnum; + return bestErr; +} + +//by marshmellow +//demodulates strong heavily clipped samples +int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low, int *startIdx) +{ + *startIdx=0; + size_t bitCnt=0, smplCnt=1, errCnt=0; + bool waveHigh = (BinStream[0] >= high); + for (size_t i=1; i < *size; i++){ + if (BinStream[i] >= high && waveHigh){ + smplCnt++; + } else if (BinStream[i] <= low && !waveHigh){ + smplCnt++; + } else { //transition + if ((BinStream[i] >= high && !waveHigh) || (BinStream[i] <= low && waveHigh)){ + if (smplCnt > clk-(clk/4)-1) { //full clock + if (smplCnt > clk + (clk/4)+1) { //too many samples + errCnt++; + if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); + BinStream[bitCnt++] = 7; + } else if (waveHigh) { + BinStream[bitCnt++] = invert; + BinStream[bitCnt++] = invert; + } else if (!waveHigh) { + BinStream[bitCnt++] = invert ^ 1; + BinStream[bitCnt++] = invert ^ 1; + } + if (*startIdx==0) *startIdx = i-clk; + waveHigh = !waveHigh; + smplCnt = 0; + } else if (smplCnt > (clk/2) - (clk/4)-1) { //half clock + if (waveHigh) { + BinStream[bitCnt++] = invert; + } else if (!waveHigh) { + BinStream[bitCnt++] = invert ^ 1; + } + if (*startIdx==0) *startIdx = i-(clk/2); + waveHigh = !waveHigh; + smplCnt = 0; + } else { + smplCnt++; + //transition bit oops + } + } else { //haven't hit new high or new low yet + smplCnt++; + } + } + } + *size = bitCnt; + return errCnt; +} + +//by marshmellow +//attempts to demodulate ask modulations, askType == 0 for ask/raw, askType==1 for ask/manchester +int askdemod_ext(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType, int *startIdx) { + if (*size==0) return -1; + int start = DetectASKClock(BinStream, *size, clk, maxErr); //clock default + 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, amp %d", *clk, start, amp); + + //start pos from detect ask clock is 1/2 clock offset + // NOTE: can be negative (demod assumes rest of wave was there) + *startIdx = start - (*clk/2); + uint8_t initLoopMax = 255; + if (initLoopMax > *size) initLoopMax = *size; + // Detect high and lows + //25% clip in case highs and lows aren't clipped [marshmellow] + int high, low; + if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1) + return -2; //just noise + + size_t errCnt = 0; + // if clean clipped waves detected run alternate demod + if (DetectCleanAskWave(BinStream, *size, high, low)) { + if (g_debugMode==2) prnt("DEBUG ASK: Clean Wave Detected - using clean wave demod"); + errCnt = cleanAskRawDemod(BinStream, size, *clk, *invert, high, low, startIdx); + if (askType) { //askman + uint8_t alignPos = 0; + errCnt = manrawdecode(BinStream, size, 0, &alignPos); + *startIdx += *clk/2 * alignPos; + if (g_debugMode) prnt("DEBUG ASK CLEAN: startIdx %i, alignPos %u", *startIdx, alignPos); + return errCnt; + } else { //askraw + return errCnt; + } + } + if (g_debugMode) prnt("DEBUG ASK WEAK: startIdx %i", *startIdx); + if (g_debugMode==2) prnt("DEBUG ASK: Weak Wave Detected - using weak wave demod"); + + int lastBit; //set first clock check - can go negative + size_t i, bitnum = 0; //output counter + uint8_t midBit = 0; + uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + size_t MaxBits = 3072; //max bits to collect + lastBit = start - *clk; + + for (i = start; i < *size; ++i) { + if (i-lastBit >= *clk-tol){ + if (BinStream[i] >= high) { + BinStream[bitnum++] = *invert; + } else if (BinStream[i] <= low) { + BinStream[bitnum++] = *invert ^ 1; + } else if (i-lastBit >= *clk+tol) { + if (bitnum > 0) { + if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i); + BinStream[bitnum++]=7; + errCnt++; + } + } else { //in tolerance - looking for peak + continue; + } + midBit = 0; + lastBit += *clk; + } else if (i-lastBit >= (*clk/2-tol) && !midBit && !askType){ + if (BinStream[i] >= high) { + BinStream[bitnum++] = *invert; + } else if (BinStream[i] <= low) { + BinStream[bitnum++] = *invert ^ 1; + } else if (i-lastBit >= *clk/2+tol) { + BinStream[bitnum] = BinStream[bitnum-1]; + bitnum++; + } else { //in tolerance - looking for peak + continue; + } + midBit = 1; + } + if (bitnum >= MaxBits) break; + } + *size = bitnum; + return errCnt; +} + +int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType) { + int start = 0; + return askdemod_ext(BinStream, size, clk, invert, maxErr, amp, askType, &start); +} + +// by marshmellow - demodulate NRZ wave - requires a read with strong signal +// peaks invert bit (high=1 low=0) each clock cycle = 1 bit determined by last peak +int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int *startIdx) { + if (justNoise(dest, *size)) return -1; + size_t clkStartIdx = 0; + *clk = DetectNRZClock(dest, *size, *clk, &clkStartIdx); + if (*clk==0) return -2; + size_t i, gLen = 4096; + if (gLen>*size) gLen = *size-20; + int high, low; + if (getHiLo(dest, gLen, &high, &low, 75, 75) < 1) return -3; //25% fuzz on high 25% fuzz on low + + uint8_t bit=0; + //convert wave samples to 1's and 0's + for(i=20; i < *size-20; i++){ + if (dest[i] >= high) bit = 1; + if (dest[i] <= low) bit = 0; + dest[i] = bit; + } + //now demod based on clock (rf/32 = 32 1's for one 1 bit, 32 0's for one 0 bit) + size_t lastBit = 0; + size_t numBits = 0; + for(i=21; i < *size-20; i++) { + //if transition detected or large number of same bits - store the passed bits + if (dest[i] != dest[i-1] || (i-lastBit) == (10 * *clk)) { + memset(dest+numBits, dest[i-1] ^ *invert, (i - lastBit + (*clk/4)) / *clk); + numBits += (i - lastBit + (*clk/4)) / *clk; + if (lastBit == 0) { + *startIdx = i - (numBits * *clk); + if (g_debugMode==2) prnt("DEBUG NRZ: startIdx %i", *startIdx); + } + lastBit = i-1; + } + } + *size = numBits; + return 0; +} + +//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, int *startIdx) { + size_t last_transition = 0; + size_t idx = 1; + if (fchigh==0) fchigh=10; + if (fclow==0) fclow=8; + //set the threshold close to 0 (graph) or 128 std to avoid static + size_t preLastSample = 0; + size_t LastSample = 0; + size_t currSample = 0; + if ( size < 1024 ) return 0; // not enough samples + + //find start of modulating data in trace + idx = findModStart(dest, size, fchigh); + // Need to threshold first sample + if(dest[idx] < FSK_PSK_THRESHOLD) dest[0] = 0; + else dest[0] = 1; + + last_transition = idx; + idx++; + size_t numBits = 0; + // 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 < size; idx++) { + // threshold current value + if (dest[idx] < FSK_PSK_THRESHOLD) dest[idx] = 0; + else dest[idx] = 1; + + // Check for 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) + //do nothing with extra garbage + } 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 (numBits > 1 && LastSample > (fchigh-2) && (preLastSample < (fchigh-1))){ + dest[numBits-1]=1; + } + dest[numBits++]=1; + if (numBits > 0 && *startIdx==0) *startIdx = idx - fclow; + } else if (currSample > (fchigh+1) && numBits < 3) { //12 + and first two bit = unusable garbage + //do nothing with beginning garbage and reset.. should be rare.. + numBits = 0; + } 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; + if (numBits > 0 && *startIdx==0) *startIdx = idx - fclow; + } else { //9+ = 10 sample waves (or 6+ = 7) + dest[numBits++]=0; + if (numBits > 0 && *startIdx==0) *startIdx = idx - fchigh; + } + last_transition = idx; + } + } + return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 +} + +//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, int *startIdx) { + uint8_t lastval=dest[0]; + size_t idx=0; + size_t numBits=0; + uint32_t n=1; + for( idx=1; idx < size; idx++) { + n++; + if (dest[idx]==lastval) continue; //skip until we hit a transition + + //find out how many bits (n) we collected (use 1/2 clk tolerance) + //if lastval was 1, we have a 1->0 crossing + if (dest[idx-1]==1) { + n = (n * fclow + rfLen/2) / rfLen; + } else {// 0->1 crossing + n = (n * fchigh + rfLen/2) / rfLen; + } + if (n == 0) n = 1; + + //first transition - save startidx + if (numBits == 0) { + if (lastval == 1) { //high to low + *startIdx += (fclow * idx) - (n*rfLen); + if (g_debugMode==2) prnt("DEBUG FSK: startIdx %i, fclow*idx %i, n*rflen %u", *startIdx, fclow*(idx), n*rfLen); + } else { + *startIdx += (fchigh * idx) - (n*rfLen); + if (g_debugMode==2) prnt("DEBUG FSK: startIdx %i, fchigh*idx %i, n*rflen %u", *startIdx, fchigh*(idx), n*rfLen); + } + } + + //add to our destination the bits we collected + memset(dest+numBits, dest[idx-1]^invert , n); + numBits += n; + n=0; + lastval=dest[idx]; + }//end for + // if valid extra bits at the end were all the same frequency - add them in + if (n > rfLen/fchigh) { + if (dest[idx-2]==1) { + n = (n * fclow + rfLen/2) / rfLen; + } else { + n = (n * fchigh + rfLen/2) / rfLen; + } + memset(dest+numBits, dest[idx-1]^invert , n); + numBits += n; + } + return numBits; +} + +//by marshmellow (from holiman's base) +// full fsk demod from GraphBuffer wave to decoded 1s and 0s (no mandemod) +int fskdemod_ext(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, int *startIdx) { + // FSK demodulator + size = fsk_wave_demod(dest, size, fchigh, fclow, startIdx); + size = aggregate_bits(dest, size, rfLen, invert, fchigh, fclow, startIdx); + return size; +} + +int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) { + int startIdx=0; + return fskdemod_ext(dest, size, rfLen, invert, fchigh, fclow, &startIdx); +} + +// by marshmellow +// convert psk1 demod to psk2 demod +// only transition waves are 1s +void psk1TOpsk2(uint8_t *BitStream, size_t size) { + size_t i=1; + uint8_t lastBit=BitStream[0]; + for (; i= samples[i+2]){ + waveEnd = i+1; + if (g_debugMode == 2) prnt("DEBUG PSK: waveEnd: %u, waveStart: %u", waveEnd, waveStart); + waveLenCnt = waveEnd-waveStart; + if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+8)){ //not first peak and is a large wave but not out of whack + lastAvgWaveVal = avgWaveVal/(waveLenCnt); + firstFullWave = waveStart; + *fullWaveLen = waveLenCnt; + //if average wave value is > graph 0 then it is an up wave or a 1 (could cause inverting) + if (lastAvgWaveVal > FSK_PSK_THRESHOLD) *curPhase ^= 1; + return firstFullWave; + } + waveStart = i+1; + avgWaveVal = 0; + } + avgWaveVal += samples[i+2]; + } + return 0; +} + +//by marshmellow - demodulate PSK1 wave +//uses wave lengths (# Samples) +int pskRawDemod_ext(uint8_t dest[], size_t *size, int *clock, int *invert, int *startIdx) { + if (*size < 170) return -1; + + uint8_t curPhase = *invert; + size_t i=0, numBits=0, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0; + uint16_t fc=0, fullWaveLen=0, waveLenCnt=0, avgWaveVal, tol=1; + uint16_t errCnt=0, errCnt2=0; + + fc = countFC(dest, *size, 1); + if ((fc >> 8) == 10) return -1; //fsk found - quit + fc = fc & 0xFF; + if (fc!=2 && fc!=4 && fc!=8) return -1; + *clock = DetectPSKClock(dest, *size, *clock); + if (*clock == 0) return -1; + + //find start of modulating data in trace + i = findModStart(dest, *size, fc); + + //find first phase shift + firstFullWave = pskFindFirstPhaseShift(dest, *size, &curPhase, i, fc, &fullWaveLen); + if (firstFullWave == 0) { + // no phase shift detected - could be all 1's or 0's - doesn't matter where we start + // so skip a little to ensure we are past any Start Signal + firstFullWave = 160; + memset(dest, curPhase, firstFullWave / *clock); + } else { + memset(dest, curPhase^1, firstFullWave / *clock); + } + //advance bits + numBits += (firstFullWave / *clock); + *startIdx = firstFullWave - (*clock * numBits)+2; + //set start of wave as clock align + lastClkBit = firstFullWave; + if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u, startIdx %i",firstFullWave,fullWaveLen, *startIdx); + if (g_debugMode==2) prnt("DEBUG PSK: 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++){ + //top edge of wave = start of new wave + if (dest[i]+fc < dest[i+1] && dest[i+1] >= dest[i+2]){ + if (waveStart == 0) { + waveStart = i+1; + waveLenCnt = 0; + avgWaveVal = dest[i+1]; + } else { //waveEnd + waveEnd = i+1; + waveLenCnt = waveEnd-waveStart; + if (waveLenCnt > fc){ + //this wave is a phase shift + //PrintAndLog("DEBUG: phase shift at: %d, len: %d, nextClk: %d, i: %d, fc: %d",waveStart,waveLenCnt,lastClkBit+*clock-tol,i+1,fc); + if (i+1 >= lastClkBit + *clock - tol){ //should be a clock bit + curPhase ^= 1; + dest[numBits++] = curPhase; + lastClkBit += *clock; + } else if (i < lastClkBit+10+fc){ + //noise after a phase shift - ignore + } else { //phase shift before supposed to based on clock + errCnt++; + dest[numBits++] = 7; + } + } else if (i+1 > lastClkBit + *clock + tol + fc){ + lastClkBit += *clock; //no phase shift but clock bit + dest[numBits++] = curPhase; + } else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often) + errCnt2++; + if(errCnt2 > 101) return errCnt2; + } + avgWaveVal = 0; + waveStart = i+1; + } + } + avgWaveVal += dest[i+1]; + } + *size = numBits; + return errCnt; +} + +int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert) { + int startIdx = 0; + return pskRawDemod_ext(dest, size, clock, invert, &startIdx); +} + +//********************************************************************************************** +//-----------------Tag format detection section------------------------------------------------- +//********************************************************************************************** + +// by marshmellow +// FSK Demod then try to locate an AWID ID +int AWIDdemodFSK(uint8_t *dest, size_t *size) { + //make sure buffer has enough data + if (*size < 96*50) return -1; + + if (justNoise(dest, *size)) return -2; + + // FSK demodulator + *size = fskdemod(dest, *size, 50, 1, 10, 8); // fsk2a RF/50 + if (*size < 96) return -3; //did we get a good demod? + + uint8_t preamble[] = {0,0,0,0,0,0,0,1}; + size_t startIdx = 0; + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -4; //preamble not found + if (*size != 96) return -5; + return (int)startIdx; +} + +//by marshmellow +//takes 1s and 0s and searches for EM410x format - output EM ID +uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo) +{ + //sanity checks + if (*size < 64) return 0; + if (BitStream[1]>1) return 0; //allow only 1s and 0s + + // 111111111 bit pattern represent start of frame + // include 0 in front to help get start pos + uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1}; + uint8_t errChk = 0; + uint8_t FmtLen = 10; // sets of 4 bits = end data + *startIdx = 0; + errChk = preambleSearch(BitStream, preamble, sizeof(preamble), size, startIdx); + if ( errChk == 0 || (*size != 64 && *size != 128) ) return 0; + if (*size == 128) FmtLen = 22; // 22 sets of 4 bits + + //skip last 4bit parity row for simplicity + *size = removeParity(BitStream, *startIdx + sizeof(preamble), 5, 0, FmtLen * 5); + if (*size == 40) { // std em410x format + *hi = 0; + *lo = ((uint64_t)(bytebits_to_byte(BitStream, 8)) << 32) | (bytebits_to_byte(BitStream + 8, 32)); + } else if (*size == 88) { // long em format + *hi = (bytebits_to_byte(BitStream, 24)); + *lo = ((uint64_t)(bytebits_to_byte(BitStream + 24, 32)) << 32) | (bytebits_to_byte(BitStream + 24 + 32, 32)); + } else { + return 0; + } + return 1; +} + +// 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) { + //make sure buffer has enough data + if (*size < 128) return -1; + + size_t startIdx = 0; + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,1}; + + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -2; //preamble not found + return (int)startIdx; +} + +// by marshmellow +// demod gProxIIDemod +// error returns as -x +// success returns start position in BitStream +// BitStream must contain previously askrawdemod and biphasedemoded data +int gProxII_Demod(uint8_t BitStream[], size_t *size) { + size_t startIdx=0; + uint8_t preamble[] = {1,1,1,1,1,0}; + + uint8_t errChk = preambleSearch(BitStream, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -3; //preamble not found + if (*size != 96) return -2; //should have found 96 bits + //check first 6 spacer bits to verify format + if (!BitStream[startIdx+5] && !BitStream[startIdx+10] && !BitStream[startIdx+15] && !BitStream[startIdx+20] && !BitStream[startIdx+25] && !BitStream[startIdx+30]){ + //confirmed proper separator bits found + //return start position + return (int) startIdx; + } + return -5; //spacer bits not found - not a valid gproxII +} + +// loop to get raw HID waveform then FSK demodulate the TAG ID from it +int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) { + if (justNoise(dest, *size)) return -1; + + size_t numStart=0, size2=*size, startIdx=0; + // FSK demodulator + *size = fskdemod(dest, size2,50,1,10,8); //fsk2a + if (*size < 96*2) return -2; + // 00011101 bit pattern represent start of frame, 01 pattern represents a 0 and 10 represents a 1 + uint8_t preamble[] = {0,0,0,1,1,1,0,1}; + // find bitstring in array + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -3; //preamble not found + + numStart = startIdx + sizeof(preamble); + // final loop, go over previously decoded FSK data and manchester decode into usable tag ID + for (size_t idx = numStart; (idx-numStart) < *size - sizeof(preamble); idx+=2){ + if (dest[idx] == dest[idx+1]){ + return -4; //not manchester data + } + *hi2 = (*hi2<<1)|(*hi>>31); + *hi = (*hi<<1)|(*lo>>31); + //Then, shift in a 0 or one into low + if (dest[idx] && !dest[idx+1]) // 1 0 + *lo=(*lo<<1)|1; + else // 0 1 + *lo=(*lo<<1)|0; + } + return (int)startIdx; +} + +int IOdemodFSK(uint8_t *dest, size_t size) { + if (justNoise(dest, size)) return -1; + //make sure buffer has data + if (size < 66*64) return -2; + // FSK demodulator + size = fskdemod(dest, size, 64, 1, 10, 8); // FSK2a RF/64 + if (size < 65) return -3; //did we get a good demod? + //Index map + //0 10 20 30 40 50 60 + //| | | | | | | + //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 + //----------------------------------------------------------------------------- + //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11 + // + //XSF(version)facility:codeone+codetwo + //Handle the data + size_t startIdx = 0; + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,1}; + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), &size, &startIdx); + if (errChk == 0) return -4; //preamble not found + + if (!dest[startIdx+8] && dest[startIdx+17]==1 && dest[startIdx+26]==1 && dest[startIdx+35]==1 && dest[startIdx+44]==1 && dest[startIdx+53]==1){ + //confirmed proper separator bits found + //return start position + return (int) startIdx; + } + return -5; +} + +// redesigned by marshmellow adjusted from existing decode functions +// indala id decoding - only tested on 26 bit tags, but attempted to make it work for more +int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert) { + //26 bit 40134 format (don't know other formats) + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + uint8_t preamble_i[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0}; + size_t startidx = 0; + if (!preambleSearch(bitStream, preamble, sizeof(preamble), size, &startidx)){ + // if didn't find preamble try again inverting + if (!preambleSearch(bitStream, preamble_i, sizeof(preamble_i), size, &startidx)) return -1; + *invert ^= 1; + } + if (*size != 64 && *size != 224) return -2; + if (*invert==1) + for (size_t i = startidx; i < *size; i++) + bitStream[i] ^= 1; + + return (int) startidx; +} + +// loop to get raw paradox waveform then FSK demodulate the TAG ID from it +int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) { + if (justNoise(dest, *size)) return -1; + + size_t numStart=0, size2=*size, startIdx=0; + // FSK demodulator + *size = fskdemod(dest, size2,50,1,10,8); //fsk2a + if (*size < 96) return -2; + + // 00001111 bit pattern represent start of frame, 01 pattern represents a 0 and 10 represents a 1 + uint8_t preamble[] = {0,0,0,0,1,1,1,1}; + + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -3; //preamble not found + + numStart = startIdx + sizeof(preamble); + // final loop, go over previously decoded FSK data and manchester decode into usable tag ID + for (size_t idx = numStart; (idx-numStart) < *size - sizeof(preamble); idx+=2){ + if (dest[idx] == dest[idx+1]) + return -4; //not manchester data + *hi2 = (*hi2<<1)|(*hi>>31); + *hi = (*hi<<1)|(*lo>>31); + //Then, shift in a 0 or one into low + if (dest[idx] && !dest[idx+1]) // 1 0 + *lo=(*lo<<1)|1; + else // 0 1 + *lo=(*lo<<1)|0; + } + 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; +} + +// by marshmellow +// FSK Demod then try to locate a Farpointe Data (pyramid) ID +int PyramiddemodFSK(uint8_t *dest, size_t *size) { + //make sure buffer has data + if (*size < 128*50) return -5; + + //test samples are not just noise + if (justNoise(dest, *size)) return -1; + + // FSK demodulator + *size = fskdemod(dest, *size, 50, 1, 10, 8); // fsk2a RF/50 + if (*size < 128) return -2; //did we get a good demod? + + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + size_t startIdx = 0; + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -4; //preamble not found + if (*size != 128) return -3; + return (int)startIdx; +} + +// by marshmellow +// find viking preamble 0xF200 in already demoded data +int VikingDemod_AM(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,1,1,1,0,0,1,0,0,0,0,0,0,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 + uint32_t checkCalc = bytebits_to_byte(dest+startIdx,8) ^ bytebits_to_byte(dest+startIdx+8,8) ^ bytebits_to_byte(dest+startIdx+16,8) + ^ bytebits_to_byte(dest+startIdx+24,8) ^ bytebits_to_byte(dest+startIdx+32,8) ^ bytebits_to_byte(dest+startIdx+40,8) + ^ bytebits_to_byte(dest+startIdx+48,8) ^ bytebits_to_byte(dest+startIdx+56,8); + if ( checkCalc != 0xA8 ) return -5; + if (*size != 64) return -6; + //return start position + return (int) startIdx; +} // by iceman // find Visa2000 preamble in already demoded data diff --git a/common/lfdemod.h b/common/lfdemod.h index b465a659..a881fa18 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -19,6 +19,7 @@ //generic extern size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType); extern int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType); +extern int askdemod_ext(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType, int *startIdx); extern void askAmp(uint8_t *BitStream, size_t size); extern int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert); extern uint32_t bytebits_to_byte(uint8_t* src, size_t numbits); @@ -28,23 +29,24 @@ extern int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxE extern uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low); extern uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow); extern uint8_t detectFSKClk_ext(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow, int *firstClockEdge); -extern int DetectNRZClock(uint8_t dest[], size_t size, int clock); -extern int DetectNRZClock_ext(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx); +extern int DetectNRZClock(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx); extern int DetectPSKClock(uint8_t dest[], size_t size, int clock); extern int DetectPSKClock_ext(uint8_t dest[], size_t size, int clock, int *firstPhaseShift); -extern int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low, int *clock); +extern int DetectStrongAskClock(uint8_t dest[], size_t size, int high, int low, int *clock); extern bool DetectST(uint8_t buffer[], size_t *size, int *foundclock); extern bool DetectST_ext(uint8_t buffer[], size_t *size, int *foundclock, size_t *ststart, size_t *stend); extern int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow); +extern int fskdemod_ext(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, int *startIdx); extern int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo); extern uint32_t manchesterEncode2Bytes(uint16_t datain); extern int ManchesterEncode(uint8_t *BitStream, size_t size); -extern int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert); -extern int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert); +extern int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert, uint8_t *alignPos); +extern int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int *startIdx); extern uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType); extern uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx); extern bool preambleSearchEx(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx, bool findone); extern int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert); +extern int pskRawDemod_ext(uint8_t dest[], size_t *size, int *clock, int *invert, int *startIdx); extern void psk2TOpsk1(uint8_t *BitStream, size_t size); extern void psk1TOpsk2(uint8_t *BitStream, size_t size); extern size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen); diff --git a/tools/nonce2key/Makefile b/tools/nonce2key/Makefile deleted file mode 100644 index 11e019de..00000000 --- a/tools/nonce2key/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -VPATH = ../../common/crapto1 -CC = gcc -LD = gcc -CFLAGS = -I../../common -Wall -O4 -LDFLAGS = - -OBJS = crypto1.o crapto1.o -HEADERS = crapto1.h -EXES = nonce2key -WINEXES = $(patsubst %, %.exe, $(EXES)) - -all: $(OBJS) $(EXES) - -%.o : %.c - $(CC) $(CFLAGS) -c -o $@ $< - -% : %.c - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $< - -clean: - rm -f $(OBJS) $(EXES) $(WINEXES) diff --git a/tools/nonce2key/nonce2key.c b/tools/nonce2key/nonce2key.c deleted file mode 100644 index b789dca4..00000000 --- a/tools/nonce2key/nonce2key.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "crapto1/crapto1.h" -#include -#include -typedef unsigned char byte_t; - -int main(const int argc, const char* argv[]) { - struct Crypto1State *state; - uint32_t pos, uid, nt, nr, rr, nr_diff; - byte_t bt, i, ks3x[8], par[8][8]; - uint64_t key_recovered; - uint64_t par_info; - uint64_t ks_info; - nr = rr = 0; - - if (argc < 5) { - printf("\nsyntax: %s \n\n",argv[0]); - return 1; - } - sscanf(argv[1],"%08x",&uid); - sscanf(argv[2],"%08x",&nt); - sscanf(argv[3],"%016" SCNx64,&par_info); - sscanf(argv[4],"%016" SCNx64,&ks_info); - - // Reset the last three significant bits of the reader nonce - nr &= 0xffffff1f; - - printf("\nuid(%08x) nt(%08x) par(%016" PRIx64 ") ks(%016" PRIx64 ")\n\n",uid,nt,par_info,ks_info); - - for (pos=0; pos<8; pos++) - { - ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f; - bt = (par_info >> (pos*8)) & 0xff; - for (i=0; i<8; i++) - { - par[7-pos][i] = (bt >> i) & 0x01; - } - } - - printf("|diff|{nr} |ks3|ks3^5|parity |\n"); - printf("+----+--------+---+-----+---------------+\n"); - for (i=0; i<8; i++) - { - nr_diff = nr | i << 5; - printf("| %02x |%08x|",i << 5, nr_diff); - printf(" %01x | %01x |",ks3x[i], ks3x[i]^5); - for (pos=0; pos<7; pos++) printf("%01x,",par[i][pos]); - printf("%01x|\n",par[i][7]); - } - - state = lfsr_common_prefix(nr,rr,ks3x,par); - lfsr_rollback_word(state,uid^nt,0); - crypto1_get_lfsr(state,&key_recovered); - printf("\nkey recovered: %012" PRIx64 "\n\n",key_recovered); - crypto1_destroy(state); - - return 0; -}