diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index df01a348c85..02bc677ba69 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -143,7 +143,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out) { + BitBuffer* out, + bool is_nested) { furi_assert(crypto); furi_assert(nt); furi_assert(nr); @@ -153,7 +154,11 @@ void crypto1_encrypt_reader_nonce( uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t)); crypto1_init(crypto, key); - crypto1_word(crypto, nt_num ^ cuid, 0); + if(is_nested) { + nt_num = crypto1_word(crypto, nt_num ^ cuid, 1) ^ nt_num; + } else { + crypto1_word(crypto, nt_num ^ cuid, 0); + } for(size_t i = 0; i < 4; i++) { uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index f2bdb272b0e..7cc16fcffde 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -35,7 +35,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out); + BitBuffer* out, + bool is_nested); uint32_t prng_successor(uint32_t x, uint32_t n); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index f05a6800ad1..19e52570175 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -178,6 +178,25 @@ MfClassicError mf_classic_poller_get_nt( MfClassicKeyType key_type, MfClassicNt* nt); +/** + * @brief Collect tag nonce during nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Starts nested authentication procedure and collects tag nonce. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] nt pointer to the MfClassicNt structure to be filled with nonce data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt); + /** * @brief Perform authentication. * @@ -200,6 +219,27 @@ MfClassicError mf_classic_poller_auth( MfClassicKeyType key_type, MfClassicAuthContext* data); +/** + * @brief Perform nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Perform nested authentication as specified in Mf Classic protocol. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @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. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + /** * @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 4b071815ea8..16bfb3f7282 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -33,11 +33,12 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) { return ret; } -MfClassicError mf_classic_poller_get_nt( +static MfClassicError mf_classic_poller_get_nt_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKeyType key_type, - MfClassicNt* nt) { + MfClassicNt* nt, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -47,14 +48,29 @@ MfClassicError mf_classic_poller_get_nt( uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); - error = iso14443_3a_poller_send_standard_frame( - instance->iso14443_3a_poller, - instance->tx_plain_buffer, - instance->rx_plain_buffer, - MF_CLASSIC_FWT_FC); - if(error != Iso14443_3aErrorWrongCrc) { - ret = mf_classic_process_error(error); - break; + 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; + } + } else { + error = iso14443_3a_poller_send_standard_frame( + instance->iso14443_3a_poller, + instance->tx_plain_buffer, + instance->rx_plain_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorWrongCrc) { + ret = mf_classic_process_error(error); + break; + } } if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) { ret = MfClassicErrorProtocol; @@ -69,12 +85,29 @@ MfClassicError mf_classic_poller_get_nt( return ret; } -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_get_nt( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, false); +} + +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, true); +} + +static MfClassicError mf_classic_poller_auth_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, - MfClassicAuthContext* data) { + MfClassicAuthContext* data, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -84,7 +117,11 @@ MfClassicError mf_classic_poller_auth( iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); MfClassicNt nt = {}; - ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + if(is_nested) { + ret = mf_classic_poller_get_nt_nested(instance, block_num, key_type, &nt); + } else { + ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + } if(ret != MfClassicErrorNone) break; if(data) { data->nt = nt; @@ -96,7 +133,13 @@ MfClassicError mf_classic_poller_auth( furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); crypto1_encrypt_reader_nonce( - instance->crypto, key_num, cuid, nt.data, nr.data, instance->tx_encrypted_buffer); + instance->crypto, + key_num, + cuid, + nt.data, + nr.data, + instance->tx_encrypted_buffer, + is_nested); error = iso14443_3a_poller_txrx_custom_parity( instance->iso14443_3a_poller, instance->tx_encrypted_buffer, @@ -130,6 +173,24 @@ MfClassicError mf_classic_poller_auth( return ret; } +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false); +} + +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, true); +} + MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index e735e2c6ddd..cb34f969adc 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e25254dddd2..439fc7bf5a5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2288,6 +2288,8 @@ 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_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*"