Merge branch 'master' into smartcard-relay

This commit is contained in:
Grayson Martin 2023-07-13 17:14:19 -05:00
commit efea49415d
No known key found for this signature in database
GPG key ID: 4914C62F2696A273
13 changed files with 206 additions and 58 deletions

View file

@ -139,7 +139,7 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo,
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
}
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
return mifare_classic_authex_cmd(pcs, uid, blockNo, keyType ? MIFARE_AUTH_KEYA : MIFARE_AUTH_KEYB, ui64Key, isNested, ntptr, timing);
return mifare_classic_authex_cmd(pcs, uid, blockNo, (keyType & 1) == 0 ? MIFARE_AUTH_KEYA : MIFARE_AUTH_KEYB, ui64Key, isNested, ntptr, timing);
}
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {

View file

@ -78,6 +78,8 @@ THE SOFTWARE.
#define DEBUG_KEY_ELIMINATION 1
// #define DEBUG_BRUTE_FORCE
#define MIN_BUCKETS_SIZE 128
typedef enum {
EVEN_STATE = 0,
ODD_STATE = 1
@ -88,7 +90,8 @@ static uint32_t bf_test_nonce[256];
static uint8_t bf_test_nonce_2nd_byte[256];
static uint8_t bf_test_nonce_par[256];
static uint32_t bucket_count = 0;
static statelist_t *buckets[128];
static size_t buckets_allocated = 0;
static statelist_t **buckets = NULL;
static uint32_t keys_found = 0;
static uint64_t num_keys_tested;
static uint64_t found_bs_key = 0;
@ -157,6 +160,7 @@ crack_states_thread(void *x) {
uint8_t *best_first_bytes;
} *thread_arg;
const int num_brute_force_threads = NUM_BRUTE_FORCE_THREADS;
thread_arg = (struct arg *)x;
const int thread_id = thread_arg->thread_ID;
uint32_t current_bucket = thread_id;
@ -188,7 +192,7 @@ crack_states_thread(void *x) {
}
}
}
current_bucket += NUM_BRUTE_FORCE_THREADS;
current_bucket += num_brute_force_threads;
}
return NULL;
}
@ -294,12 +298,34 @@ static void write_benchfile(statelist_t *candidates) {
#endif
static bool ensure_buckets_alloc(size_t need_buckets) {
if (need_buckets > buckets_allocated) {
size_t alloc_sz = ((buckets_allocated == 0) ? MIN_BUCKETS_SIZE : (buckets_allocated * 2));
while (need_buckets > alloc_sz) {
alloc_sz *= 2;
}
buckets = realloc(buckets, sizeof(statelist_t *) * alloc_sz);
if (buckets == NULL) {
buckets_allocated = 0;
return false;
}
memset(buckets + buckets_allocated, 0, (alloc_sz - buckets_allocated) * sizeof(statelist_t *));
buckets_allocated = alloc_sz;
}
return true;
}
bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint64_t *found_key) {
#if defined (WRITE_BENCH_FILE)
write_benchfile(candidates);
#endif
bool silent = (bf_rate != NULL);
const int num_brute_force_threads = NUM_BRUTE_FORCE_THREADS;
keys_found = 0;
num_keys_tested = 0;
found_bs_key = 0;
@ -310,6 +336,11 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
bucket_count = 0;
for (statelist_t *p = candidates; p != NULL; p = p->next) {
if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) {
if (!ensure_buckets_alloc(bucket_count + 1)) {
PrintAndLogEx(ERR, "Can't allocate buckets, abort!");
return false;
}
buckets[bucket_count] = p;
bucket_count++;
}
@ -322,7 +353,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
return false;
#endif
pthread_t threads[NUM_BRUTE_FORCE_THREADS];
pthread_t threads[num_brute_force_threads];
struct args {
bool silent;
int thread_ID;
@ -331,9 +362,9 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
uint64_t maximum_states;
noncelist_t *nonces;
uint8_t *best_first_bytes;
} thread_args[NUM_BRUTE_FORCE_THREADS];
} thread_args[num_brute_force_threads];
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
for (uint32_t i = 0; i < num_brute_force_threads; i++) {
thread_args[i].thread_ID = i;
thread_args[i].silent = silent;
thread_args[i].cuid = cuid;
@ -343,10 +374,14 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
thread_args[i].best_first_bytes = best_first_bytes;
pthread_create(&threads[i], NULL, crack_states_thread, (void *)&thread_args[i]);
}
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
for (uint32_t i = 0; i < num_brute_force_threads; i++) {
pthread_join(threads[i], 0);
}
free(buckets);
buckets = NULL;
buckets_allocated = 0;
uint64_t elapsed_time = msclock() - start_time;
if (bf_rate != NULL)
@ -434,30 +469,31 @@ static bool read_bench_data(statelist_t *test_candidates) {
float brute_force_benchmark(void) {
statelist_t test_candidates[NUM_BRUTE_FORCE_THREADS];
const int num_brute_force_threads = NUM_BRUTE_FORCE_THREADS;
statelist_t test_candidates[num_brute_force_threads];
test_candidates[0].states[ODD_STATE] = calloc(1, (TEST_BENCH_SIZE + 1) * sizeof(uint32_t));
test_candidates[0].states[EVEN_STATE] = calloc(1, (TEST_BENCH_SIZE + 1) * sizeof(uint32_t));
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS - 1; i++) {
for (uint32_t i = 0; i < num_brute_force_threads - 1; i++) {
test_candidates[i].next = test_candidates + i + 1;
test_candidates[i + 1].states[ODD_STATE] = test_candidates[0].states[ODD_STATE];
test_candidates[i + 1].states[EVEN_STATE] = test_candidates[0].states[EVEN_STATE];
}
test_candidates[NUM_BRUTE_FORCE_THREADS - 1].next = NULL;
test_candidates[num_brute_force_threads - 1].next = NULL;
if (!read_bench_data(test_candidates)) {
PrintAndLogEx(NORMAL, "Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE);
return DEFAULT_BRUTE_FORCE_RATE;
}
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
for (uint32_t i = 0; i < num_brute_force_threads; i++) {
test_candidates[i].len[ODD_STATE] = TEST_BENCH_SIZE;
test_candidates[i].len[EVEN_STATE] = TEST_BENCH_SIZE;
test_candidates[i].states[ODD_STATE][TEST_BENCH_SIZE] = -1;
test_candidates[i].states[EVEN_STATE][TEST_BENCH_SIZE] = -1;
}
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t)NUM_BRUTE_FORCE_THREADS;
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t)num_brute_force_threads;
float bf_rate;
uint64_t found_key = 0;

View file

@ -57,6 +57,11 @@
"description": ""
},
{
"value": "6a02c3020602ffff",
"name": "Access: Hotel: Hilton",
"description": "TCI might be a wildcard before a reservation is made"
},
{
"value": "6a02cb0206021100deadbeefdeadbeef",
@ -64,10 +69,45 @@
"description": "Last 8 bytes refer to reader group identifier, common for all readers in same home installation, allows to differentiate between keys for different homes"
},
{
"value": "6a02c30209010001",
"name": "Access: Car Pairing: BMW",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for BMW"
},
{
"value": "6a02c30209010201",
"name": "Access: Mercedes Pairing",
"description": "Device does not respond to this frame. Displays a car pairing popup for Mercedes"
"name": "Access: Car Pairing: Mercedes",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for Mercedes"
},
{
"value": "6a02c30209010051",
"name": "Access: Car Pairing: Genesis",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for Genesis"
},
{
"value": "6a02c30209010041",
"name": "Access: Car Pairing: KIA",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for KIA"
},
{
"value": "6a02c30209010301",
"name": "Access: Car Pairing: Hyundai",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for Hyundai"
},
{
"value": "6a02c30209010701",
"name": "Access: Car Pairing: BYD",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for BYD"
},
{
"value": "6a02c30209010241",
"name": "Access: Car Pairing: Denza",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for Denza"
},
{
"value": "6a02c30209010091",
"name": "Access: Car Pairing: Lotus",
"description": "Device does not respond to poll after this frame. Displays a car pairing popup for Lotus"
},

