From a8ee668770c99f651346266a506b79192e944ab3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 7 Jul 2016 02:15:40 +0200 Subject: [PATCH 01/16] CHG: moved includes into header file where it belong --- armsrc/BigBuf.c | 6 +----- armsrc/BigBuf.h | 3 +++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 57eb8db1..91cf5ce8 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -8,11 +8,7 @@ //----------------------------------------------------------------------------- // BigBuf and functions to allocate/free parts of it. //----------------------------------------------------------------------------- - -#include -#include "proxmark3.h" -#include "apps.h" -#include "string.h" +#include "bigbuf.h" // BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces. // Also used to hold various smaller buffers and the Mifare Emulator Memory. diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 347c1a4c..61e82b86 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -12,6 +12,9 @@ #ifndef __BIGBUF_H #define __BIGBUF_H +#include "proxmark3.h" +#include "apps.h" +#include "string.h" #define BIGBUF_SIZE 40000 #define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame -- 2.39.5 From b9b480d0813a18ccd31ea8535c1f336d06942dcf Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 7 Jul 2016 10:01:50 +0200 Subject: [PATCH 02/16] chg: name error? --- armsrc/BigBuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 91cf5ce8..7d7a76d1 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -8,7 +8,7 @@ //----------------------------------------------------------------------------- // BigBuf and functions to allocate/free parts of it. //----------------------------------------------------------------------------- -#include "bigbuf.h" +#include "BigBuf.h" // BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces. // Also used to hold various smaller buffers and the Mifare Emulator Memory. -- 2.39.5 From 81ba7ee8376c73c4593d5ed1592807d663388e8b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 20 Jul 2016 12:02:08 +0200 Subject: [PATCH 03/16] CHG: minor changes to code, mostly newlines, change a value to #DEFINE END_OF_LIST_MARKER CHG: GOOD_BYTES_REQUIRED changed from 28 > 13, makes it nonce collecting part faster, but the fail rate goes also up. its a value to fiddle with. --- client/cmdhfmfhard.c | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/client/cmdhfmfhard.c b/client/cmdhfmfhard.c index 6da4a1d1..d3381214 100644 --- a/client/cmdhfmfhard.c +++ b/client/cmdhfmfhard.c @@ -37,7 +37,9 @@ #include #define CONFIDENCE_THRESHOLD 0.95 // Collect nonces until we are certain enough that the following brute force is successfull -#define GOOD_BYTES_REQUIRED 28 +#define GOOD_BYTES_REQUIRED 13 // default 28, could be smaller == faster + +#define END_OF_LIST_MARKER 0xFFFFFFFF static const float p_K[257] = { // the probability that a random nonce has a Sum Property == K 0.0290, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, @@ -199,7 +201,6 @@ static void init_nonce_memory(void) num_good_first_bytes = 0; } - static void free_nonce_list(noncelistentry_t *p) { if (p == NULL) { @@ -868,10 +869,10 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ time1 = clock() - time1; if ( time1 > 0 ) { - PrintAndLog("Acquired a total of %d nonces in %1.1f seconds (%0.0f nonces/minute)", - total_num_nonces, - ((float)time1)/CLOCKS_PER_SEC, - total_num_nonces * 60.0 * CLOCKS_PER_SEC/(float)time1 + PrintAndLog("Acquired a total of %d nonces in %1.1f seconds (%0.0f nonces/minute)", + total_num_nonces, + ((float)time1)/CLOCKS_PER_SEC, + total_num_nonces * 60.0 * CLOCKS_PER_SEC/(float)time1 ); } return 0; @@ -920,7 +921,7 @@ static int init_partial_statelists(void) for (uint16_t i = 0; i <= 16; i += 2) { uint32_t *p = partial_statelist[i].states[odd_even]; p += partial_statelist[i].len[odd_even]; - *p = 0xffffffff; + *p = END_OF_LIST_MARKER; } } @@ -946,7 +947,7 @@ static void init_BitFlip_statelist(void) } // set len and add End Of List marker statelist_bitflip.len[0] = p - statelist_bitflip.states[0]; - *p = 0xffffffff; + *p = END_OF_LIST_MARKER; statelist_bitflip.states[0] = realloc(statelist_bitflip.states[0], sizeof(uint32_t) * (statelist_bitflip.len[0] + 1)); } @@ -956,7 +957,7 @@ static inline uint32_t *find_first_state(uint32_t state, uint32_t mask, partial_ if (p == NULL) return NULL; while (*p < (state & mask)) p++; - if (*p == 0xffffffff) return NULL; // reached end of list, no match + if (*p == END_OF_LIST_MARKER) return NULL; // reached end of list, no match if ((*p & mask) == (state & mask)) return p; // found a match. return NULL; // no match } @@ -1034,7 +1035,7 @@ static bool all_other_first_bytes_match(uint32_t state, odd_even_t odd_even) uint16_t part_sum_a8 = (odd_even == ODD_STATE) ? r : s; uint32_t *p = find_first_state(state, mask, &partial_statelist[part_sum_a8], odd_even); if (p != NULL) { - while ((state & mask) == (*p & mask) && (*p != 0xffffffff)) { + while ((state & mask) == (*p & mask) && (*p != END_OF_LIST_MARKER)) { if (remaining_bits_match(j, bytes_diff, state, (state&0x00fffff0) | *p, odd_even)) { found_match = true; // if ((odd_even == ODD_STATE && state == test_state_odd) @@ -1092,7 +1093,7 @@ static bool all_bit_flips_match(uint32_t state, odd_even_t odd_even) bool found_match = false; uint32_t *p = find_first_state(state, mask, &statelist_bitflip, 0); if (p != NULL) { - while ((state & mask) == (*p & mask) && (*p != 0xffffffff)) { + while ((state & mask) == (*p & mask) && (*p != END_OF_LIST_MARKER)) { if (remaining_bits_match(j, bytes_diff, state, (state&0x00fffff0) | *p, odd_even)) { found_match = true; // if ((odd_even == ODD_STATE && state == test_state_odd) @@ -1165,11 +1166,11 @@ static int add_matching_states(statelist_t *candidates, uint16_t part_sum_a0, ui return 4; } uint32_t *add_p = candidates->states[odd_even]; - for (uint32_t *p1 = partial_statelist[part_sum_a0].states[odd_even]; *p1 != 0xffffffff; p1++) { + for (uint32_t *p1 = partial_statelist[part_sum_a0].states[odd_even]; *p1 != END_OF_LIST_MARKER; p1++) { uint32_t search_mask = 0x000ffff0; uint32_t *p2 = find_first_state((*p1 << 4), search_mask, &partial_statelist[part_sum_a8], odd_even); if (p2 != NULL) { - while (((*p1 << 4) & search_mask) == (*p2 & search_mask) && *p2 != 0xffffffff) { + while (((*p1 << 4) & search_mask) == (*p2 & search_mask) && *p2 != END_OF_LIST_MARKER) { if ((nonces[best_first_bytes[0]].BitFlip[odd_even] && find_first_state((*p1 << 4) | *p2, 0x000fffff, &statelist_bitflip, 0)) || !nonces[best_first_bytes[0]].BitFlip[odd_even]) { if (all_other_first_bytes_match((*p1 << 4) | *p2, odd_even)) { @@ -1184,7 +1185,7 @@ static int add_matching_states(statelist_t *candidates, uint16_t part_sum_a0, ui } // set end of list marker and len - *add_p = 0xffffffff; + *add_p = END_OF_LIST_MARKER; candidates->len[odd_even] = add_p - candidates->states[odd_even]; candidates->states[odd_even] = realloc(candidates->states[odd_even], sizeof(uint32_t) * (candidates->len[odd_even] + 1)); @@ -1230,14 +1231,14 @@ static void TestIfKeyExists(uint64_t key) bool found_even = false; uint32_t *p_odd = p->states[ODD_STATE]; uint32_t *p_even = p->states[EVEN_STATE]; - while (*p_odd != 0xffffffff) { + while (*p_odd != END_OF_LIST_MARKER) { if ((*p_odd & 0x00ffffff) == state_odd) { found_odd = true; break; } p_odd++; } - while (*p_even != 0xffffffff) { + while (*p_even != END_OF_LIST_MARKER) { if ((*p_even & 0x00ffffff) == state_even) { found_even = true; } @@ -1245,10 +1246,12 @@ static void TestIfKeyExists(uint64_t key) } count += (p_odd - p->states[ODD_STATE]) * (p_even - p->states[EVEN_STATE]); if (found_odd && found_even) { - PrintAndLog("Key Found after testing %lld (2^%1.1f) out of %lld (2^%1.1f) keys. A brute force would have taken approx %lld minutes.", - count, log(count)/log(2), - maximum_states, log(maximum_states)/log(2), - (count>>23)/60); + PrintAndLog("Key Found after testing %lld (2^%1.1f) out of %lld (2^%1.1f) keys. ", + count, + log(count)/log(2), + maximum_states, + log(maximum_states)/log(2) + ); if (write_stats) { fprintf(fstats, "1\n"); } @@ -1301,7 +1304,7 @@ static void generate_candidates(uint16_t sum_a0, uint16_t sum_a8) } else { current_candidates->len[EVEN_STATE] = 0; uint32_t *p = current_candidates->states[EVEN_STATE] = malloc(sizeof(uint32_t)); - *p = 0xffffffff; + *p = END_OF_LIST_MARKER; } } else { add_matching_states(current_candidates, q, s, EVEN_STATE); @@ -1310,7 +1313,7 @@ static void generate_candidates(uint16_t sum_a0, uint16_t sum_a8) } else { current_candidates->len[ODD_STATE] = 0; uint32_t *p = current_candidates->states[ODD_STATE] = malloc(sizeof(uint32_t)); - *p = 0xffffffff; + *p = END_OF_LIST_MARKER; } } //printf("Odd state candidates: %6d (2^%0.1f)\n", current_candidates->len[ODD_STATE], log(current_candidates->len[ODD_STATE])/log(2)); @@ -1673,7 +1676,7 @@ static void brute_force(void) pthread_t threads[thread_count]; // enumerate states using all hardware threads, each thread handles one bucket - PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %"PRIu32" states...", thread_count, bucket_count, maximum_states); + PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %"PRIu64" states...", thread_count, bucket_count, maximum_states); for(size_t i = 0; i < thread_count; i++){ pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); @@ -1682,13 +1685,14 @@ static void brute_force(void) pthread_join(threads[i], 0); } - time(&end); - unsigned long elapsed_time = difftime(end, start); + time(&end); + double elapsed_time = difftime(end, start); + PrintAndLog(""); if(keys_found){ - PrintAndLog("Success! Tested %"PRIu32" states, found %u keys after %u seconds", total_states_tested, keys_found, elapsed_time); + PrintAndLog("Success! Tested %"PRIu64" states, found %u keys after %.f seconds", total_states_tested, keys_found, elapsed_time); PrintAndLog("\nFound key: %012"PRIx64"\n", foundkey); } else { - PrintAndLog("Fail! Tested %"PRIu32" states, in %u seconds", total_states_tested, elapsed_time); + PrintAndLog("Fail! Tested %"PRIu64" states, in %.f seconds", total_states_tested, elapsed_time); } // reset this counter for the next call nonces_to_bruteforce = 0; @@ -1772,6 +1776,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc PrintAndLog("Time for generating key candidates list: %1.0f seconds", ((float)time1)/CLOCKS_PER_SEC); brute_force(); + free_nonces_memory(); free_statelist_cache(); free_candidates_memory(candidates); -- 2.39.5 From 36e78d669c9c3765f7f3b020d3901fe0ddba2598 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 21 Jul 2016 17:26:17 +0200 Subject: [PATCH 04/16] CHG: added some includes / libarys for HomeBrew AND QT5 compiling on MAC OSX. They are commented away, but if you need it replace the other two lines and uncomment. All credit to @koalazak [ref] https://github.com/Proxmark/proxmark3/pull/184/commits/ed1525805c940fe738fc05286ffd22e0ce3a0fbf --- client/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/Makefile b/client/Makefile index 8ccd1cea..616a2a74 100644 --- a/client/Makefile +++ b/client/Makefile @@ -41,9 +41,16 @@ ifneq (,$(findstring MINGW,$(platform))) endif else ifeq ($(platform),Darwin) + + # Assuming you have QT4 installed. CFLAGS += -I/usr/include/malloc/ -I/usr/local/opt/readline/include LDLIBS = -L/opt/local/lib -L/usr/local/opt/readline/lib -lreadline -lpthread -lm - CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O3 + + # use this if you have QT5 installed. + #CFLAGS += -I/usr/include/malloc/ -I/usr/local/opt/readline/include -I/usr/local/opt/qt5/include + #LDLIBS = -L/opt/local/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/qt5/lib -lreadline -lpthread -lm + + CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O3 QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) MOC = $(shell pkg-config --variable=moc_location QtCore) LUAPLATFORM = macosx -- 2.39.5 From e13ccb6b3ff004ecdcb19f6b27719dd4c3002a50 Mon Sep 17 00:00:00 2001 From: k02a Date: Fri, 22 Jul 2016 09:49:02 +0200 Subject: [PATCH 05/16] Inclusion of unused oem variable MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When compilation of the current source code, I am getting the warning of setting the unused variable "oem". I have included this, along with minor spelling corrections/language updates in the menu system. gcc -std=c99 -O3 -mpopcnt -march=native -g -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall -DHAVE_GUI -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED -c -o obj/cmdlfhid.o cmdlfhid.c cmdlfhid.c: I funktion "CmdHIDWiegand": cmdlfhid.c:292:11: varning: variabeln "oem" sätts men används inte [-Wunused-but-set-variable] uint32_t oem; ^ Before: pm3 --> lf hid wiegand 0 101 2001 HID 26 bit | FC: 101 CN: 2001 | Wiegand Code: 0000002004CA0FA2 [...] HID 40 bit | FC: 101 CN: 2001 | Wiegand Code: 0000000000000FA2 After: pm3 --> lf hid wiegand 0 101 2001 HID 26 bit | OEM: 0 FC: 101 CN: 2001 | Wiegand code: 0000002004CA0FA2 [...] HID 40 bit | OEM: 0 FC: 101 CN: 2001 | Wiegand code: 0000000000000FA2 --- client/cmdlfhid.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 5bdeea6d..00a4722a 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -22,26 +22,26 @@ static int CmdHelp(const char *Cmd); int usage_lf_hid_wiegand(void){ - PrintAndLog("Usage: lf hid wiegand [h] [oem] [FacilityCode] [cardnumber]"); - PrintAndLog("This command converts FC/Cardnum to wiegand code"); + PrintAndLog("Usage: lf hid wiegand [h] [OEM] [FC] [CN]"); + PrintAndLog("This command converts facility code/card number to Wiegand code"); PrintAndLog("Options:"); - PrintAndLog(" h - This help"); - PrintAndLog(" oem - Oem number"); - PrintAndLog(" facilitynum - Facility number"); - PrintAndLog(" cardnum - Card number"); + PrintAndLog(" h - This help"); + PrintAndLog(" OEM - OEM number"); + PrintAndLog(" FC - facility code"); + PrintAndLog(" CN - card number"); PrintAndLog("Examples:"); PrintAndLog(" lf hid wiegand 0 101 2001"); return 0; } int usage_lf_hid_brute(void){ - PrintAndLog("Enables bruteforce of HID readers with specified facility-code."); + PrintAndLog("Enables bruteforce of HID readers with specified facility code."); PrintAndLog("Different formatlength is supported"); PrintAndLog("This is a incremental attack against reader."); PrintAndLog(""); - PrintAndLog("Usage: lf hid brute "); + PrintAndLog("Usage: lf hid brute "); PrintAndLog("Options :"); - PrintAndLog(" - 26|33|34|35|37|40|44|84"); - PrintAndLog(" - 8-bit value HID facility code"); + PrintAndLog(" - 26|33|34|35|37|40|44|84"); + PrintAndLog(" - 8-bit value HID facility code"); PrintAndLog(""); PrintAndLog("Sample : lf hid brute 26 224"); return 0; @@ -303,7 +303,7 @@ int CmdHIDWiegand(const char *Cmd) { uint8_t ftmlen[] = {26,33,34,35,37,38,40}; for (uint8_t i = 0; i < sizeof(ftmlen); i++){ calcWiegand( ftmlen[i], fc, cardnum, &hi, &lo); - PrintAndLog("HID %d bit | FC: %d CN: %llu | Wiegand Code: %08X%08X", ftmlen[i], fc, cardnum, hi, lo); + PrintAndLog("HID %d bit | OEM: %d FC: %d CN: %llu | Wiegand code: %08X%08X", ftmlen[i], oem, fc, cardnum, hi, lo); } return 0; } @@ -332,7 +332,7 @@ int CmdHIDBrute(const char *Cmd){ fc = param_get8(Cmd, 1); if ( fc == 0) return usage_lf_hid_brute(); - PrintAndLog("Bruteforceing HID Reader"); + PrintAndLog("Brute-forcing HID reader"); PrintAndLog("Press pm3-button to abort simulation or run another command"); for ( uint16_t cn = 1; cn < 0xFFFF; ++cn){ @@ -362,13 +362,13 @@ int CmdHIDBrute(const char *Cmd){ } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - //{"demod", CmdHIDDemod, 1, "Demodulate HID Prox Card II (not optimal)"}, - {"fskdemod",CmdHIDDemodFSK, 0, "['1'] Realtime HID FSK demodulator (option '1' for one tag only)"}, - {"sim", CmdHIDSim, 0, " -- HID tag simulator"}, - {"clone", CmdHIDClone, 0, " ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, - {"wiegand", CmdHIDWiegand, 0, " -- convert facilitycode, cardnumber to Wiegand code"}, - {"brute", CmdHIDBrute, 0, " -- bruteforce card number"}, + {"help", CmdHelp, 1, "This help"}, +// {"demod", CmdHIDDemod, 1, "Demodulate HID Prox Card II (not optimal)"}, + {"fskdemod",CmdHIDDemodFSK, 0, "['1'] Realtime HID FSK demodulator (option '1' for one tag only)"}, + {"sim", CmdHIDSim, 0, " -- HID tag simulator"}, + {"clone", CmdHIDClone, 0, " ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, + {"wiegand", CmdHIDWiegand, 0, " -- convert facility code/card number to Wiegand code"}, + {"brute", CmdHIDBrute, 0, " -- brute force card number"}, {NULL, NULL, 0, NULL} }; -- 2.39.5 From a360a90bb613c17bf6ee57f2e50d267579480b1b Mon Sep 17 00:00:00 2001 From: k02a Date: Fri, 22 Jul 2016 13:40:05 +0200 Subject: [PATCH 06/16] Improved compilation compability on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Compilation of Lua on a currently updated Slackware Linux 14.2 x86_64 vanilla distribution will cause some errors, due to a missing flags in the Makefile. I noticed that adding the termcap library solves the problem. I also found a thread (http://lua.2524044.n2.nabble.com/readline-termcap-ncurses-td5726148.html ) where other Linux distributions might have similar problems with Lua. Included version of liblua, derived from Lua 5.2.2, also seems to depend on the Termcap library and/or ncurses library. Output: bash-4.3$ make -C proxmark3 make: GÃ¥r till katalogen "/home/github/iceman1001/proxmark3" make -C client all make[1]: GÃ¥r till katalogen "/home/github/iceman1001/proxmark3/client" Compiling liblua, using platform linux cd ../liblua && make linux make[2]: GÃ¥r till katalogen "/home/github/iceman1001/proxmark3/liblua" make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" make[3]: GÃ¥r till katalogen "/home/github/iceman1001/proxmark3/liblua" gcc -O3 -Wall -DLUA_COMPAT_ALL -DLUA_USE_LINUX -c -o lapi.o lapi.c [...] gcc -O3 -Wall -DLUA_COMPAT_ALL -DLUA_USE_LINUX -c -o linit.o linit.c ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o ranlib liblua.a gcc -O3 -Wall -DLUA_COMPAT_ALL -DLUA_USE_LINUX -c -o lua.o lua.c gcc -o lua lua.o liblua.a -lm -Wl,-E -ldl -lreadline /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tputs' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgoto' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetflag' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `UP' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetent' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetnum' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `PC' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetstr' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `BC' collect2: fel: ld returnerade avslutningsstatus 1 Makefile:63: receptet för mÃ¥let "lua" misslyckades make[3]: *** [lua] Fel 1 make[3]: Lämnar katalogen "/home/github/iceman1001/proxmark3/liblua" Makefile:106: receptet för mÃ¥let "linux" misslyckades make[2]: *** [linux] Fel 2 make[2]: Lämnar katalogen "/home/github/iceman1001/proxmark3/liblua" Makefile:203: receptet för mÃ¥let "lua_build" misslyckades make[1]: *** [lua_build] Fel 2 make[1]: Lämnar katalogen "/home/github/iceman1001/proxmark3/client" Makefile:12: receptet för mÃ¥let "client/all" misslyckades make: *** [client/all] Fel 2 make: Lämnar katalogen "/home/github/iceman1001/proxmark3" --- liblua/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liblua/Makefile b/liblua/Makefile index 12be8e83..89a11e71 100644 --- a/liblua/Makefile +++ b/liblua/Makefile @@ -103,7 +103,7 @@ freebsd: generic: $(ALL) linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -ltermcap -lncurses" macosx: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" -- 2.39.5 From 39814f19abaa972dec4831bfc0f8eb207e098437 Mon Sep 17 00:00:00 2001 From: k02a Date: Fri, 22 Jul 2016 13:52:12 +0200 Subject: [PATCH 07/16] Addition of depending library flags... MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Inclusion of termcap library or ncurses library solves the compilation errors on some Linux distributions, for example a currently updated Slackware Linux 14.2 x86_64 vanilla distribution (which I run). Output: bash-4.3# make -C proxmark3 [...] g++ -DQT_SHARED -I/usr/lib64/qt/include/QtGui -I/usr/lib64/qt/include/QtCore -Wall -O3 obj/proxmark3.o obj/uart.o obj/util.o obj/sleep.o obj/nonce2key/crapto1.o obj/nonce2key/crypto1.o obj/nonce2key/nonce2key.o obj/nonce2key/crypto1_bs.o obj/loclass/cipher.o obj/loclass/cipherutils.o obj/loclass/des.o obj/loclass/ikeys.o obj/loclass/elite_crack.o obj/loclass/fileutils.o obj/mifarehost.o obj/parity.o obj/crc.o obj/crc16.o obj/crc64.o obj/iso14443crc.o obj/iso15693tools.o obj/data.o obj/graph.o obj/ui.o obj/cmddata.o obj/lfdemod.o obj/cmdanalyse.o obj/cmdhf.o obj/cmdhf14a.o obj/cmdhf14b.o obj/cmdhf15.o obj/cmdhfepa.o obj/cmdhflegic.o obj/cmdhficlass.o obj/cmdhfmf.o obj/cmdhfmfu.o obj/cmdhfmfhard.o obj/cmdhfmfdes.o obj/cmdhftopaz.o obj/cmdhw.o obj/cmdlf.o obj/cmdlfio.o obj/cmdlfhid.o obj/cmdlfawid.o obj/cmdlfem4x.o obj/cmdlfhitag.o obj/cmdlfti.o obj/cmdparser.o obj/cmdmain.o obj/cmdlft55xx.o obj/cmdlfpcf7931.o obj/cmdlfviking.o obj/cmdlfpresco.o obj/cmdlfpyramid.o obj/cmdlfguard.o obj/cmdlfnedap.o obj/pm3_binlib.o obj/scripting.o obj/cmdscript.o obj/pm3_bitlib.o obj/aes.o obj/protocols.o obj/sha1.o obj/sha256.o obj/cmdcrc.o obj/reveng/preset.o obj/reveng/reveng.o obj/reveng/cli.o obj/reveng/bmpbit.o obj/reveng/model.o obj/reveng/poly.o obj/reveng/getopt.o obj/tea.o obj/prng.o obj/radixsort.o obj/bucketsort.o obj/proxgui.o obj/proxguiqt.o obj/proxguiqt.moc.o -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm ../liblua/liblua.a -ldl -L/usr/lib64/qt/lib -lQtGui -lQtCore -o proxmark3 /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetstr' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tputs' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `BC' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetent' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetflag' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgoto' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `UP' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `tgetnum' /usr/lib64/gcc/x86_64-slackware-linux/5.3.0/../../../../lib64/libreadline.so: undefined reference to `PC' collect2: fel: ld returnerade avslutningsstatus 1 Makefile:172: receptet för mÃ¥let "proxmark3" misslyckades make[1]: *** [proxmark3] Fel 1 make[1]: Lämnar katalogen "/home/github/iceman1001/proxmark3/client" Makefile:12: receptet för mÃ¥let "client/all" misslyckades make: *** [client/all] Fel 2 make: Lämnar katalogen "/home/github/iceman1001/proxmark3" --- client/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/client/Makefile b/client/Makefile index 616a2a74..7b9a65fd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -58,6 +58,7 @@ else CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O3 QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) LUALIB += -ldl + LDLIBS += -ltermcap -lncurses MOC = $(shell pkg-config --variable=moc_location QtCore) # Below is a variant you can use if you have problems compiling with QT5 on ubuntu. see http://www.proxmark.org/forum/viewtopic.php?id=1661 for more info. #MOC = /usr/lib/x86_64-linux-gnu/qt4/bin/moc -- 2.39.5 From 2de9622f0e8244c06acbce41fc5501ba7304e85b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 23 Jul 2016 18:31:20 +0200 Subject: [PATCH 08/16] CHG: some clearing of memory --- client/nonce2key/crypto1_bs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/nonce2key/crypto1_bs.c b/client/nonce2key/crypto1_bs.c index 9a0272dd..7fd1b715 100644 --- a/client/nonce2key/crypto1_bs.c +++ b/client/nonce2key/crypto1_bs.c @@ -80,7 +80,9 @@ inline const bitslice_value_t crypto1_bs_lfsr_rollback(const bitslice_value_t in // note that bytes are sliced and unsliced with reversed endianness inline void crypto1_bs_convert_states(bitslice_t bitsliced_states[], state_t regular_states[]){ size_t bit_idx = 0, slice_idx = 0; - state_t values[MAX_BITSLICES] = {{0x00}}; + state_t values[MAX_BITSLICES]; + memset(values, 0x0, sizeof(values)); + for(slice_idx = 0; slice_idx < MAX_BITSLICES; slice_idx++){ for(bit_idx = 0; bit_idx < STATE_SIZE; bit_idx++){ bool bit = get_vector_bit(slice_idx, bitsliced_states[bit_idx]); @@ -90,7 +92,8 @@ inline void crypto1_bs_convert_states(bitslice_t bitsliced_states[], state_t reg // swap endianness values[slice_idx].value = rev_state_t(values[slice_idx].value); // roll off unused bits - values[slice_idx].value >>= ((sizeof(state_t)*8)-STATE_SIZE); + //values[slice_idx].value >>= ((sizeof(state_t)*8)-STATE_SIZE); // - 48 + values[slice_idx].value >>= 16; } memcpy(regular_states, values, sizeof(values)); } -- 2.39.5 From 1f1d974f02e20b4ce7996fa2159950fb2ea06750 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 23 Jul 2016 18:33:30 +0200 Subject: [PATCH 09/16] CHG: added a comment --- client/util.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/client/util.c b/client/util.c index 99a26a40..4bbc992e 100644 --- a/client/util.c +++ b/client/util.c @@ -186,19 +186,16 @@ char *sprint_hex_ascii(const uint8_t *data, const size_t len) { return buf; } -void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) -{ +void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { dest[len] = (uint8_t) n; n >>= 8; } } -uint64_t bytes_to_num(uint8_t* src, size_t len) -{ +uint64_t bytes_to_num(uint8_t* src, size_t len) { uint64_t num = 0; - while (len--) - { + while (len--) { num = (num << 8) | (*src); src++; } @@ -212,6 +209,7 @@ void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { n >>= 1; } } + //least significant bit first void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) { for(int i = 0 ; i < len ; ++i) { @@ -220,7 +218,6 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) { } } - // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp // to // hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii @@ -549,6 +546,7 @@ void rol(uint8_t *data, const size_t len){ } // Swap bit order on a uint32_t value. Can be limited by nrbits just use say 8bits reversal +// And clears the rest of the bits. uint32_t SwapBits(uint32_t value, int nrbits) { uint32_t newvalue = 0; for(int i = 0; i < nrbits; i++) { -- 2.39.5 From b82c2f85e457f361b119d21a31f3263ac3489cc8 Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 28 Jul 2016 18:38:20 +0200 Subject: [PATCH 10/16] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d6776b0..7f3b327d 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,9 @@ Use only container tag [1.6.1] ##Buying a proxmark3 The Proxmark 3 device is available for purchase (assembled and tested) from the following locations: - * http://www.elechouse.com (new and revised hardware package 2015) + * http://proxmark3.tictail.com/ (For buyers in EU, most likely in Sweden) + + * http://www.elechouse.com/ (new and revised hardware package 2015, located in China) I recommend you to buy this version. -- 2.39.5 From 91d4cda48bfd0e6d17e4d02f852a3c80cc8470cc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 20:42:46 +0200 Subject: [PATCH 11/16] CHG: removed the linking to radixsort.c --- client/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/Makefile b/client/Makefile index 7b9a65fd..3f1d13ed 100644 --- a/client/Makefile +++ b/client/Makefile @@ -78,7 +78,8 @@ CORESRCS = uart.c \ sleep.c -CMDSRCS = nonce2key/crapto1.c \ +CMDSRCS = mifarehost.c \ + nonce2key/crapto1.c \ nonce2key/crypto1.c \ nonce2key/nonce2key.c \ nonce2key/crypto1_bs.c \ @@ -88,7 +89,6 @@ CMDSRCS = nonce2key/crapto1.c \ loclass/ikeys.c \ loclass/elite_crack.c \ loclass/fileutils.c \ - mifarehost.c \ parity.c \ crc.c \ crc16.c \ @@ -148,8 +148,9 @@ CMDSRCS = nonce2key/crapto1.c \ reveng/getopt.c \ tea.c \ prng.c \ - radixsort.c \ bucketsort.c +# radixsort.c \ + ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c ZLIB_FLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED -- 2.39.5 From 83dad64b9120695adeaaeb3e8ccffa0285740af1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 21:16:02 +0200 Subject: [PATCH 12/16] ADD: some new usb commmands from EMV, and for LEGIC. --- client/lualibs/commands.lua | 13 +++++++++++++ include/usb_cmd.h | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index afdba7e7..b953562e 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -95,6 +95,7 @@ local _commands = { CMD_SNOOP_ISO_14443a = 0x0383, CMD_SIMULATE_TAG_ISO_14443a = 0x0384, CMD_READER_ISO_14443a = 0x0385, + CMD_RAW_WRITER_LEGIC_RF = 0x0386, CMD_SIMULATE_TAG_LEGIC_RF = 0x0387, CMD_READER_LEGIC_RF = 0x0388, CMD_WRITER_LEGIC_RF = 0x0389, @@ -169,6 +170,18 @@ local _commands = { CMD_MIFARE_DESFIRE = 0x072e, CMD_HF_SNIFFER = 0x0800, + + --// For EMV Commands + CMD_EMV_READ_RECORD = 0x0700, + CMD_EMV_TRANSACTION = 0x0701, + CMD_EMV_CLONE = 0x0702, + CMD_EMV_SIM = 0x0703, + CMD_EMV_TEST = 0x0704, + CMD_EMV_FUZZ_RATS = 0x0705, + CMD_EMV_GET_RANDOM_NUM = 0x0706, + CMD_EMV_LOAD_VALUE = 0x0707, + CMD_EMV_DUMP_CARD = 0x0708, + CMD_UNKNOWN = 0xFFFF, } diff --git a/include/usb_cmd.h b/include/usb_cmd.h index ae9d15c2..e4ec0493 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -138,6 +138,7 @@ typedef struct{ #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 +#define CMD_RAW_WRITER_LEGIC_RF 0x0386 #define CMD_SIMULATE_TAG_LEGIC_RF 0x0387 #define CMD_READER_LEGIC_RF 0x0388 #define CMD_WRITER_LEGIC_RF 0x0389 @@ -213,6 +214,18 @@ typedef struct{ #define CMD_HF_SNIFFER 0x0800 + +// For EMV Commands +#define CMD_EMV_READ_RECORD 0x0700 +#define CMD_EMV_TRANSACTION 0x0701 +#define CMD_EMV_CLONE 0x0702 +#define CMD_EMV_SIM 0x0703 +#define CMD_EMV_TEST 0x0704 +#define CMD_EMV_FUZZ_RATS 0x0705 +#define CMD_EMV_GET_RANDOM_NUM 0x0706 +#define CMD_EMV_LOAD_VALUE 0x0707 +#define CMD_EMV_DUMP_CARD 0x0708 + #define CMD_UNKNOWN 0xFFFF -- 2.39.5 From 3e134b4c20a5528b8264cd87d3fdebd0b2df6fd9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 21:41:44 +0200 Subject: [PATCH 13/16] CHG: merged the forum user @jason 's fixes to LEGIC. *UNTESTED* CHG: changed the CRC implementations. --- armsrc/appmain.c | 4 + armsrc/legicrf.c | 934 +++++++++++++++++++++++++++++++++++++++++++- armsrc/legicrf.h | 4 + armsrc/util.h | 13 + client/cmdhflegic.c | 303 ++++++++++---- client/cmdhflegic.h | 13 + client/util.c | 22 +- client/util.h | 13 +- common/bucketsort.c | 2 +- common/bucketsort.h | 2 + common/crc.c | 134 +++++-- common/crc.h | 36 +- common/crc16.c | 33 +- common/crc16.h | 8 +- common/crc32.h | 4 +- common/crc64.c | 4 +- 16 files changed, 1367 insertions(+), 162 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 59011df2..5896eae7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1058,6 +1058,10 @@ void UsbPacketReceived(uint8_t *packet, int len) LegicRfWriter(c->arg[1], c->arg[0]); break; + case CMD_RAW_WRITER_LEGIC_RF: + LegicRfRawWriter(c->arg[0], c->arg[1]); + break; + case CMD_READER_LEGIC_RF: LegicRfReader(c->arg[0], c->arg[1]); break; diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 5ad1fdf1..a725c0bc 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -325,12 +325,11 @@ static void LegicCommonInit(void) { crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); } +/* Switch off carrier, make sure tag is reset */ static void switch_off_tag_rwd(void) { - /* Switch off carrier, make sure tag is reset */ AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; SpinDelay(10); - WDT_HIT(); } /* calculate crc for a legic command */ @@ -372,11 +371,12 @@ int legic_read_byte(int byte_index, int cmd_sz) { * * wait until the tag sends back an ACK ('1' bit unencrypted) * * forward the prng based on the timing */ +//int legic_write_byte(int byte, int addr, int addr_sz, int PrngCorrection) { int legic_write_byte(int byte, int addr, int addr_sz) { - //do not write UID, CRC, DCF - if(addr <= 0x06) + //do not write UID, CRC + if(addr <= 0x04) { return 0; - + } //== send write command ============================== crc_clear(&legic_crc); crc_update(&legic_crc, 0, 1); /* CMD_WRITE */ @@ -390,10 +390,13 @@ int legic_write_byte(int byte, int addr, int addr_sz) { |(0x00 <<0)); //CMD = W uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd - legic_prng_forward(2); /* we wait anyways */ + legic_prng_forward(4); /* we wait anyways */ while(timer->TC_CV < 387) ; /* ~ 258us */ frame_send_rwd(cmd, cmd_sz); + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; + //== wait for ack ==================================== int t, old_level=0, edges=0; int next_bit_at =0; @@ -413,7 +416,7 @@ int legic_write_byte(int byte, int addr, int addr_sz) { int c = t/TAG_TIME_BIT; timer->TC_CCR = AT91C_TC_SWTRG; while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ - legic_prng_forward(c); + legic_prng_forward(c-1); return 0; } } @@ -423,6 +426,11 @@ int legic_write_byte(int byte, int addr, int addr_sz) { } int LegicRfReader(int offset, int bytes) { + + // ice_legic_setup(); + // ice_legic_select_card(); + // return 0; + int byte_index=0, cmd_sz=0, card_sz=0; LegicCommonInit(); @@ -434,13 +442,18 @@ int LegicRfReader(int offset, int bytes) { uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); switch_off_tag_rwd(); //we lose to mutch time with dprintf switch(tag_type) { + case 0x0d: + DbpString("MIM22 card found, reading card ..."); + cmd_sz = 6; + card_sz = 22; + break; case 0x1d: - DbpString("MIM 256 card found, reading card ..."); + DbpString("MIM256 card found, reading card ..."); cmd_sz = 9; card_sz = 256; break; case 0x3d: - DbpString("MIM 1024 card found, reading card ..."); + DbpString("MIM1024 card found, reading card ..."); cmd_sz = 11; card_sz = 1024; break; @@ -469,7 +482,7 @@ int LegicRfReader(int offset, int bytes) { BigBuf[byte_index] = r; WDT_HIT(); byte_index++; - if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); + if (byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); } LED_B_OFF(); LED_C_OFF(); @@ -479,6 +492,47 @@ int LegicRfReader(int offset, int bytes) { return 0; } +/*int _LegicRfWriter(int bytes, int offset, int addr_sz, uint8_t *BigBuf, int RoundBruteforceValue) { + int byte_index=0; + + LED_B_ON(); + perform_setup_phase_rwd(SESSION_IV); + //legic_prng_forward(2); + while(byte_index < bytes) { + int r; + + //check if the DCF should be changed + if ( (offset == 0x05) && (bytes == 0x02) ) { + //write DCF in reverse order (addr 0x06 before 0x05) + r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue); + //legic_prng_forward(1); + if(r == 0) { + byte_index++; + r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue); + } + //legic_prng_forward(1); + } + else { + r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz, RoundBruteforceValue); + } + if((r != 0) || BUTTON_PRESS()) { + Dbprintf("operation aborted @ 0x%03.3x", byte_index); + switch_off_tag_rwd(); + LED_B_OFF(); + LED_C_OFF(); + return -1; + } + + WDT_HIT(); + byte_index++; + if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); + } + LED_B_OFF(); + LED_C_OFF(); + DbpString("write successful"); + return 0; +}*/ + void LegicRfWriter(int bytes, int offset) { int byte_index=0, addr_sz=0; uint8_t *BigBuf = BigBuf_get_addr(); @@ -489,32 +543,56 @@ void LegicRfWriter(int bytes, int offset) { uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); switch_off_tag_rwd(); switch(tag_type) { + case 0x0d: + if(offset+bytes > 22) { + Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset+bytes); + return; + } + addr_sz = 5; + Dbprintf("MIM22 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); + break; case 0x1d: if(offset+bytes > 0x100) { - Dbprintf("Error: can not write to 0x%03.3x on MIM 256", offset+bytes); + Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes); return; } addr_sz = 8; - Dbprintf("MIM 256 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); + Dbprintf("MIM256 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); break; case 0x3d: if(offset+bytes > 0x400) { - Dbprintf("Error: can not write to 0x%03.3x on MIM 1024", offset+bytes); + Dbprintf("Error: can not write to 0x%03.3x on MIM1024", offset+bytes); return; } addr_sz = 10; - Dbprintf("MIM 1024 card found, writing 0x%03.3x - 0x%03.3x ...", offset, offset+bytes); + Dbprintf("MIM1024 card found, writing 0x%03.3x - 0x%03.3x ...", offset, offset+bytes); break; default: Dbprintf("No or unknown card found, aborting"); return; } +#if 1 LED_B_ON(); perform_setup_phase_rwd(SESSION_IV); - legic_prng_forward(2); + while(byte_index < bytes) { - int r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz); + int r; + + //check if the DCF should be changed + if ( ((byte_index+offset) == 0x05) && (bytes >= 0x02) ) { + //write DCF in reverse order (addr 0x06 before 0x05) + r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz); + + // write second byte on success... + if(r == 0) { + byte_index++; + r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz); + } + } + else { + r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz); + } if((r != 0) || BUTTON_PRESS()) { Dbprintf("operation aborted @ 0x%03.3x", byte_index); switch_off_tag_rwd(); @@ -522,6 +600,76 @@ void LegicRfWriter(int bytes, int offset) { LED_C_OFF(); return; } + + WDT_HIT(); + byte_index++; + if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); + } + LED_B_OFF(); + LED_C_OFF(); + DbpString("write successful"); +#else + for(byte_index = -2; byte_index < 200; byte_index++) + { + Dbprintf("+ Try RndValue %d...", byte_index); + if(_LegicRfWriter(bytes, offset, addr_sz, BigBuf, byte_index) == 0) + break; + } +#endif + +} + +void LegicRfRawWriter(int offset, int byte) { + int byte_index=0, addr_sz=0; + + LegicCommonInit(); + + DbpString("setting up legic card"); + uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); + switch_off_tag_rwd(); + switch(tag_type) { + case 0x0d: + if(offset > 22) { + Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset); + return; + } + addr_sz = 5; + Dbprintf("MIM22 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte); + break; + case 0x1d: + if(offset > 0x100) { + Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset); + return; + } + addr_sz = 8; + Dbprintf("MIM256 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte); + break; + case 0x3d: + if(offset > 0x400) { + Dbprintf("Error: can not write to 0x%03.3x on MIM1024", offset); + return; + } + addr_sz = 10; + Dbprintf("MIM1024 card found, writing at addr 0x%03.3x - value 0x%03.3x ...", offset, byte); + break; + default: + Dbprintf("No or unknown card found, aborting"); + return; + } + Dbprintf("integer value: %d offset: %d addr_sz: %d", byte, offset, addr_sz); + LED_B_ON(); + perform_setup_phase_rwd(SESSION_IV); + //legic_prng_forward(2); + + int r = legic_write_byte(byte, offset, addr_sz); + + if((r != 0) || BUTTON_PRESS()) { + Dbprintf("operation aborted @ 0x%03.3x (%1d)", byte_index, r); + switch_off_tag_rwd(); + LED_B_OFF(); + LED_C_OFF(); + return; + WDT_HIT(); byte_index++; if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); @@ -756,3 +904,757 @@ void LegicRfSimulate(int phase, int frame, int reqresp) LED_C_OFF(); } + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Code up a string of octets at layer 2 (including CRC, we don't generate +// that here) so that they can be transmitted to the reader. Doesn't transmit +// them yet, just leaves them ready to send in ToSend[]. +//----------------------------------------------------------------------------- +// static void CodeLegicAsTag(const uint8_t *cmd, int len) +// { + // int i; + + // ToSendReset(); + + // // Transmit a burst of ones, as the initial thing that lets the + // // reader get phase sync. This (TR1) must be > 80/fs, per spec, + // // but tag that I've tried (a Paypass) exceeds that by a fair bit, + // // so I will too. + // for(i = 0; i < 20; i++) { + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // } + + // // Send SOF. + // for(i = 0; i < 10; i++) { + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // } + // for(i = 0; i < 2; i++) { + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // } + + // for(i = 0; i < len; i++) { + // int j; + // uint8_t b = cmd[i]; + + // // Start bit + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + + // // Data bits + // for(j = 0; j < 8; j++) { + // if(b & 1) { + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // } else { + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // } + // b >>= 1; + // } + + // // Stop bit + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // } + + // // Send EOF. + // for(i = 0; i < 10; i++) { + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // ToSendStuffBit(0); + // } + // for(i = 0; i < 2; i++) { + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // ToSendStuffBit(1); + // } + + // // Convert from last byte pos to length + // ToSendMax++; +// } + +//----------------------------------------------------------------------------- +// The software UART that receives commands from the reader, and its state +// variables. +//----------------------------------------------------------------------------- +static struct { + enum { + STATE_UNSYNCD, + STATE_GOT_FALLING_EDGE_OF_SOF, + STATE_AWAITING_START_BIT, + STATE_RECEIVING_DATA + } state; + uint16_t shiftReg; + int bitCnt; + int byteCnt; + int byteCntMax; + int posCnt; + uint8_t *output; +} Uart; + +/* Receive & handle a bit coming from the reader. + * + * This function is called 4 times per bit (every 2 subcarrier cycles). + * Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us + * + * LED handling: + * LED A -> ON once we have received the SOF and are expecting the rest. + * LED A -> OFF once we have received EOF or are in error state or unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + */ +// static RAMFUNC int HandleLegicUartBit(uint8_t bit) +// { + // switch(Uart.state) { + // case STATE_UNSYNCD: + // if(!bit) { + // // we went low, so this could be the beginning of an SOF + // Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF; + // Uart.posCnt = 0; + // Uart.bitCnt = 0; + // } + // break; + + // case STATE_GOT_FALLING_EDGE_OF_SOF: + // Uart.posCnt++; + // if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit + // if(bit) { + // if(Uart.bitCnt > 9) { + // // we've seen enough consecutive + // // zeros that it's a valid SOF + // Uart.posCnt = 0; + // Uart.byteCnt = 0; + // Uart.state = STATE_AWAITING_START_BIT; + // LED_A_ON(); // Indicate we got a valid SOF + // } else { + // // didn't stay down long enough + // // before going high, error + // Uart.state = STATE_UNSYNCD; + // } + // } else { + // // do nothing, keep waiting + // } + // Uart.bitCnt++; + // } + // if(Uart.posCnt >= 4) Uart.posCnt = 0; + // if(Uart.bitCnt > 12) { + // // Give up if we see too many zeros without + // // a one, too. + // LED_A_OFF(); + // Uart.state = STATE_UNSYNCD; + // } + // break; + + // case STATE_AWAITING_START_BIT: + // Uart.posCnt++; + // if(bit) { + // if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs + // // stayed high for too long between + // // characters, error + // Uart.state = STATE_UNSYNCD; + // } + // } else { + // // falling edge, this starts the data byte + // Uart.posCnt = 0; + // Uart.bitCnt = 0; + // Uart.shiftReg = 0; + // Uart.state = STATE_RECEIVING_DATA; + // } + // break; + + // case STATE_RECEIVING_DATA: + // Uart.posCnt++; + // if(Uart.posCnt == 2) { + // // time to sample a bit + // Uart.shiftReg >>= 1; + // if(bit) { + // Uart.shiftReg |= 0x200; + // } + // Uart.bitCnt++; + // } + // if(Uart.posCnt >= 4) { + // Uart.posCnt = 0; + // } + // if(Uart.bitCnt == 10) { + // if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001)) + // { + // // this is a data byte, with correct + // // start and stop bits + // Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff; + // Uart.byteCnt++; + + // if(Uart.byteCnt >= Uart.byteCntMax) { + // // Buffer overflowed, give up + // LED_A_OFF(); + // Uart.state = STATE_UNSYNCD; + // } else { + // // so get the next byte now + // Uart.posCnt = 0; + // Uart.state = STATE_AWAITING_START_BIT; + // } + // } else if (Uart.shiftReg == 0x000) { + // // this is an EOF byte + // LED_A_OFF(); // Finished receiving + // Uart.state = STATE_UNSYNCD; + // if (Uart.byteCnt != 0) { + // return TRUE; + // } + // } else { + // // this is an error + // LED_A_OFF(); + // Uart.state = STATE_UNSYNCD; + // } + // } + // break; + + // default: + // LED_A_OFF(); + // Uart.state = STATE_UNSYNCD; + // break; + // } + + // return FALSE; +// } + + +static void UartReset() +{ + Uart.byteCntMax = MAX_FRAME_SIZE; + Uart.state = STATE_UNSYNCD; + Uart.byteCnt = 0; + Uart.bitCnt = 0; + Uart.posCnt = 0; + memset(Uart.output, 0x00, MAX_FRAME_SIZE); +} + +// static void UartInit(uint8_t *data) +// { + // Uart.output = data; + // UartReset(); +// } + +//============================================================================= +// An LEGIC reader. We take layer two commands, code them +// appropriately, and then send them to the tag. We then listen for the +// tag's response, which we leave in the buffer to be demodulated on the +// PC side. +//============================================================================= + +static struct { + enum { + DEMOD_UNSYNCD, + DEMOD_PHASE_REF_TRAINING, + DEMOD_AWAITING_FALLING_EDGE_OF_SOF, + DEMOD_GOT_FALLING_EDGE_OF_SOF, + DEMOD_AWAITING_START_BIT, + DEMOD_RECEIVING_DATA + } state; + int bitCount; + int posCount; + int thisBit; + uint16_t shiftReg; + uint8_t *output; + int len; + int sumI; + int sumQ; +} Demod; + +/* + * Handles reception of a bit from the tag + * + * This function is called 2 times per bit (every 4 subcarrier cycles). + * Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us + * + * LED handling: + * LED C -> ON once we have received the SOF and are expecting the rest. + * LED C -> OFF once we have received EOF or are unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + * + */ + + #ifndef SUBCARRIER_DETECT_THRESHOLD + # define SUBCARRIER_DETECT_THRESHOLD 8 + #endif + + // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) +#ifndef CHECK_FOR_SUBCARRIER +# define CHECK_FOR_SUBCARRIER() { v = MAX(ai, aq) + MIN(halfci, halfcq); } +#endif + +// The soft decision on the bit uses an estimate of just the +// quadrant of the reference angle, not the exact angle. +// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) +#define MAKE_SOFT_DECISION() { \ + if(Demod.sumI > 0) \ + v = ci; \ + else \ + v = -ci; \ + \ + if(Demod.sumQ > 0) \ + v += cq; \ + else \ + v -= cq; \ + \ + } + +static RAMFUNC int HandleLegicSamplesDemod(int ci, int cq) +{ + int v = 0; + int ai = ABS(ci); + int aq = ABS(cq); + int halfci = (ai >> 1); + int halfcq = (aq >> 1); + + switch(Demod.state) { + case DEMOD_UNSYNCD: + + CHECK_FOR_SUBCARRIER() + + if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected + Demod.state = DEMOD_PHASE_REF_TRAINING; + Demod.sumI = ci; + Demod.sumQ = cq; + Demod.posCount = 1; + } + break; + + case DEMOD_PHASE_REF_TRAINING: + if(Demod.posCount < 8) { + + CHECK_FOR_SUBCARRIER() + + if (v > SUBCARRIER_DETECT_THRESHOLD) { + // set the reference phase (will code a logic '1') by averaging over 32 1/fs. + // note: synchronization time > 80 1/fs + Demod.sumI += ci; + Demod.sumQ += cq; + ++Demod.posCount; + } else { + // subcarrier lost + Demod.state = DEMOD_UNSYNCD; + } + } else { + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; + } + break; + + case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: + + MAKE_SOFT_DECISION() + + //Dbprintf("ICE: %d %d %d %d %d", v, Demod.sumI, Demod.sumQ, ci, cq ); + // logic '0' detected + if (v <= 0) { + + Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; + + // start of SOF sequence + Demod.posCount = 0; + } else { + // maximum length of TR1 = 200 1/fs + if(Demod.posCount > 25*2) Demod.state = DEMOD_UNSYNCD; + } + ++Demod.posCount; + break; + + case DEMOD_GOT_FALLING_EDGE_OF_SOF: + ++Demod.posCount; + + MAKE_SOFT_DECISION() + + if(v > 0) { + // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges + if(Demod.posCount < 10*2) { + Demod.state = DEMOD_UNSYNCD; + } else { + LED_C_ON(); // Got SOF + Demod.state = DEMOD_AWAITING_START_BIT; + Demod.posCount = 0; + Demod.len = 0; + } + } else { + // low phase of SOF too long (> 12 etu) + if(Demod.posCount > 13*2) { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } + break; + + case DEMOD_AWAITING_START_BIT: + ++Demod.posCount; + + MAKE_SOFT_DECISION() + + if(v > 0) { + // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + if(Demod.posCount > 3*2) { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } else { + // start bit detected + Demod.bitCount = 0; + Demod.posCount = 1; // this was the first half + Demod.thisBit = v; + Demod.shiftReg = 0; + Demod.state = DEMOD_RECEIVING_DATA; + } + break; + + case DEMOD_RECEIVING_DATA: + + MAKE_SOFT_DECISION() + + if(Demod.posCount == 0) { + // first half of bit + Demod.thisBit = v; + Demod.posCount = 1; + } else { + // second half of bit + Demod.thisBit += v; + Demod.shiftReg >>= 1; + // logic '1' + if(Demod.thisBit > 0) + Demod.shiftReg |= 0x200; + + ++Demod.bitCount; + + if(Demod.bitCount == 10) { + + uint16_t s = Demod.shiftReg; + + if((s & 0x200) && !(s & 0x001)) { + // stop bit == '1', start bit == '0' + uint8_t b = (s >> 1); + Demod.output[Demod.len] = b; + ++Demod.len; + Demod.state = DEMOD_AWAITING_START_BIT; + } else { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + + if(s == 0x000) { + // This is EOF (start, stop and all data bits == '0' + return TRUE; + } + } + } + Demod.posCount = 0; + } + break; + + default: + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + break; + } + return FALSE; +} + +// Clear out the state of the "UART" that receives from the tag. +static void DemodReset() { + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; + Demod.posCount = 0; + Demod.sumI = 0; + Demod.sumQ = 0; + Demod.bitCount = 0; + Demod.thisBit = 0; + Demod.shiftReg = 0; + memset(Demod.output, 0x00, MAX_FRAME_SIZE); +} + +static void DemodInit(uint8_t *data) { + Demod.output = data; + DemodReset(); +} + +/* + * Demodulate the samples we received from the tag, also log to tracebuffer + * quiet: set to 'TRUE' to disable debug output + */ + #define LEGIC_DMA_BUFFER_SIZE 256 +static void GetSamplesForLegicDemod(int n, bool quiet) +{ + int max = 0; + bool gotFrame = FALSE; + int lastRxCounter = LEGIC_DMA_BUFFER_SIZE; + int ci, cq, samples = 0; + + BigBuf_free(); + + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); + + // The response (tag -> reader) that we're receiving. + // Set up the demodulator for tag -> reader responses. + DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); + + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(LEGIC_DMA_BUFFER_SIZE); + int8_t *upTo = dmaBuf; + + // Setup and start DMA. + if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, LEGIC_DMA_BUFFER_SIZE) ){ + if (MF_DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return; + } + + // Signal field is ON with the appropriate LED: + LED_D_ON(); + for(;;) { + int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; + if(behindBy > max) max = behindBy; + + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (LEGIC_DMA_BUFFER_SIZE-1)) > 2) { + ci = upTo[0]; + cq = upTo[1]; + upTo += 2; + if(upTo >= dmaBuf + LEGIC_DMA_BUFFER_SIZE) { + upTo = dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = LEGIC_DMA_BUFFER_SIZE; + } + lastRxCounter -= 2; + if(lastRxCounter <= 0) + lastRxCounter = LEGIC_DMA_BUFFER_SIZE; + + samples += 2; + + gotFrame = HandleLegicSamplesDemod(ci , cq ); + if ( gotFrame ) + break; + } + + if(samples > n || gotFrame) + break; + } + + FpgaDisableSscDma(); + + if (!quiet && Demod.len == 0) { + Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", + max, + samples, + gotFrame, + Demod.len, + Demod.sumI, + Demod.sumQ + ); + } + + //Tracing + if (Demod.len > 0) { + uint8_t parity[MAX_PARITY_SIZE] = {0x00}; + LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE); + } +} +//----------------------------------------------------------------------------- +// Transmit the command (to the tag) that was placed in ToSend[]. +//----------------------------------------------------------------------------- +static void TransmitForLegic(void) +{ + int c; + + FpgaSetupSsc(); + + while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) + AT91C_BASE_SSC->SSC_THR = 0xff; + + // Signal field is ON with the appropriate Red LED + LED_D_ON(); + + // Signal we are transmitting with the Green LED + LED_B_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + + for(c = 0; c < 10;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + c++; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + legic_prng_forward(1); // forward the lfsr + c++; + if(c >= ToSendMax) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + LED_B_OFF(); +} + + +//----------------------------------------------------------------------------- +// Code a layer 2 command (string of octets, including CRC) into ToSend[], +// so that it is ready to transmit to the tag using TransmitForLegic(). +//----------------------------------------------------------------------------- +static void CodeLegicBitsAsReader(const uint8_t *cmd, int bits) +{ + int i, j; + uint8_t b; + + ToSendReset(); + + // Send SOF + for(i = 0; i < 7; i++) { + ToSendStuffBit(1); + } + + for(i = 0; i < bits; i++) { + // Start bit + ToSendStuffBit(0); + + // Data bits + b = cmd[i]; + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + } + b >>= 1; + } + } + + // Convert from last character reference to length + ++ToSendMax; +} + +/** + Convenience function to encode, transmit and trace Legic comms + **/ +static void CodeAndTransmitLegicAsReader(const uint8_t *cmd, int bits) +{ + CodeLegicBitsAsReader(cmd, bits); + TransmitForLegic(); + if (tracing) { + uint8_t parity[1] = {0x00}; + LogTrace(cmd, bits, 0, 0, parity, TRUE); + } +} + +int ice_legic_select_card() +{ + //int cmd_size=0, card_size=0; + uint8_t wakeup[] = { 0x7F}; + uint8_t getid[] = {0x19}; + + legic_prng_init(SESSION_IV); + + // first, wake up the tag, 7bits + CodeAndTransmitLegicAsReader(wakeup, 7); + + GetSamplesForLegicDemod(1000, TRUE); + + // frame_clean(¤t_frame); + //frame_receive_rwd(¤t_frame, 6, 1); + + legic_prng_forward(1); /* we wait anyways */ + + //while(timer->TC_CV < 387) ; /* ~ 258us */ + //frame_send_rwd(0x19, 6); + CodeAndTransmitLegicAsReader(getid, sizeof(getid)); + GetSamplesForLegicDemod(1000, TRUE); + + //if (Demod.len < 14) return 2; + Dbprintf("CARD TYPE: %02x LEN: %d", Demod.output[0], Demod.len); + + switch(Demod.output[0]) { + case 0x1d: + DbpString("MIM 256 card found"); + // cmd_size = 9; + // card_size = 256; + break; + case 0x3d: + DbpString("MIM 1024 card found"); + // cmd_size = 11; + // card_size = 1024; + break; + default: + return -1; + } + + // if(bytes == -1) + // bytes = card_size; + + // if(bytes + offset >= card_size) + // bytes = card_size - offset; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(FALSE); + return 1; +} + +// Set up LEGIC communication +void ice_legic_setup() { + + // standard things. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BigBuf_free(); BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(TRUE); + DemodReset(); + UartReset(); + + // Set up the synchronous serial port + FpgaSetupSsc(); + + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + SpinDelay(200); + // Start the timer + //StartCountSspClk(); + + // initalize CRC + crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); + + // initalize prng + legic_prng_init(0); +} \ No newline at end of file diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 57ab7e6d..69fb442f 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -14,5 +14,9 @@ extern void LegicRfSimulate(int phase, int frame, int reqresp); extern int LegicRfReader(int bytes, int offset); extern void LegicRfWriter(int bytes, int offset); +extern void LegicRfRawWriter(int offset, int bytes); + +int ice_legic_select_card(); +void ice_legic_setup(); #endif /* __LEGICRF_H */ diff --git a/armsrc/util.h b/armsrc/util.h index 0fb445d6..486f22e9 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -14,6 +14,10 @@ #include #include #include "common.h" +#include "string.h" +#include "apps.h" +#include "BigBuf.h" +#include "proxmark3.h" #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -27,9 +31,17 @@ #define BUTTON_DOUBLE_CLICK -2 #define BUTTON_ERROR -99 +#ifndef BSWAP_16 +# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8))) +#endif +#ifndef BITMASK +# define BITMASK(X) (1 << (X)) +#endif + void print_result(char *name, uint8_t *buf, size_t len); size_t nbytes(size_t nbits); uint32_t SwapBits(uint32_t value, int nrbits); +uint32_t reflect(uint32_t v, int b); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); void rol(uint8_t *data, const size_t len); @@ -52,6 +64,7 @@ uint32_t RAMFUNC GetCountUS(); //uint32_t RAMFUNC GetDeltaCountUS(); void StartCountSspClk(); +void ResetSspClk(void); uint32_t RAMFUNC GetCountSspClk(); #endif diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 0262f81c..d6aaaf3d 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -7,27 +7,21 @@ //----------------------------------------------------------------------------- // High frequency Legic commands //----------------------------------------------------------------------------- - -#include -#include -#include "proxmark3.h" -#include "data.h" -#include "ui.h" -#include "cmdparser.h" #include "cmdhflegic.h" -#include "cmdmain.h" -#include "util.h" -#include "crc.h" + static int CmdHelp(const char *Cmd); int usage_legic_calccrc8(void){ - PrintAndLog("Calculates the legic crc8 on the input hexbytes."); + PrintAndLog("Calculates the legic crc8/crc16 on the input hexbytes."); PrintAndLog("There must be an even number of hexsymbols as input."); - PrintAndLog("Usage: hf legic crc8 "); + PrintAndLog("Usage: hf legic crc8 [h] b u "); PrintAndLog("Options :"); - PrintAndLog(" : hex bytes in a string"); + PrintAndLog(" b : hex bytes"); + PrintAndLog(" u : MCC hexbyte"); PrintAndLog(""); - PrintAndLog("Sample : hf legic crc8 deadbeef1122"); + PrintAndLog("Samples :"); + PrintAndLog(" hf legic crc8 b deadbeef1122"); + PrintAndLog(" hf legic crc8 b deadbeef1122 u 9A"); return 0; } @@ -64,8 +58,10 @@ int CmdLegicDecode(const char *Cmd) { int crc = 0; int wrp = 0; int wrc = 0; - uint8_t data_buf[1024]; // receiver buffer, should be 1024.. - char token_type[4]; + uint8_t data_buf[1052]; // receiver buffer, should be 1024.. + char token_type[5]; + int dcf; + int bIsSegmented = 0; // download EML memory, where the "legic read" command puts the data. GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0); @@ -89,71 +85,120 @@ int CmdLegicDecode(const char *Cmd) { (calc_crc == crc) ? "OK":"Fail" ); + + token_type[0] = 0; + dcf = ((int)data_buf[6] << 8) | (int)data_buf[5]; + + // New unwritten media? + if(dcf == 0xFFFF) { + + PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)", + dcf, + data_buf[5], + data_buf[6] + ); + + } else if(dcf > 60000) { // Master token? + + int fl = 0; + + if(data_buf[6] == 0xec) { + strncpy(token_type, "XAM", sizeof(token_type)); + fl = 1; + stamp_len = 0x0c - (data_buf[5] >> 4); + } else { switch (data_buf[5] & 0x7f) { case 0x00 ... 0x2f: strncpy(token_type, "IAM",sizeof(token_type)); + fl = (0x2f - (data_buf[5] & 0x7f)) + 1; break; case 0x30 ... 0x6f: strncpy(token_type, "SAM",sizeof(token_type)); + fl = (0x6f - (data_buf[5] & 0x7f)) + 1; break; case 0x70 ... 0x7f: strncpy(token_type, "GAM",sizeof(token_type)); - break; - default: - strncpy(token_type, "???",sizeof(token_type)); + fl = (0x7f - (data_buf[5] & 0x7f)) + 1; break; } stamp_len = 0xfc - data_buf[6]; + } - PrintAndLog("DCF: %02x %02x, Token Type=%s (OLE=%01u), Stamp len=%02u", + PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u", + dcf, data_buf[5], data_buf[6], token_type, (data_buf[5]&0x80)>>7, - stamp_len + stamp_len, + fl ); - PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", + } else { // Is IM(-S) type of card... + + if(data_buf[7] == 0x9F && data_buf[8] == 0xFF) { + bIsSegmented = 1; + strncpy(token_type, "IM-S", sizeof(token_type)); + } else { + strncpy(token_type, "IM", sizeof(token_type)); + } + + PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u)", + dcf, + data_buf[5], + data_buf[6], + token_type, + (data_buf[5]&0x80)>>7 + ); + } + + // Makes no sence to show this on blank media... + if(dcf != 0xFFFF) { + + if(bIsSegmented) { + PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, SSC=%02x", data_buf[7]&0x0f, (data_buf[7]&0x70)>>4, (data_buf[7]&0x80)>>7, - data_buf[7], data_buf[8] ); + } + // Header area is only available on IM-S cards, on master tokens this data is the master token data itself + if(bIsSegmented || dcf > 60000) { + if(dcf > 60000) { + PrintAndLog("Master token data"); + PrintAndLog("%s", sprint_hex(data_buf+8, 14)); + } else { PrintAndLog("Remaining Header Area"); PrintAndLog("%s", sprint_hex(data_buf+9, 13)); + } + } + } + uint8_t segCrcBytes[8] = {0x00}; uint32_t segCalcCRC = 0; uint32_t segCRC = 0; - // see if user area is xored or just zeros. - int numOfZeros = 0; - for (int index=22; index < 256; ++index){ - if ( data_buf[index] == 0x00 ) - ++numOfZeros; - } - // if possible zeros is less then 60%, lets assume data is xored - // 256 - 22 (header) = 234 - // 1024 - 22 (header) = 1002 - int isXored = (numOfZeros*100/stamp_len) < 50; - PrintAndLog("is data xored? %d ( %d %)", isXored, (numOfZeros*100/stamp_len)); - print_hex_break( data_buf, 33, 16); - - return 0; + // Data card? + if(dcf <= 60000) { PrintAndLog("\nADF: User Area"); PrintAndLog("------------------------------------------------------"); + + if(bIsSegmented) { + + // Data start point on segmented cards i = 22; - // 64 potential segements - // how to detect there is no segments?!? - for ( segmentNum=0; segmentNum<64; segmentNum++ ) { + + // decode segments + for (segmentNum=1; segmentNum < 128; segmentNum++ ) + { segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; - wrp = (data_buf[i+2]^crc); wrc = ((data_buf[i+3]^crc)&0x70)>>4; @@ -198,11 +243,10 @@ int CmdLegicDecode(const char *Cmd) { PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); PrintAndLog("\nrow | data"); PrintAndLog("-----+------------------------------------------------"); - // de-xor? if not zero, assume it needs xoring. - if ( isXored) { - for ( k=i; k < wrc; ++k) + + for ( k=i; k < (i+wrc); ++k) data_buf[k] ^= crc; - } + print_hex_break( data_buf+i, wrc, 16); i += wrc; @@ -213,16 +257,14 @@ int CmdLegicDecode(const char *Cmd) { PrintAndLog("\nrow | data"); PrintAndLog("-----+------------------------------------------------"); - if (isXored) { - for (k=i; k < wrp_len; ++k) + for (k=i; k < (i+wrp_len); ++k) data_buf[k] ^= crc; - } print_hex_break( data_buf+i, wrp_len, 16); i += wrp_len; - // does this one work? + // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...) if( wrp_len == 8 ) PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4]^crc, data_buf[i-3]^crc, data_buf[i-2]^crc); } @@ -230,10 +272,9 @@ int CmdLegicDecode(const char *Cmd) { PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); PrintAndLog("\nrow | data"); PrintAndLog("-----+------------------------------------------------"); - if ( isXored ) { - for ( k=i; k < remain_seg_payload_len; ++k) + + for ( k=i; k < (i+remain_seg_payload_len); ++k) data_buf[k] ^= crc; - } print_hex_break( data_buf+i, remain_seg_payload_len, 16); @@ -245,6 +286,56 @@ int CmdLegicDecode(const char *Cmd) { if (segment_flag & 0x8) return 0; } // end for loop + + } else { + + // Data start point on unsegmented cards + i = 8; + + wrp = data_buf[7] & 0x0F; + wrc = (data_buf[7] & 0x07) >> 4; + + bool hasWRC = (wrc > 0); + bool hasWRP = (wrp > wrc); + int wrp_len = (wrp - wrc); + int remain_seg_payload_len = (1024 - 22 - wrp); // Any chance to get physical card size here!? + + PrintAndLog("Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u", + wrp, + wrc, + (data_buf[7] & 0x80) >> 7 + ); + + if ( hasWRC ) { + PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc); + PrintAndLog("\nrow | data"); + PrintAndLog("-----+------------------------------------------------"); + print_hex_break( data_buf+i, wrc, 16); + i += wrc; + } + + if ( hasWRP ) { + PrintAndLog("Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len); + PrintAndLog("\nrow | data"); + PrintAndLog("-----+------------------------------------------------"); + print_hex_break( data_buf+i, wrp_len, 16); + i += wrp_len; + + // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...) + if( wrp_len == 8 ) + PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4], data_buf[i-3], data_buf[i-2]); + } + + PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len); + PrintAndLog("\nrow | data"); + PrintAndLog("-----+------------------------------------------------"); + print_hex_break( data_buf+i, remain_seg_payload_len, 16); + i += remain_seg_payload_len; + + PrintAndLog("-----+------------------------------------------------\n"); + } + } + return 0; } @@ -417,8 +508,37 @@ int CmdLegicRfWrite(const char *Cmd) { return 0; } +//TODO: write a help text (iceman) +int CmdLegicRfRawWrite(const char *Cmd) { + char answer; + UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {0,0,0} }; + int res = sscanf(Cmd, " 0x%"llx" 0x%"llx, &c.arg[0], &c.arg[1]); + if(res != 2) { + PrintAndLog("Please specify the offset and value as two hex strings"); + return -1; + } + + if (c.arg[0] == 0x05 || c.arg[0] == 0x06) { + PrintAndLog("############# DANGER !! #############"); + PrintAndLog("# changing the DCF is irreversible #"); + PrintAndLog("#####################################"); + PrintAndLog("do youe really want to continue? y(es) n(o)"); + scanf(" %c", &answer); + if (answer == 'y' || answer == 'Y') { + SendCommand(&c); + return 0; + } + return -1; + } + + clearCommandBuffer(); + SendCommand(&c); + return 0; +} + +//TODO: write a help text (iceman) int CmdLegicRfFill(const char *Cmd) { - UsbCommand cmd = {CMD_WRITER_LEGIC_RF}; + UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} }; int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); if(res != 3) { PrintAndLog("Please specify the offset, length and value as two hex strings"); @@ -427,14 +547,14 @@ int CmdLegicRfFill(const char *Cmd) { int i; UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}}; - for(i = 0; i < 48; i++) { - c.d.asBytes[i] = cmd.arg[2]; - } - + memcpy(c.d.asBytes, cmd.arg[2], 48); + for(i = 0; i < 22; i++) { c.arg[0] = i*48; + + clearCommandBuffer(); SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); + WaitForResponse(CMD_ACK, NULL); } clearCommandBuffer(); SendCommand(&cmd); @@ -443,20 +563,64 @@ int CmdLegicRfFill(const char *Cmd) { int CmdLegicCalcCrc8(const char *Cmd){ - int len = strlen(Cmd); - if ( len & 1 ) return usage_legic_calccrc8(); + uint8_t *data; + uint8_t cmdp = 0, uidcrc = 0, type=0; + bool errors = false; + int len = 0; - // add 1 for null terminator. - uint8_t *data = malloc(len+1); - if ( data == NULL ) return 1; - - if (param_gethex(Cmd, 0, data, len )) { - free(data); - return usage_legic_calccrc8(); + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'b': + case 'B': + data = malloc(len); + if ( data == NULL ) { + PrintAndLog("Can't allocate memory. exiting"); + errors = true; + break; + } + param_gethex_ex(Cmd, cmdp+1, data, &len); + // if odd symbols, (hexbyte must be two symbols) + if ( len & 1 ) errors = true; + + len >>= 1; + cmdp += 2; + break; + case 'u': + case 'U': + uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16); + cmdp += 2; + break; + case 'c': + case 'C': + type = param_get8ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'h': + case 'H': + errors = true; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if (errors) break; + } + //Validations + if (errors){ + if (data != NULL) free(data); + return usage_legic_calccrc8(); + } + + switch (type){ + case 16: + PrintAndLog("LEGIC CRC16: %X", CRC16Legic(data, len, uidcrc)); + break; + default: + PrintAndLog("LEGIC CRC8: %X", CRC8Legic(data, len) ); + break; } - uint32_t checksum = CRC8Legic(data, len/2); - PrintAndLog("Bytes: %s || CRC8: %X", sprint_hex(data, len/2), checksum ); free(data); return 0; } @@ -469,6 +633,7 @@ static command_t CommandTable[] = { {"load", CmdLegicLoad, 0, " -- Restore samples"}, {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"}, {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, + {"writeRaw",CmdLegicRfRawWrite, 0, "
-- Write direct to address"}, {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"}, {NULL, NULL, 0, NULL} diff --git a/client/cmdhflegic.h b/client/cmdhflegic.h index 31082155..a22de93d 100644 --- a/client/cmdhflegic.h +++ b/client/cmdhflegic.h @@ -11,6 +11,16 @@ #ifndef CMDHFLEGIC_H__ #define CMDHFLEGIC_H__ +#include +#include +#include "proxmark3.h" +#include "data.h" +#include "ui.h" +#include "cmdparser.h" +#include "cmdmain.h" +#include "util.h" +#include "crc.h" + int CmdHFLegic(const char *Cmd); int CmdLegicRFRead(const char *Cmd); @@ -19,9 +29,12 @@ int CmdLegicLoad(const char *Cmd); int CmdLegicSave(const char *Cmd); int CmdLegicRfSim(const char *Cmd); int CmdLegicRfWrite(const char *Cmd); +int CmdLegicRfRawWrite(const char *Cmd); int CmdLegicRfFill(const char *Cmd); int CmdLegicCalcCrc8(const char *Cmd); int usage_legic_calccrc8(void); +int usage_legic_load(void); +int usage_legic_read(void); #endif diff --git a/client/util.c b/client/util.c index 4bbc992e..4129daaf 100644 --- a/client/util.c +++ b/client/util.c @@ -9,15 +9,13 @@ //----------------------------------------------------------------------------- #include "util.h" -#include "proxmark3.h" #define MAX_BIN_BREAK_LENGTH (3072+384+1) #ifndef _WIN32 #include #include -int ukbhit(void) -{ +int ukbhit(void) { int cnt = 0; int error; static struct termios Otty, Ntty; @@ -553,4 +551,20 @@ uint32_t SwapBits(uint32_t value, int nrbits) { newvalue ^= ((value >> i) & 1) << (nrbits - 1 - i); } return newvalue; -} \ No newline at end of file +} +/* + ref http://www.csm.ornl.gov/~dunigan/crc.html + Returns the value v with the bottom b [0,32] bits reflected. + Example: reflect(0x3e23L,3) == 0x3e26 +*/ +uint32_t reflect(uint32_t v, int b) { + uint32_t t = v; + for ( int i = 0; i < b; ++i) { + if (t & 1) + v |= BITMASK((b-1)-i); + else + v &= ~BITMASK((b-1)-i); + t>>=1; + } + return v; +} diff --git a/client/util.h b/client/util.h index e492fd49..655f823b 100644 --- a/client/util.h +++ b/client/util.h @@ -15,7 +15,11 @@ #include #include #include "data.h" //for FILE_PATH_SIZE +#include "proxmark3.h" +#ifndef BITMASK +# define BITMASK(X) (1 << (X)) +#endif #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) #endif @@ -26,10 +30,14 @@ # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef BSWAP_32 -#define BSWAP_32(x) \ +# define BSWAP_32(x) \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) #endif +#ifndef BSWAP_16 +# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8))) +#endif + #define TRUE 1 #define FALSE 0 #define EVEN 0 @@ -93,4 +101,5 @@ int32_t le24toh (uint8_t data[3]); uint32_t le32toh (uint8_t *data); uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits); void rol(uint8_t *data, const size_t len); -uint32_t SwapBits(uint32_t value, int nrbits); \ No newline at end of file +uint32_t SwapBits(uint32_t value, int nrbits); +uint32_t reflect(uint32_t v, int b); \ No newline at end of file diff --git a/common/bucketsort.c b/common/bucketsort.c index 2aca2632..162869e3 100644 --- a/common/bucketsort.c +++ b/common/bucketsort.c @@ -1,6 +1,6 @@ #include "bucketsort.h" -void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop, +extern void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop, uint32_t* const ostart, uint32_t* const ostop, bucket_info_t *bucket_info, bucket_array_t bucket) { diff --git a/common/bucketsort.h b/common/bucketsort.h index d5423aa5..be504508 100644 --- a/common/bucketsort.h +++ b/common/bucketsort.h @@ -1,7 +1,9 @@ #ifndef BUCKETSORT_H__ #define BUCKETSORT_H__ + #include #include + typedef struct bucket { uint32_t *head; uint32_t *bp; diff --git a/common/crc.c b/common/crc.c index 6c2f6994..451282bf 100644 --- a/common/crc.c +++ b/common/crc.c @@ -5,66 +5,136 @@ //----------------------------------------------------------------------------- // Generic CRC calculation code. //----------------------------------------------------------------------------- +// the Check value below in the comments is CRC of the string '123456789' +// #include "crc.h" -#include "util.h" -#include -#include -void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor) -{ +void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout) { + crc_init(crc, order, polynom, initial_value, final_xor); + crc->refin = refin; + crc->refout = refout; + crc_clear(crc); +} + +void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor) { crc->order = order; + crc->topbit = BITMASK( order-1 ); crc->polynom = polynom; crc->initial_value = initial_value; crc->final_xor = final_xor; crc->mask = (1L<refin = FALSE; + crc->refout = FALSE; crc_clear(crc); } -void crc_update(crc_t *crc, uint32_t data, int data_width) -{ - for( int i=0; i < data_width; i++) { - int oldstate = crc->state; - crc->state = crc->state >> 1; - if( (oldstate^data) & 1 ) { - crc->state ^= crc->polynom; - } - data >>= 1; +void crc_clear(crc_t *crc) { + crc->state = crc->initial_value & crc->mask; + if (crc->refin) + crc->state = reflect(crc->state, crc->order); +} + +void crc_update(crc_t *crc, uint32_t indata, int data_width){ + + //reflected + if (crc->refin) indata = reflect(indata, data_width); + + // Bring the next byte into the remainder. + crc->state ^= indata << (crc->order - data_width); + + for( uint8_t bit = data_width; bit > 0; --bit) { + // Try to divide the current data bit. + if (crc->state & crc->topbit) + crc->state = (crc->state << 1) ^ crc->polynom; + else + crc->state = (crc->state << 1); } } -void crc_clear(crc_t *crc) -{ - crc->state = crc->initial_value & crc->mask; +uint32_t crc_finish(crc_t *crc) { + uint32_t val = crc->state; + if (crc->refout) val = reflect(val, crc->order); + return ( val ^ crc->final_xor ) & crc->mask; } -uint32_t crc_finish(crc_t *crc) -{ - return ( crc->state ^ crc->final_xor ) & crc->mask; +/* +static void print_crc(crc_t *crc) { + printf(" Order %d\n Poly %x\n Init %x\n Final %x\n Mask %x\n topbit %x\n RefIn %s\n RefOut %s\n State %x\n", + crc->order, + crc->polynom, + crc->initial_value, + crc->final_xor, + crc->mask, + crc->topbit, + (crc->refin) ? "TRUE":"FALSE", + (crc->refout) ? "TRUE":"FALSE", + crc->state + ); } +*/ -//credits to iceman +// width=8 poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xA1 name="CRC-8/MAXIM" uint32_t CRC8Maxim(uint8_t *buff, size_t size) { crc_t crc; - crc_init(&crc, 9, 0x8c, 0x00, 0x00); - crc_clear(&crc); + crc_init_ref(&crc, 8, 0x31, 0, 0, TRUE, TRUE); + for ( int i=0; i < size; ++i) + crc_update(&crc, buff[i], 8); + return crc_finish(&crc); +} + - for (size_t i=0; i < size; ++i) +// width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC" +// width=8 poly=0x63, reversed poly=0x8D init=0x55 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/LEGIC" +// the CRC needs to be reversed before returned. +uint32_t CRC8Legic(uint8_t *buff, size_t size) { + crc_t crc; + crc_init_ref(&crc, 8, 0x63, 0x55, 0, TRUE, TRUE); + for ( int i = 0; i < size; ++i) crc_update(&crc, buff[i], 8); + return reflect(crc_finish(&crc), 8); +} +// credits to marshmellow +// width=8 poly=0xA3, reversed poly=0x8B, init=0xB0 refin=true refout=true xorout=0x00 check=0x28 name="CRC-8/JA" +uint32_t CRC8ja(uint8_t *buff, size_t size) { + crc_t crc; + crc_init_ref(&crc, 8, 0xA3, 0x42, 0x00, TRUE, TRUE); + for ( int i=0; i < size; ++i) + crc_update(&crc, buff[i], 8); return crc_finish(&crc); + //return reflect(crc_finish(&crc), 8); } -//credits to iceman -uint32_t CRC8Legic(uint8_t *buff, size_t size) { +// This CRC-16 is used in Legic Advant systems. +// width=8 poly=0xB400, reversed poly=0x init=depends refin=true refout=true xorout=0x0000 check= name="CRC-16/LEGIC" +uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc) { - // Poly 0x63, reversed poly 0xC6, Init 0x55, Final 0x00 + #define CRC16_POLY_LEGIC 0xB400 + //uint8_t initial = reflect(uidcrc, 8); + uint16_t initial = uidcrc; + initial |= initial << 8; crc_t crc; - crc_init(&crc, 8, 0xC6, 0x55, 0); - crc_clear(&crc); - - for ( int i = 0; i < size; ++i) + crc_init_ref(&crc, 16, CRC16_POLY_LEGIC, initial, 0, TRUE, TRUE); + for ( int i=0; i < size; ++i) crc_update(&crc, buff[i], 8); - return SwapBits(crc_finish(&crc), 8); + return reflect(crc_finish(&crc), 16); } +//w=16 poly=0x3d65 init=0x0000 refin=true refout=true xorout=0xffff check=0xea82 name="CRC-16/DNP" +uint32_t CRC16_DNP(uint8_t *buff, size_t size) { + crc_t crc; + crc_init_ref(&crc, 16, 0x3d65, 0, 0xffff, TRUE, TRUE); + for ( int i=0; i < size; ++i) + crc_update(&crc, buff[i], 8); + + return BSWAP_16(crc_finish(&crc)); +} +//width=16 poly=0x1021 init=0x1d0f refin=false refout=false xorout=0x0000 check=0xe5cc name="CRC-16/AUG-CCITT" +uint32_t CRC16_CCITT(uint8_t *buff, size_t size) { + crc_t crc; + crc_init(&crc, 16, 0x1021, 0x1d0f, 0); + for ( int i=0; i < size; ++i) + crc_update(&crc, buff[i], 8); + return crc_finish(&crc); +} \ No newline at end of file diff --git a/common/crc.h b/common/crc.h index fc76dc48..48e0d1e6 100644 --- a/common/crc.h +++ b/common/crc.h @@ -9,8 +9,10 @@ #ifndef __CRC_H #define __CRC_H -#include +#include //uint32+ +#include //bool #include +#include "util.h" // reflect, bswap_16 typedef struct crc { uint32_t state; @@ -19,13 +21,25 @@ typedef struct crc { uint32_t initial_value; uint32_t final_xor; uint32_t mask; + int topbit; + bool refin; /* Parameter: Reflect input bytes? */ + bool refout; /* Parameter: Reflect output CRC? */ } crc_t; +/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 + * polynom is the CRC polynom. initial_value is the initial value of a clean state. + * final_xor is XORed onto the state before returning it from crc_result(). + * refin is the setting for reversing (bitwise) the bytes during crc + * refot is the setting for reversing (bitwise) the crc byte before returning it. + */ +extern void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout); + /* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 * polynom is the CRC polynom. initial_value is the initial value of a clean state. * final_xor is XORed onto the state before returning it from crc_result(). */ extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor); + /* Update the crc state. data is the data of length data_width bits (only the * data_width lower-most bits are used). */ @@ -40,9 +54,24 @@ extern uint32_t crc_finish(crc_t *crc); // Calculate CRC-8/Maxim checksum uint32_t CRC8Maxim(uint8_t *buff, size_t size); +// Calculate CRC-4/Legic checksum +uint32_t CRC4Legic(uint8_t *buff, size_t size); + // Calculate CRC-8/Legic checksum uint32_t CRC8Legic(uint8_t *buff, size_t size); +// Calculate CRC-16/Legic checksum +// the initial_value is based on the previous legic_Crc8 of the UID. +// ie: uidcrc = 0x78 then initial_value == 0x7878 +uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc); + +// Calculate CRC-8/ja checksum +uint32_t CRC8ja(uint8_t *buff, size_t size); + +// test crc 16. +uint32_t CRC16_DNP(uint8_t *buff, size_t size); + + /* Static initialization of a crc structure */ #define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ .state = ((_initial_value) & ((1L<<(_order))-1)), \ @@ -50,6 +79,9 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size); .polynom = (_polynom), \ .initial_value = (_initial_value), \ .final_xor = (_final_xor), \ - .mask = ((1L<<(_order))-1) } + .mask = ((1L<<(_order))-1) \ + .refin = FALSE, \ + .refout = FALSE \ + } #endif /* __CRC_H */ diff --git a/common/crc16.c b/common/crc16.c index 9d3f68c9..21310b79 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -9,11 +9,9 @@ #include "crc16.h" #define CRC16_POLY_CCITT 0x1021 #define CRC16_POLY 0x8408 -#define CRC16_POLY_LEGIC 0xB400 -unsigned short update_crc16( unsigned short crc, unsigned char c ) -{ - unsigned short i, v, tcrc = 0; +uint16_t update_crc16( uint16_t crc, unsigned char c ) { + uint16_t i, v, tcrc = 0; v = (crc ^ c) & 0xff; for (i = 0; i < 8; i++) { @@ -29,8 +27,8 @@ uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t if (length == 0) return (~remainder); - for (int byte = 0; byte < length; ++byte) { - remainder ^= (message[byte] << 8); + for (uint32_t i = 0; i < length; ++i) { + remainder ^= (message[i] << 8); for (uint8_t bit = 8; bit > 0; --bit) { if (remainder & 0x8000) { remainder = (remainder << 1) ^ polynomial; @@ -47,25 +45,6 @@ uint16_t crc16_ccitt(uint8_t const *message, int length) { } uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) { - return bit_reverse_uint16(crc16(message, length, 0x0000, CRC16_POLY_CCITT)); -} - -//ICEMAN: not working yet, -// This CRC-16 is used in Legic Advant systems. -uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital) { - return crc16(message, length, inital, CRC16_POLY_LEGIC); -} - -uint16_t bit_reverse_uint16 (uint16_t value) { - const uint16_t mask0 = 0x5555; - const uint16_t mask1 = 0x3333; - const uint16_t mask2 = 0x0F0F; - const uint16_t mask3 = 0x00FF; - - value = (((~mask0) & value) >> 1) | ((mask0 & value) << 1); - value = (((~mask1) & value) >> 2) | ((mask1 & value) << 2); - value = (((~mask2) & value) >> 4) | ((mask2 & value) << 4); - value = (((~mask3) & value) >> 8) | ((mask3 & value) << 8); - - return value; + uint16_t val = crc16(message, length, 0x0000, CRC16_POLY_CCITT); + return SwapBits(val, 16); } diff --git a/common/crc16.h b/common/crc16.h index d53c7766..3db2cd79 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -5,14 +5,14 @@ //----------------------------------------------------------------------------- // CRC16 //----------------------------------------------------------------------------- -#include - #ifndef __CRC16_H #define __CRC16_H + +#include +#include "util.h" + unsigned short update_crc16(unsigned short crc, unsigned char c); uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial); uint16_t crc16_ccitt(uint8_t const *message, int length); uint16_t crc16_ccitt_kermit(uint8_t const *message, int length); -uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital); -uint16_t bit_reverse_uint16 (uint16_t value); #endif diff --git a/common/crc32.h b/common/crc32.h index 0dd2a328..7df7c79d 100644 --- a/common/crc32.h +++ b/common/crc32.h @@ -9,7 +9,7 @@ #ifndef __CRC32_H #define __CRC32_H -void crc32 (const uint8_t *data, const size_t len, uint8_t *crc); -void crc32_append (uint8_t *data, const size_t len); +void crc32 (const uint8_t *data, const size_t len, uint8_t *crc); +void crc32_append (uint8_t *data, const size_t len); #endif diff --git a/common/crc64.c b/common/crc64.c index 709c64d6..adf62d97 100644 --- a/common/crc64.c +++ b/common/crc64.c @@ -74,9 +74,7 @@ const uint64_t crc64_table[] = { void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) { - for (size_t i = 0; i < len; i++) - { - //uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff; + for (size_t i = 0; i < len; i++) { uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff; *crc = crc64_table[tableIndex] ^ (*crc << 8); } -- 2.39.5 From ab3af4fe8510c66c8fba51b91fbf0f31a85220fe Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 21:45:00 +0200 Subject: [PATCH 14/16] CHG: forgot to add the reflect function --- armsrc/util.c | 55 ++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/armsrc/util.c b/armsrc/util.c index 120e7b44..1efc2b2b 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -8,11 +8,7 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#include "proxmark3.h" #include "util.h" -#include "string.h" -#include "apps.h" -#include "BigBuf.h" void print_result(char *name, uint8_t *buf, size_t len) { uint8_t *p = buf; @@ -48,6 +44,23 @@ uint32_t SwapBits(uint32_t value, int nrbits) { return newvalue; } +/* + ref http://www.csm.ornl.gov/~dunigan/crc.html + Returns the value v with the bottom b [0,32] bits reflected. + Example: reflect(0x3e23L,3) == 0x3e26 +*/ +uint32_t reflect(uint32_t v, int b) { + uint32_t t = v; + for ( int i = 0; i < b; ++i) { + if (t & 1) + v |= BITMASK((b-1)-i); + else + v &= ~BITMASK((b-1)-i); + t>>=1; + } + return v; +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { dest[len] = (uint8_t) n; @@ -80,13 +93,11 @@ void lsl (uint8_t *data, size_t len) { data[len - 1] <<= 1; } -int32_t le24toh (uint8_t data[3]) -{ +int32_t le24toh (uint8_t data[3]) { return (data[2] << 16) | (data[1] << 8) | data[0]; } -void LEDsoff() -{ +void LEDsoff() { LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); @@ -94,8 +105,7 @@ void LEDsoff() } // LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8] -void LED(int led, int ms) -{ +void LED(int led, int ms) { if (led & LED_RED) LED_C_ON(); if (led & LED_ORANGE) @@ -120,13 +130,11 @@ void LED(int led, int ms) LED_D_OFF(); } - // Determine if a button is double clicked, single clicked, // not clicked, or held down (for ms || 1sec) // In general, don't use this function unless you expect a // double click, otherwise it will waste 500ms -- use BUTTON_HELD instead -int BUTTON_CLICKED(int ms) -{ +int BUTTON_CLICKED(int ms) { // Up to 500ms in between clicks to mean a double click int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -188,8 +196,7 @@ int BUTTON_CLICKED(int ms) } // Determine if a button is held down -int BUTTON_HELD(int ms) -{ +int BUTTON_HELD(int ms) { // If button is held for one second int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -228,8 +235,7 @@ int BUTTON_HELD(int ms) // attempt at high resolution microsecond timer // beware: timer counts in 21.3uS increments (1024/48Mhz) -void SpinDelayUs(int us) -{ +void SpinDelayUs(int us) { int ticks = (48*us) >> 10; // Borrow a PWM unit for my real-time clock @@ -250,8 +256,7 @@ void SpinDelayUs(int us) } } -void SpinDelay(int ms) -{ +void SpinDelay(int ms) { // convert to uS and call microsecond delay function SpinDelayUs(ms*1000); } @@ -261,8 +266,7 @@ void SpinDelay(int ms) * verifies the magic properties, then stores a formatted string, prefixed by * prefix in dst. */ -void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information) -{ +void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information) { struct version_information *v = (struct version_information*)version_information; dst[0] = 0; strncat(dst, prefix, len-1); @@ -301,8 +305,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers // ti = GetTickCount() - ti; // Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); -void StartTickCount() -{ +void StartTickCount() { // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency @@ -321,8 +324,7 @@ uint32_t RAMFUNC GetTickCount(){ // ------------------------------------------------------------------------- // microseconds timer // ------------------------------------------------------------------------- -void StartCountUS() -{ +void StartCountUS() { AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); // AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; @@ -363,8 +365,7 @@ uint32_t RAMFUNC GetCountUS(){ // ------------------------------------------------------------------------- // Timer for iso14443 commands. Uses ssp_clk from FPGA // ------------------------------------------------------------------------- -void StartCountSspClk() -{ +void StartCountSspClk() { AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none -- 2.39.5 From c827ffb098737ba43e280dd92e9a416d27ced6f6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 21:46:27 +0200 Subject: [PATCH 15/16] spacing.. --- client/nonce2key/crapto1.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/nonce2key/crapto1.h b/client/nonce2key/crapto1.h index 269ca8f3..1cbebe5d 100644 --- a/client/nonce2key/crapto1.h +++ b/client/nonce2key/crapto1.h @@ -19,8 +19,10 @@ */ #ifndef CRAPTO1_H__ #define CRAPTO1_H__ + #include #include "bucketsort.h" + #ifdef __cplusplus extern "C" { #endif -- 2.39.5 From 53b3c3e816c8a322a15d2b20652d6126baa6644a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 28 Jul 2016 21:47:52 +0200 Subject: [PATCH 16/16] ADD: Added some new analyse functions like CHKSUM ADD/SUBTRACKT with one's complement --- client/cmdanalyse.c | 200 +++++++++++++++++++++++++++++++++++++++++++- client/cmdanalyse.h | 9 +- 2 files changed, 204 insertions(+), 5 deletions(-) diff --git a/client/cmdanalyse.c b/client/cmdanalyse.c index ff6c0d4e..b5f9cb52 100644 --- a/client/cmdanalyse.c +++ b/client/cmdanalyse.c @@ -25,13 +25,105 @@ int usage_analyse_lcr(void) { PrintAndLog("expected output: Target (BA) requires final LRC XOR byte value: 5A"); return 0; } + +int usage_analyse_checksum(void) { + PrintAndLog("The bytes will be added with eachother and than limited with the applied mask"); + PrintAndLog("Finally compute ones' complement of the least significant bytes"); + PrintAndLog(""); + PrintAndLog("Usage: analyse chksum [h] b m "); + PrintAndLog("Options:"); + PrintAndLog(" h This help"); + PrintAndLog(" b bytes to calc missing XOR in a LCR"); + PrintAndLog(" m bit mask to limit the outpuyt"); + PrintAndLog(""); + PrintAndLog("Samples:"); + PrintAndLog(" analyse chksum b 137AF00A0A0D m FF"); + PrintAndLog("expected output: 0x61"); + return 0; +} + +int usage_analyse_crc(void){ + PrintAndLog("A stub method to test different crc implementations inside the PM3 sourcecode. Just because you figured out the poly, doesn't mean you get the desired output"); + PrintAndLog(""); + PrintAndLog("Usage: analyse crc [h] "); + PrintAndLog("Options:"); + PrintAndLog(" h This help"); + PrintAndLog(" bytes to calc crc"); + PrintAndLog(""); + PrintAndLog("Samples:"); + PrintAndLog(" analyse crc 137AF00A0A0D"); + return 0; +} + static uint8_t calculateLRC( uint8_t* bytes, uint8_t len) { uint8_t LRC = 0; for (uint8_t i = 0; i < len; i++) LRC ^= bytes[i]; return LRC; } - + +static uint8_t calcSumCrumbAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { + uint8_t sum = 0; + for (uint8_t i = 0; i < len; i++) { + sum += CRUMB(bytes[i], 0); + sum += CRUMB(bytes[i], 2); + sum += CRUMB(bytes[i], 4); + sum += CRUMB(bytes[i], 6); + } + sum ^= mask; + return sum; +} +static uint8_t calcSumCrumbAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { + return ~calcSumCrumbAdd(bytes, len, mask); +} +static uint8_t calcSumNibbleAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { + uint8_t sum = 0; + for (uint8_t i = 0; i < len; i++) { + sum += NIBBLE_LOW(bytes[i]); + sum += NIBBLE_HIGH(bytes[i]); + } + sum ^= mask; + return sum; +} +static uint8_t calcSumNibbleAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask){ + return ~calcSumNibbleAdd(bytes, len, mask); +} + +static uint8_t calcSumByteAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { + uint8_t sum = 0; + for (uint8_t i = 0; i < len; i++) + sum += bytes[i]; + sum ^= mask; + return sum; +} +// Ones complement +static uint8_t calcSumByteAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { + return ~calcSumByteAdd(bytes, len, mask); +} + +static uint8_t calcSumByteSub( uint8_t* bytes, uint8_t len, uint32_t mask) { + uint8_t sum = 0; + for (uint8_t i = 0; i < len; i++) + sum -= bytes[i]; + sum ^= mask; + return sum; +} +static uint8_t calcSumByteSubOnes( uint8_t* bytes, uint8_t len, uint32_t mask){ + return ~calcSumByteSub(bytes, len, mask); +} +static uint8_t calcSumNibbleSub( uint8_t* bytes, uint8_t len, uint32_t mask) { + uint8_t sum = 0; + for (uint8_t i = 0; i < len; i++) { + sum -= NIBBLE_LOW(bytes[i]); + sum -= NIBBLE_HIGH(bytes[i]); + } + sum ^= mask; + return sum; +} +static uint8_t calcSumNibbleSubOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { + return ~calcSumNibbleSub(bytes, len, mask); +} + int CmdAnalyseLCR(const char *Cmd) { uint8_t data[50]; char cmdp = param_getchar(Cmd, 0); @@ -45,17 +137,117 @@ int CmdAnalyseLCR(const char *Cmd) { PrintAndLog("Target [%02X] requires final LRC XOR byte value: 0x%02X",data[len-1] ,finalXor); return 0; } +int CmdAnalyseCRC(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_analyse_crc(); + + int len = strlen(Cmd); + if ( len & 1 ) return usage_analyse_crc(); + + // add 1 for null terminator. + uint8_t *data = malloc(len+1); + if ( data == NULL ) return 1; + + if ( param_gethex(Cmd, 0, data, len)) { + free(data); + return usage_analyse_crc(); + } + len >>= 1; + + PrintAndLog("\nTests with '%s' hex bytes", sprint_hex(data, len)); + PrintAndLog(" JA: CRC8: %X (0x6C expected)", CRC8ja(data, len) ); + + PrintAndLog("\nTests of reflection. Two current methods in source code"); + PrintAndLog(" reflect(0x3e23L,3) is %04X == 0x3e26", reflect(0x3e23L,3) ); + PrintAndLog(" SwapBits(0x3e23L,3) is %04X == 0x3e26", SwapBits(0x3e23L,3) ); + PrintAndLog(" 0xB400 == %04X", reflect( (1 << 16 | 0xb400),16) ); + + // + // Test of CRC16, '123456789' string. + // + PrintAndLog("\nTests with '123456789' string"); + uint8_t dataStr[] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39 }; + uint8_t legic8 = CRC8Legic(dataStr, sizeof(dataStr)); + + PrintAndLog("JA: CRC8 : %X (0x28 expected)", CRC8ja(dataStr, sizeof(dataStr)) ); + PrintAndLog("LEGIC: CRC16: %X", CRC16Legic(dataStr, sizeof(dataStr), legic8)); + + //these below has been tested OK. + PrintAndLog("Confirmed CRC Implementations"); + PrintAndLog("LEGIC: CRC8 : %X (0xC6 expected)", legic8); + PrintAndLog("MAXIM: CRC8 : %X (0xA1 expected)", CRC8Maxim(dataStr, sizeof(dataStr))); + PrintAndLog("DNP : CRC16: %X (0x82EA expected)", CRC16_DNP(dataStr, sizeof(dataStr))); + PrintAndLog("CCITT: CRC16: %X (0xE5CC expected)", CRC16_CCITT(dataStr, sizeof(dataStr))); + + free(data); + return 0; +} +int CmdAnalyseCHKSUM(const char *Cmd){ + + uint8_t data[50]; + uint8_t cmdp = 0; + uint32_t mask = 0xFF; + bool errors = false; + int len = 0; + + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'b': + case 'B': + param_gethex_ex(Cmd, cmdp+1, data, &len); + if ( len%2 ) errors = true; + len >>= 1; + cmdp += 2; + break; + case 'm': + case 'M': + mask = param_get32ex(Cmd, cmdp+1, 0, 16); + cmdp += 2; + break; + case 'h': + case 'H': + return usage_analyse_checksum(); + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_analyse_checksum(); + + PrintAndLog("\nByte Add | 0x%X", calcSumByteAdd(data, len, mask)); + PrintAndLog("Nibble Add | 0x%X", calcSumNibbleAdd(data, len, mask)); + PrintAndLog("Crumb Add | 0x%X", calcSumCrumbAdd(data, len, mask)); + + PrintAndLog("\nByte Subtract | 0x%X", calcSumByteSub(data, len, mask)); + PrintAndLog("Nibble Subtract | 0x%X", calcSumNibbleSub(data, len, mask)); + + PrintAndLog("\nCHECKSUM - One's complement"); + PrintAndLog("Byte Add | 0x%X", calcSumByteAddOnes(data, len, mask)); + PrintAndLog("Nibble Add | 0x%X", calcSumNibbleAddOnes(data, len, mask)); + PrintAndLog("Crumb Add | 0x%X", calcSumCrumbAddOnes(data, len, mask)); + + PrintAndLog("Byte Subtract | 0x%X", calcSumByteSubOnes(data, len, mask)); + PrintAndLog("Nibble Subtract | 0x%X", calcSumNibbleSubOnes(data, len, mask)); + + return 0; +} int CmdAnalyseDates(const char *Cmd){ // look for datestamps in a given array of bytes - PrintAndLog("To be implemented. If you feel to contribute!"); + PrintAndLog("To be implemented. Feel free to contribute!"); return 0; } static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"lcr", CmdAnalyseLCR, 0, "Generate final byte for XOR LRC"}, - {"dates", CmdAnalyseDates, 0, "Look for datestamps in a given array of bytes"}, + {"lcr", CmdAnalyseLCR, 1, "Generate final byte for XOR LRC"}, + {"crc", CmdAnalyseCRC, 1, "Stub method for CRC evaluations"}, + {"chksum", CmdAnalyseCHKSUM, 1, "Checksum with adding, masking and one's complement"}, + {"dates", CmdAnalyseDates, 1, "Look for datestamps in a given array of bytes"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdanalyse.h b/client/cmdanalyse.h index 58ec865a..40ca961b 100644 --- a/client/cmdanalyse.h +++ b/client/cmdanalyse.h @@ -16,9 +16,16 @@ #include "cmdmain.h" #include "proxmark3.h" #include "ui.h" // PrintAndLog -command_t * CmdDataCommands(); +#include "util.h" +#include "crc.h" + +int usage_analyse_lcr(void); +int usage_analyse_checksum(void); +int usage_analyse_crc(void); int CmdAnalyse(const char *Cmd); int CmdAnalyseLCR(const char *Cmd); +int CmdAnalyseCHKSUM(const char *Cmd); int CmdAnalyseDates(const char *Cmd); +int CmdAnalyseCRC(const char *Cmd); #endif -- 2.39.5