From 8dd3daf6257a1047a31d5ef30b3efb1d24620524 Mon Sep 17 00:00:00 2001 From: noproto Date: Fri, 9 Aug 2024 20:22:19 -0400 Subject: [PATCH] Fixed parity bit collection --- lib/nfc/helpers/crypto1.c | 43 +++ lib/nfc/helpers/crypto1.h | 4 + .../protocols/mf_classic/mf_classic_poller.c | 289 +++++++++++------- .../protocols/mf_classic/mf_classic_poller.h | 4 +- .../mf_classic/mf_classic_poller_i.c | 12 +- .../mf_classic/mf_classic_poller_i.h | 2 + lib/toolbox/bit_buffer.c | 2 +- targets/f7/api_symbols.csv | 6 +- 8 files changed, 252 insertions(+), 110 deletions(-) diff --git a/lib/nfc/helpers/crypto1.c b/lib/nfc/helpers/crypto1.c index bd4fc8d61..97b92edfd 100644 --- a/lib/nfc/helpers/crypto1.c +++ b/lib/nfc/helpers/crypto1.c @@ -177,3 +177,46 @@ void crypto1_encrypt_reader_nonce( bit_buffer_set_byte_with_parity(out, i, byte, parity_bit); } } + +static uint8_t lfsr_rollback_bit(Crypto1* crypto1, uint32_t in, int fb) { + int out; + uint8_t ret; + uint32_t t; + + crypto1->odd &= 0xffffff; + t = crypto1->odd; + crypto1->odd = crypto1->even; + crypto1->even = t; + + out = crypto1->even & 1; + out ^= LF_POLY_EVEN & (crypto1->even >>= 1); + out ^= LF_POLY_ODD & crypto1->odd; + out ^= !!in; + out ^= (ret = crypto1_filter(crypto1->odd)) & (!!fb); + + crypto1->even |= (nfc_util_even_parity32(out)) << 23; + return ret; +} + +uint32_t lfsr_rollback_word(Crypto1* crypto1, uint32_t in, int fb) { + uint32_t ret = 0; + for(int i = 31; i >= 0; i--) { + ret |= lfsr_rollback_bit(crypto1, BEBIT(in, i), fb) << (24 ^ i); + } + return ret; +} + +// Return true if the nonce is invalid else return false +bool valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t parity) { + return ((nfc_util_odd_parity8((Nt >> 24) & 0xFF) == + (((parity >> 3) & 1) ^ nfc_util_odd_parity8((NtEnc >> 24) & 0xFF) ^ + FURI_BIT(Ks1, 16))) && + (nfc_util_odd_parity8((Nt >> 16) & 0xFF) == + (((parity >> 2) & 1) ^ nfc_util_odd_parity8((NtEnc >> 16) & 0xFF) ^ + FURI_BIT(Ks1, 8))) && + (nfc_util_odd_parity8((Nt >> 8) & 0xFF) == + (((parity >> 1) & 1) ^ nfc_util_odd_parity8((NtEnc >> 8) & 0xFF) ^ + FURI_BIT(Ks1, 0)))) ? + true : + false; +} diff --git a/lib/nfc/helpers/crypto1.h b/lib/nfc/helpers/crypto1.h index e71ab9a40..ed71bc3e1 100644 --- a/lib/nfc/helpers/crypto1.h +++ b/lib/nfc/helpers/crypto1.h @@ -38,6 +38,10 @@ void crypto1_encrypt_reader_nonce( BitBuffer* out, bool is_nested); +uint32_t lfsr_rollback_word(Crypto1* crypto1, uint32_t in, int fb); + +bool valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t parity); + uint32_t prng_successor(uint32_t x, uint32_t n); #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 87986b5fd..3b7c499a5 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -849,17 +849,6 @@ bool validate_prng_nonce(uint32_t nonce) { return x == (nonce & 0xFFFF); } -// Return 1 if the nonce is invalid else return 0 -/* -uint8_t valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { - return ( - (oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \ - (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \ - (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0))) - ) ? 1 : 0; -} -*/ - // Helper function to add a nonce to the array static bool add_nested_nonce( MfClassicNestedNonceArray* array, @@ -918,6 +907,28 @@ NfcCommand mf_classic_poller_handler_nested_analyze_backdoor(MfClassicPoller* in NfcCommand command = NfcCommandContinue; MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; // TODO: Check for Fudan backdoor + // Can use on more than S variant as a free key for Nested + /* + do { + uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_CMD_AUTH_KEY_B : + MF_CLASSIC_CMD_AUTH_KEY_A; + uint8_t auth_cmd[2] = {auth_type, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); + + if(is_nested) { + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_plain_buffer, // NT gets decrypted by mf_classic_async_auth + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + */ dict_attack_ctx->backdoor = MfClassicBackdoorNone; instance->state = MfClassicPollerStateNestedController; return command; @@ -966,6 +977,7 @@ uint16_t get_median(uint16_t arr[], int n) { NfcCommand mf_classic_poller_handler_nested_calibrate(MfClassicPoller* instance) { // TODO: Calibrate backdoored tags too + // TODO: Check if we have already identified the tag as static encrypted NfcCommand command = NfcCommandContinue; MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; uint8_t nt_enc_calibration_cnt = 11; @@ -984,7 +996,7 @@ NfcCommand mf_classic_poller_handler_nested_calibrate(MfClassicPoller* instance) uint32_t nt_prev = 0; uint32_t nt_enc_prev = 0; uint32_t same_nt_enc_cnt = 0; - bool static_encrypted = false; + uint8_t nt_enc_collected = 0; // Step 1: Perform full authentication once error = mf_classic_poller_auth( @@ -1012,28 +1024,33 @@ NfcCommand mf_classic_poller_handler_nested_calibrate(MfClassicPoller* instance) block, &dict_attack_ctx->current_key, dict_attack_ctx->current_key_type, - &auth_ctx); + &auth_ctx, + false); if(error != MfClassicErrorNone) { FURI_LOG_E(TAG, "Failed to perform nested authentication %u", collection_cycle); continue; } - uint32_t nt_enc = bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); - if(nt_enc == nt_enc_prev) { + nt_enc_temp_arr[collection_cycle] = + bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); + nt_enc_collected++; + } + + for(int i = 0; i < nt_enc_collected; i++) { + if(nt_enc_temp_arr[i] == nt_enc_prev) { same_nt_enc_cnt++; if(same_nt_enc_cnt > 3) { - static_encrypted = true; + dict_attack_ctx->static_encrypted = true; break; } } else { same_nt_enc_cnt = 0; - nt_enc_prev = nt_enc; + nt_enc_prev = nt_enc_temp_arr[i]; } - nt_enc_temp_arr[collection_cycle] = nt_enc; } - if(static_encrypted) { + if(dict_attack_ctx->static_encrypted) { FURI_LOG_E(TAG, "Static encrypted nonce detected"); if(dict_attack_ctx->backdoor == MfClassicBackdoorFM11RF08S) { // TODO: Backdoor static nested attack calibration @@ -1101,23 +1118,10 @@ NfcCommand mf_classic_poller_handler_nested_calibrate(MfClassicPoller* instance) } NfcCommand mf_classic_poller_handler_nested_collect_nt_enc(MfClassicPoller* instance) { - // TODO: Use d_median value and parity to get candidate states. d_median is the center, keep adding +/- 1 until a parity match is found. - /* - uint32_t ncount = 0; - uint32_t nttest = prng_successor(nt1, dmin - 1); - - for(j = dmin; j < dmax + 1; j++) { - nttest = prng_successor(nttest, 1); - ks1 = nt2 ^ nttest; - - if(valid_nonce(nttest, nt2, ks1, par_array)) { - if(ncount > 0) { // we are only interested in disambiguous nonces, try again - FURI_LOG_D(TAG, "Nonce#%lu: dismissed (ambiguous), ntdist=%lu", i + 1, j); - (..) - */ - NfcCommand command = NfcCommandContinue; + // TODO: Handle when nonce is not collected (retry counter? Do not increment nested_target_key) + NfcCommand command = NfcCommandReset; MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - MfClassicNestedNonceArray result = {NULL, 0}; + bool collection_success = false; do { if(dict_attack_ctx->prng_type == MfClassicPrngTypeHard) { @@ -1127,6 +1131,30 @@ NfcCommand mf_classic_poller_handler_nested_collect_nt_enc(MfClassicPoller* inst break; } + if(dict_attack_ctx->static_encrypted) { + FURI_LOG_E(TAG, "Static encrypted nonce detected"); + if(dict_attack_ctx->backdoor == MfClassicBackdoorFM11RF08S) { + // TODO: Backdoor static nested attack with calibrated distance + break; + } else { + // TODO: If not present, just log nonces with parity bits, e.g. + /* + bool success = add_nested_nonce( + &result, + cuid, + dict_attack_ctx->reuse_key_sector, + nt_prev, + nt_enc_prev, + parity, + UINT16_MAX); + if(!success) { + FURI_LOG_E(TAG, "Failed to add nested nonce to array. OOM?"); + } + */ + break; + } + } + uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->reuse_key_sector); uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data); @@ -1134,14 +1162,15 @@ NfcCommand mf_classic_poller_handler_nested_collect_nt_enc(MfClassicPoller* inst MfClassicAuthContext auth_ctx = {}; MfClassicError error; - uint8_t nt_enc_per_collection = 2; - uint32_t nt_enc_arr[nt_enc_per_collection]; - uint8_t par_arr[nt_enc_per_collection]; + uint8_t nonce_pair_index = dict_attack_ctx->nested_target_key % 2; + uint8_t nt_enc_per_collection = 2 + nonce_pair_index; + MfClassicKeyType target_key_type = ((dict_attack_ctx->nested_target_key & 0x03) < 2) ? + MfClassicKeyTypeA : + MfClassicKeyTypeB; + uint8_t target_block = (4 * (dict_attack_ctx->nested_target_key / 4)) + 3; + uint32_t nt_enc_temp_arr[nt_enc_per_collection]; + uint8_t nt_enc_collected = 0; uint8_t parity = 0; - uint32_t nt_prev = 0; - uint32_t nt_enc_prev = 0; - uint32_t same_nt_enc_cnt = 0; - bool static_encrypted = false; // Step 1: Perform full authentication once error = mf_classic_poller_auth( @@ -1158,84 +1187,132 @@ NfcCommand mf_classic_poller_handler_nested_collect_nt_enc(MfClassicPoller* inst FURI_LOG_E(TAG, "Full authentication successful"); - nt_prev = bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); - // Step 2: Perform nested authentication a variable number of times to get nt_enc at a different PRNG offset // eg. Collect most commonly observed nonce from 3 auths to known sector and 4th to target, then separately the // most commonly observed nonce from 4 auths to known sector and 5th to target. This gets us a nonce pair, // at a known distance (confirmed by parity bits) telling us the nt_enc plain. - // We also have backup values for the distance in case of rare issues. - //printf("ks: %08x\n", nth_successor ^ nt_enc); - //MfClassicKeyType target_key_type = - // (dict_attack_ctx->nested_target_key % 2 == 0) ? MfClassicKeyTypeA : MfClassicKeyTypeB; - //uint8_t target_block = (4 * (dict_attack_ctx->nested_target_key / 2)) + 3; - for(uint32_t round_no = 0; round_no < nt_enc_per_collection; round_no++) { + for(uint8_t collection_cycle = 0; collection_cycle < (nt_enc_per_collection - 1); + collection_cycle++) { + // This loop must match the calibrated loop error = mf_classic_poller_auth_nested( instance, block, &dict_attack_ctx->current_key, dict_attack_ctx->current_key_type, - &auth_ctx); + &auth_ctx, + false); if(error != MfClassicErrorNone) { - FURI_LOG_E(TAG, "Failed to perform nested authentication %lu", round_no); - continue; + FURI_LOG_E(TAG, "Failed to perform nested authentication %u", collection_cycle); + break; } - uint32_t nt_enc = bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); - if(nt_enc == nt_enc_prev) { - same_nt_enc_cnt++; - if(same_nt_enc_cnt > 3) { - static_encrypted = true; + nt_enc_temp_arr[collection_cycle] = + bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); + nt_enc_collected++; + } + error = mf_classic_poller_auth_nested( + instance, + target_block, + &dict_attack_ctx->current_key, + target_key_type, + &auth_ctx, + true); + + if(nt_enc_collected != (nt_enc_per_collection - 1)) { + FURI_LOG_E(TAG, "Failed to collect sufficient nt_enc values"); + break; + } + + uint32_t nt_enc = bit_lib_bytes_to_num_be(auth_ctx.nt.data, sizeof(MfClassicNt)); + // Collect parity bits + const uint8_t* parity_data = bit_buffer_get_parity(instance->rx_plain_buffer); + for(int i = 0; i < 4; i++) { + parity = (parity << 1) | (((parity_data[0] >> i) & 0x01) ^ 0x01); + } + // Decrypt the previous nonce + uint32_t nt_prev = nt_enc_temp_arr[nt_enc_collected - 1]; + uint64_t known_key = bit_lib_bytes_to_num_be(dict_attack_ctx->current_key.data, 6); + Crypto1 crypto_temp; + crypto1_init(&crypto_temp, known_key); + crypto1_word(&crypto_temp, nt_prev ^ cuid, 1); + uint32_t decrypted_nt_prev = + (nt_prev ^ lfsr_rollback_word(&crypto_temp, nt_prev ^ cuid, 1)); + + // Find matching nt_enc plain at expected distance + bool found_matching_nt = false; + uint32_t found_nt = 0; + uint16_t current_dist = 0; + const uint16_t max_dist = 16; // 32 would work too + // TODO: Better handling of overflows (allow wrap instead of stopping?) + while(!found_matching_nt && current_dist < max_dist && + ((dict_attack_ctx->d_median - current_dist) != 0) && + ((dict_attack_ctx->d_median + current_dist) != UINT16_MAX)) { + uint32_t nth_successor_positive = + prng_successor(decrypted_nt_prev, dict_attack_ctx->d_median + current_dist); + if(valid_nonce( + nth_successor_positive, nt_enc, nth_successor_positive ^ nt_enc, parity)) { + found_matching_nt = true; + found_nt = nth_successor_positive; + break; + } + if(current_dist > 0) { + uint32_t nth_successor_negative = + prng_successor(decrypted_nt_prev, dict_attack_ctx->d_median - current_dist); + if(valid_nonce( + nth_successor_negative, nt_enc, nth_successor_negative ^ nt_enc, parity)) { + found_matching_nt = true; + found_nt = nth_successor_negative; break; } - } else { - same_nt_enc_cnt = 0; - nt_enc_prev = nt_enc; } - // Collect parity bits - const uint8_t* parity_data = bit_buffer_get_parity(instance->rx_encrypted_buffer); - for(int i = 0; i < 4; i++) { - parity |= ((parity_data[i] & 0x01) << (3 - i)); - } - par_arr[round_no] = parity; - nt_enc_arr[round_no] = nt_enc; + current_dist++; } - if(static_encrypted) { - FURI_LOG_E(TAG, "Static encrypted nonce detected"); - if(dict_attack_ctx->backdoor == MfClassicBackdoorFM11RF08S) { - // TODO: Backdoor static nested attack - break; - } else { - // TODO: If not present, just log nonces with parity bits - bool success = add_nested_nonce( - &result, - cuid, - dict_attack_ctx->reuse_key_sector, - nt_prev, - nt_enc_prev, - parity, - UINT16_MAX); - if(!success) { - FURI_LOG_E(TAG, "Failed to add nested nonce to array. OOM?"); - } - break; + // Add the nonce to the array + if(found_matching_nt) { + collection_success = add_nested_nonce( + &dict_attack_ctx->nested_nonce, + cuid, + dict_attack_ctx->nested_target_key, + found_nt, + nt_enc, + parity, + 0); + if(!collection_success) { + FURI_LOG_E(TAG, "Failed to add nested nonce to array. OOM?"); } + } else { + FURI_LOG_E(TAG, "Failed to find matching nonce"); } - for(uint8_t i = 0; i < nt_enc_per_collection; i++) { - FURI_LOG_E(TAG, "nt_enc: %08lx", nt_enc_arr[i]); - FURI_LOG_E( - TAG, - "parity: %u%u%u%u", - ((par_arr[i] >> 3) & 1), - ((par_arr[i] >> 2) & 1), - ((par_arr[i] >> 1) & 1), - (par_arr[i] & 1)); - } + FURI_LOG_E( + TAG, + "Target: %u (nonce pair %u, key type %s, block %u)", + dict_attack_ctx->nested_target_key, + nonce_pair_index, + (target_key_type == MfClassicKeyTypeA) ? "A" : "B", + target_block); + FURI_LOG_E(TAG, "cuid: %08lx", cuid); + FURI_LOG_E(TAG, "nt_enc: %08lx", nt_enc); + FURI_LOG_E( + TAG, + "parity: %u%u%u%u", + ((parity >> 3) & 1), + ((parity >> 2) & 1), + ((parity >> 1) & 1), + (parity & 1)); + FURI_LOG_E(TAG, "nt_enc prev: %08lx", nt_prev); + FURI_LOG_E(TAG, "nt_enc prev decrypted: %08lx", decrypted_nt_prev); } while(false); + // Probably belongs in the controller + if(collection_success) { + dict_attack_ctx->nested_target_key++; + dict_attack_ctx->retry_counter = 0; + } else { + dict_attack_ctx->retry_counter++; + } instance->state = MfClassicPollerStateNestedController; mf_classic_poller_halt(instance); @@ -1327,10 +1404,10 @@ NfcCommand mf_classic_poller_handler_nested_log(MfClassicPoller* instance) { NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance) { // Iterate through keys - // TODO: Fix infinite loop somewhere NfcCommand command = NfcCommandContinue; MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - if(dict_attack_ctx->nested_nonce.count > 0) { + if((dict_attack_ctx->nested_nonce.count > 0) && + (dict_attack_ctx->nested_target_key % 2 == 0)) { if(dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) { instance->state = MfClassicPollerStateNestedDictAttack; return command; @@ -1349,9 +1426,17 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance instance->state = MfClassicPollerStateNestedCalibrate; return command; } - // Target all sectors, key A and B - for(uint8_t key_idx = 0; key_idx <= (instance->sectors_total * 2); key_idx++) { - dict_attack_ctx->nested_target_key = key_idx; + // Target all sectors, key A and B, first and second nonce + if(dict_attack_ctx->nested_target_key < (instance->sectors_total * 4)) { + if(dict_attack_ctx->retry_counter > 3) { + // Bad sector, skip + if(dict_attack_ctx->nested_nonce.nonces) { + free(dict_attack_ctx->nested_nonce.nonces); + dict_attack_ctx->nested_nonce.count = 0; + } + dict_attack_ctx->nested_target_key += 4; + dict_attack_ctx->retry_counter = 0; + } instance->state = MfClassicPollerStateNestedCollectNtEnc; return command; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 518d029d0..043424989 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -231,6 +231,7 @@ MfClassicError mf_classic_poller_auth( * @param[in] key key to be used for authentication. * @param[in] key_type key type to be used for authentication. * @param[out] data pointer to MfClassicAuthContext structure to be filled with authentication data. + * @param[in] early_ret return immediately after receiving encrypted nonce. * @return MfClassicErrorNone on success, an error code on failure. */ MfClassicError mf_classic_poller_auth_nested( @@ -238,7 +239,8 @@ MfClassicError mf_classic_poller_auth_nested( uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, - MfClassicAuthContext* data); + MfClassicAuthContext* data, + bool early_ret); /** * @brief Halt the tag. diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 949ef8e66..d3a3882c1 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -111,7 +111,8 @@ static MfClassicError mf_classic_poller_auth_common( MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data, - bool is_nested) { + bool is_nested, + bool early_ret) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -130,6 +131,7 @@ static MfClassicError mf_classic_poller_auth_common( if(data) { data->nt = nt; } + if(early_ret) break; uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data); uint64_t key_num = bit_lib_bytes_to_num_be(key->data, sizeof(MfClassicKey)); @@ -185,7 +187,7 @@ MfClassicError mf_classic_poller_auth( MfClassicAuthContext* data) { furi_check(instance); furi_check(key); - return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false); + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false, false); } MfClassicError mf_classic_poller_auth_nested( @@ -193,10 +195,12 @@ MfClassicError mf_classic_poller_auth_nested( uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, - MfClassicAuthContext* data) { + MfClassicAuthContext* data, + bool early_ret) { furi_check(instance); furi_check(key); - return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, true); + return mf_classic_poller_auth_common( + instance, block_num, key, key_type, data, true, early_ret); } MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index f24f3496e..0614f99c1 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -120,8 +120,10 @@ typedef struct { uint8_t hard_nt_count; uint8_t nested_target_key; MfClassicNestedNonceArray nested_nonce; + bool static_encrypted; bool calibrated; uint16_t d_median; + uint8_t retry_counter; } MfClassicPollerDictAttackContext; typedef struct { diff --git a/lib/toolbox/bit_buffer.c b/lib/toolbox/bit_buffer.c index 85a52e79d..e261e80d4 100644 --- a/lib/toolbox/bit_buffer.c +++ b/lib/toolbox/bit_buffer.c @@ -113,7 +113,7 @@ void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size uint8_t bit = FURI_BIT(data[bits_processed / BITS_IN_BYTE + 1], bits_processed % BITS_IN_BYTE); - if(bits_processed % BITS_IN_BYTE) { + if((bits_processed % BITS_IN_BYTE) == 0) { buf->parity[curr_byte / BITS_IN_BYTE] = bit; } else { buf->parity[curr_byte / BITS_IN_BYTE] |= bit << (bits_processed % BITS_IN_BYTE); diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 4bfe37abb..b2e818fb8 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,71.0,, +Version,+,72.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -2211,6 +2211,7 @@ Function,+,lfrfid_worker_start_thread,void,LFRFIDWorker* Function,+,lfrfid_worker_stop,void,LFRFIDWorker* Function,+,lfrfid_worker_stop_thread,void,LFRFIDWorker* Function,+,lfrfid_worker_write_start,void,"LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*" +Function,+,lfsr_rollback_word,uint32_t,"Crypto1*, uint32_t, int" Function,-,lgamma,double,double Function,-,lgamma_r,double,"double, int*" Function,-,lgammaf,float,float @@ -2506,7 +2507,7 @@ Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" -Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*, _Bool" Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* @@ -3525,6 +3526,7 @@ Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* Function,-,utoa,char*,"unsigned, char*, int" +Function,+,valid_nonce,_Bool,"uint32_t, uint32_t, uint32_t, uint8_t" Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" Function,+,validator_is_file_free,void,ValidatorIsFile*