View file

@ -2241,28 +2241,29 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
snprintf(filename, FILE_PATH_SIZE, "hf-mf-%s-nonces.bin", uid);
}
// detect MFC EV1 Signature
if (detect_mfc_ev1_signature() && keylen == 0) {
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
blockno = 69;
keytype = MF_KEY_B;
memcpy(key, g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
}
if (known_target_key == false && nonce_file_read == false) {
// check if tag doesn't have static nonce
if (detect_classic_static_nonce() == NONCE_STATIC) {
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
PrintAndLogEx(HINT, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
return PM3_EOPABORTED;
if (g_session.pm3_present && !tests) {
// detect MFC EV1 Signature
if (detect_mfc_ev1_signature() && keylen == 0) {
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
blockno = 69;
keytype = MF_KEY_B;
memcpy(key, g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
}
uint64_t key64 = 0;
// check if we can authenticate to sector
if (mfCheckKeys(blockno, keytype, true, 1, key, &key64) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block: %3d key type: %c", blockno, (keytype == MF_KEY_B) ? 'B' : 'A');
return PM3_EWRONGANSWER;
if (known_target_key == false && nonce_file_read == false) {
// check if tag doesn't have static nonce
if (detect_classic_static_nonce() == NONCE_STATIC) {
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
PrintAndLogEx(HINT, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
return PM3_EOPABORTED;
}
uint64_t key64 = 0;
// check if we can authenticate to sector
if (mfCheckKeys(blockno, keytype, true, 1, key, &key64) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block: %3d key type: %c", blockno, (keytype == MF_KEY_B) ? 'B' : 'A');
return PM3_EWRONGANSWER;
}
}
}

View file

@ -52,6 +52,7 @@
#define STATE_FILES_DIRECTORY "hardnested_tables/"
#define STATE_FILE_TEMPLATE "bitflip_%d_%03" PRIx16 "_states.bin.bz2"
#define STATE_FILE_TEMPLATE_RAW "bitflip_%d_%03" PRIx16 "_states.bin"
#define DEBUG_KEY_ELIMINATION
// #define DEBUG_REDUCTION
@ -260,10 +261,13 @@ static void init_bitflip_bitarrays(void) {
char state_files_path[strlen(get_my_executable_directory()) + strlen(STATE_FILES_DIRECTORY) + strlen(STATE_FILE_TEMPLATE) + 1];
char state_file_name[strlen(STATE_FILE_TEMPLATE) + 1];
char state_file_raw_name[strlen(STATE_FILE_TEMPLATE_RAW) + 1];
for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
num_effective_bitflips[odd_even] = 0;
for (uint16_t bitflip = 0x001; bitflip < 0x400; bitflip++) {
bool open_uncompressed = false;
bitflip_bitarrays[odd_even][bitflip] = NULL;
count_bitflip_bitarrays[odd_even][bitflip] = 1 << 24;
@ -273,14 +277,21 @@ static void init_bitflip_bitarrays(void) {
char *path;
if (searchFile(&path, RESOURCES_SUBDIR, state_files_path, "", true) != PM3_SUCCESS) {
continue;
snprintf(state_file_raw_name, sizeof(state_file_raw_name), STATE_FILE_TEMPLATE_RAW, odd_even, bitflip);
strncpy(state_files_path, STATE_FILES_DIRECTORY, sizeof(state_files_path) - 1);
strncat(state_files_path, state_file_raw_name, sizeof(state_files_path) - (strlen(STATE_FILES_DIRECTORY) + 1));
if (searchFile(&path, RESOURCES_SUBDIR, state_files_path, "", true) == PM3_SUCCESS) {
open_uncompressed = true;
} else {
continue;
}
}
FILE *statesfile = fopen(path, "rb");
free(path);
if (statesfile == NULL) {
continue;
} else {
} else if (!open_uncompressed) {
fseek(statesfile, 0, SEEK_END);
int fsize = ftell(statesfile);
if (fsize == -1) {
@ -335,6 +346,52 @@ static void init_bitflip_bitarrays(void) {
#endif
}
BZ2_bzDecompressEnd(&compressed_stream);
} else {
fseek(statesfile, 0, SEEK_END);
int fsize = ftell(statesfile);
if (fsize == -1) {
PrintAndLogEx(ERR, "File read error with %s. Aborting...\n", state_file_name);
fclose(statesfile);
exit(5);
}
uint32_t filesize = (uint32_t)fsize;
rewind(statesfile);
uint32_t count = 0;
size_t bytesread = fread(&count, 1, sizeof(count), statesfile);
if (bytesread != 4) {
PrintAndLogEx(ERR, "File read error with %s. Aborting...\n", state_file_name);
fclose(statesfile);
exit(5);
}
if ((float)count / (1 << 24) < IGNORE_BITFLIP_THRESHOLD) {
uint32_t *bitset = (uint32_t *)malloc_bitarray(sizeof(uint32_t) * (1 << 19));
if (bitset == NULL) {
PrintAndLogEx(ERR, "Out of memory error in init_bitflip_statelists(). Aborting...\n");
fclose(statesfile);
exit(4);
}
bytesread = fread(bitset, 1, filesize-sizeof(count), statesfile);
if (bytesread != filesize-sizeof(count)) {
PrintAndLogEx(ERR, "File read error with %s. Aborting...\n", state_file_name);
fclose(statesfile);
exit(5);
}
effective_bitflip[odd_even][num_effective_bitflips[odd_even]++] = bitflip;
bitflip_bitarrays[odd_even][bitflip] = bitset;
count_bitflip_bitarrays[odd_even][bitflip] = count;
#if defined (DEBUG_REDUCTION)
PrintAndLogEx(INFO, "(%03" PRIx16 " %s:%5.1f%%) ", bitflip, odd_even ? "odd " : "even", (float)count / (1 << 24) * 100.0);
line++;
if (line == 8) {
PrintAndLogEx(NORMAL, "");
line = 0;
}
#endif
}
}
}
effective_bitflip[odd_even][num_effective_bitflips[odd_even]] = 0x400; // EndOfList marker
@ -1223,31 +1280,32 @@ __attribute__((force_align_arg_pointer))
static void check_for_BitFlipProperties(bool time_budget) {
// create and run worker threads
pthread_t thread_id[NUM_CHECK_BITFLIPS_THREADS];
const size_t num_check_bitflip_threads = NUM_CHECK_BITFLIPS_THREADS;
pthread_t thread_id[num_check_bitflip_threads];
uint8_t args[NUM_CHECK_BITFLIPS_THREADS][3];
uint16_t bytes_per_thread = (256 + (NUM_CHECK_BITFLIPS_THREADS / 2)) / NUM_CHECK_BITFLIPS_THREADS;
for (uint32_t i = 0; i < NUM_CHECK_BITFLIPS_THREADS; i++) {
uint8_t args[num_check_bitflip_threads][3];
uint16_t bytes_per_thread = (256 + (num_check_bitflip_threads / 2)) / num_check_bitflip_threads;
for (uint32_t i = 0; i < num_check_bitflip_threads; i++) {
args[i][0] = i * bytes_per_thread;
args[i][1] = MIN(args[i][0] + bytes_per_thread - 1, 255);
args[i][2] = time_budget;
}
// args[][] is uint8_t so max 255, no need to check it
// args[NUM_CHECK_BITFLIPS_THREADS - 1][1] = MAX(args[NUM_CHECK_BITFLIPS_THREADS - 1][1], 255);
// args[num_check_bitflip_threads - 1][1] = MAX(args[num_check_bitflip_threads - 1][1], 255);
// start threads
for (uint32_t i = 0; i < NUM_CHECK_BITFLIPS_THREADS; i++) {
for (uint32_t i = 0; i < num_check_bitflip_threads; i++) {
pthread_create(&thread_id[i], NULL, check_for_BitFlipProperties_thread, args[i]);
}
// wait for threads to terminate:
for (uint32_t i = 0; i < NUM_CHECK_BITFLIPS_THREADS; i++) {
for (uint32_t i = 0; i < num_check_bitflip_threads; i++) {
pthread_join(thread_id[i], NULL);
}
if (hardnested_stage & CHECK_2ND_BYTES) {
hardnested_stage &= ~CHECK_1ST_BYTES; // we are done with 1st stage, except...
for (uint32_t i = 0; i < NUM_CHECK_BITFLIPS_THREADS; i++) {
for (uint32_t i = 0; i < num_check_bitflip_threads; i++) {
if (args[i][1] != 0) {
hardnested_stage |= CHECK_1ST_BYTES; // ... when any of the threads didn't complete in time
break;
@ -2057,10 +2115,11 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
init_book_of_work();
// create and run worker threads
pthread_t thread_id[NUM_REDUCTION_WORKING_THREADS];
const size_t num_reduction_working_threads = NUM_REDUCTION_WORKING_THREADS;
pthread_t thread_id[num_reduction_working_threads];
uint16_t sums1[NUM_REDUCTION_WORKING_THREADS][3];
for (uint32_t i = 0; i < NUM_REDUCTION_WORKING_THREADS; i++) {
uint16_t sums1[num_reduction_working_threads][3];
for (uint32_t i = 0; i < num_reduction_working_threads; i++) {
sums1[i][0] = sum_a0_idx;
sums1[i][1] = sum_a8_idx;
sums1[i][2] = i + 1;
@ -2068,7 +2127,7 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
}
// wait for threads to terminate:
for (uint32_t i = 0; i < NUM_REDUCTION_WORKING_THREADS; i++) {
for (uint32_t i = 0; i < num_reduction_working_threads; i++) {
pthread_join(thread_id[i], NULL);
}

View file

@ -621,9 +621,7 @@ bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int
// check if we can communicate with Pm3
int TestProxmark(pm3_device_t *dev) {
PacketResponseNG resp;
uint16_t len = 32;
bool is_tcp_conn = false;
uint8_t data[len];
for (uint16_t i = 0; i < len; i++)
data[i] = i & 0xFF;
@ -643,6 +641,7 @@ int TestProxmark(pm3_device_t *dev) {
timeout = 1000;
#endif
PacketResponseNG resp;
if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == 0) {
return PM3_ETIMEOUT;
}
@ -666,12 +665,15 @@ int TestProxmark(pm3_device_t *dev) {
memcpy(&g_pm3_capabilities, resp.data.asBytes, MIN(sizeof(capabilities_t), resp.length));
g_conn.send_via_fpc_usart = g_pm3_capabilities.via_fpc;
g_conn.uart_speed = g_pm3_capabilities.baudrate;
is_tcp_conn = memcmp(g_conn.serial_port_name, "tcp:", 4) == 0;
bool is_tcp_conn = (memcmp(g_conn.serial_port_name, "tcp:", 4) == 0);
bool is_bt_conn = (memcmp(g_conn.serial_port_name, "bt:", 3) == 0);
PrintAndLogEx(INFO, "Communicating with PM3 over %s%s%s",
g_conn.send_via_fpc_usart ? _YELLOW_("FPC UART") : _YELLOW_("USB-CDC"),
is_tcp_conn ? " over " _YELLOW_("TCP") : "",
memcmp(g_conn.serial_port_name, "bt:", 3) == 0 ? " over " _YELLOW_("BT") : "");
(g_conn.send_via_fpc_usart) ? _YELLOW_("FPC UART") : _YELLOW_("USB-CDC"),
(is_tcp_conn) ? " over " _YELLOW_("TCP") : "",
(is_bt_conn) ? " over " _YELLOW_("BT") : ""
);
if (g_conn.send_via_fpc_usart) {
PrintAndLogEx(INFO, "PM3 UART serial baudrate: " _YELLOW_("%u") "\n", g_conn.uart_speed);
@ -771,7 +773,6 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms
if (msclock() - tmp_clk > 3000 && show_warning) {
// 3 seconds elapsed (but this doesn't mean the timeout was exceeded)
// PrintAndLogEx(INFO, "Waiting for a response from the Proxmark3...");
PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button");
show_warning = false;
}

View file

@ -268,12 +268,20 @@ static size_t removeEm410xParity(uint8_t *bits, size_t startIdx, bool isLong, bo
*validLong = false;
uint8_t bLen = isLong ? 110 : 55;
uint16_t parityCol[4] = { 0, 0, 0, 0 };
for (int word = 0; word < bLen; word += 5) {
for (int bit = 0; bit < 5; bit++) {
if (word + bit >= bLen) break;
if (word + bit >= bLen) {
break;
}
parityWd = (parityWd << 1) | bits[startIdx + word + bit];
if ((word <= 50) && (bit < 4))
if ((word <= 50) && (bit < 4)) {
parityCol[bit] = (parityCol[bit] << 1) | bits[startIdx + word + bit];
}
bits[bitCnt++] = (bits[startIdx + word + bit]);
}
if (word + 5 > bLen) break;
@ -293,12 +301,15 @@ static size_t removeEm410xParity(uint8_t *bits, size_t startIdx, bool isLong, bo
if (!isLong && validRowParitySkipColP && validColParity) {
*validShort = true;
}
if (isLong && validRowParity) {
*validLong = true;
}
if (isLong && validRowParitySkipColP && validColParity) {
*validShortExtended = true;
}
if (*validShort || *validShortExtended || *validLong) {
return bitCnt;
} else {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -221,7 +221,7 @@ reg curbit;
`ifdef PM3ICOPYX
`define EDGE_DETECT_THRESHOLD 3
`else
`define EDGE_DETECT_THRESHOLD 5
`define EDGE_DETECT_THRESHOLD 7
`endif
`define EDGE_DETECT_THRESHOLDHIGH 20