NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
# include "mf_classic_poller_i.h"
# include <nfc/protocols/nfc_poller_base.h>
# include <furi.h>
2024-08-01 22:16:10 -04:00
# include <stream/stream.h>
# include <stream/buffered_file_stream.h>
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
# define TAG "MfClassicPoller"
# define MF_CLASSIC_MAX_BUFF_SIZE (64)
typedef NfcCommand ( * MfClassicPollerReadHandler ) ( MfClassicPoller * instance ) ;
MfClassicPoller * mf_classic_poller_alloc ( Iso14443_3aPoller * iso14443_3a_poller ) {
furi_assert ( iso14443_3a_poller ) ;
MfClassicPoller * instance = malloc ( sizeof ( MfClassicPoller ) ) ;
instance - > iso14443_3a_poller = iso14443_3a_poller ;
instance - > data = mf_classic_alloc ( ) ;
instance - > crypto = crypto1_alloc ( ) ;
instance - > tx_plain_buffer = bit_buffer_alloc ( MF_CLASSIC_MAX_BUFF_SIZE ) ;
instance - > tx_encrypted_buffer = bit_buffer_alloc ( MF_CLASSIC_MAX_BUFF_SIZE ) ;
instance - > rx_plain_buffer = bit_buffer_alloc ( MF_CLASSIC_MAX_BUFF_SIZE ) ;
instance - > rx_encrypted_buffer = bit_buffer_alloc ( MF_CLASSIC_MAX_BUFF_SIZE ) ;
instance - > current_type_check = MfClassicType4k ;
2024-01-12 17:41:19 +09:00
instance - > card_state = MfClassicCardStateLost ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance - > mfc_event . data = & instance - > mfc_event_data ;
instance - > general_event . protocol = NfcProtocolMfClassic ;
instance - > general_event . event_data = & instance - > mfc_event ;
instance - > general_event . instance = instance ;
return instance ;
}
void mf_classic_poller_free ( MfClassicPoller * instance ) {
furi_assert ( instance ) ;
furi_assert ( instance - > data ) ;
furi_assert ( instance - > crypto ) ;
furi_assert ( instance - > tx_plain_buffer ) ;
furi_assert ( instance - > rx_plain_buffer ) ;
furi_assert ( instance - > tx_encrypted_buffer ) ;
furi_assert ( instance - > rx_encrypted_buffer ) ;
mf_classic_free ( instance - > data ) ;
crypto1_free ( instance - > crypto ) ;
bit_buffer_free ( instance - > tx_plain_buffer ) ;
bit_buffer_free ( instance - > rx_plain_buffer ) ;
bit_buffer_free ( instance - > tx_encrypted_buffer ) ;
bit_buffer_free ( instance - > rx_encrypted_buffer ) ;
free ( instance ) ;
}
static NfcCommand mf_classic_poller_handle_data_update ( MfClassicPoller * instance ) {
MfClassicPollerEventDataUpdate * data_update = & instance - > mfc_event_data . data_update ;
mf_classic_get_read_sectors_and_keys (
instance - > data , & data_update - > sectors_read , & data_update - > keys_found ) ;
data_update - > current_sector = instance - > mode_ctx . dict_attack_ctx . current_sector ;
instance - > mfc_event . type = MfClassicPollerEventTypeDataUpdate ;
return instance - > callback ( instance - > general_event , instance - > context ) ;
}
static void mf_classic_poller_check_key_b_is_readable (
MfClassicPoller * instance ,
uint8_t block_num ,
MfClassicBlock * data ) {
do {
if ( ! mf_classic_is_sector_trailer ( block_num ) ) break ;
if ( ! mf_classic_is_allowed_access (
instance - > data , block_num , MfClassicKeyTypeA , MfClassicActionKeyBRead ) )
break ;
MfClassicSectorTrailer * sec_tr = ( MfClassicSectorTrailer * ) data ;
2024-02-14 13:41:42 +09:00
uint64_t key_b = bit_lib_bytes_to_num_be ( sec_tr - > key_b . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
uint8_t sector_num = mf_classic_get_sector_by_block ( block_num ) ;
mf_classic_set_key_found ( instance - > data , sector_num , MfClassicKeyTypeB , key_b ) ;
} while ( false ) ;
}
NfcCommand mf_classic_poller_handler_detect_type ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandReset ;
if ( instance - > current_type_check = = MfClassicType4k ) {
iso14443_3a_copy (
instance - > data - > iso14443_3a_data ,
iso14443_3a_poller_get_data ( instance - > iso14443_3a_poller ) ) ;
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_get_nt ( instance , 254 , MfClassicKeyTypeA , NULL ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error = = MfClassicErrorNone ) {
instance - > data - > type = MfClassicType4k ;
instance - > state = MfClassicPollerStateStart ;
instance - > current_type_check = MfClassicType4k ;
FURI_LOG_D ( TAG , " 4K detected " ) ;
} else {
instance - > current_type_check = MfClassicType1k ;
}
} else if ( instance - > current_type_check = = MfClassicType1k ) {
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_get_nt ( instance , 62 , MfClassicKeyTypeA , NULL ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error = = MfClassicErrorNone ) {
instance - > data - > type = MfClassicType1k ;
FURI_LOG_D ( TAG , " 1K detected " ) ;
} else {
instance - > data - > type = MfClassicTypeMini ;
FURI_LOG_D ( TAG , " Mini detected " ) ;
}
instance - > current_type_check = MfClassicType4k ;
instance - > state = MfClassicPollerStateStart ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_start ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
instance - > sectors_total = mf_classic_get_total_sectors_num ( instance - > data - > type ) ;
memset ( & instance - > mode_ctx , 0 , sizeof ( MfClassicPollerModeContext ) ) ;
instance - > mfc_event . type = MfClassicPollerEventTypeRequestMode ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( instance - > mfc_event_data . poller_mode . mode = = MfClassicPollerModeDictAttack ) {
mf_classic_copy ( instance - > data , instance - > mfc_event_data . poller_mode . data ) ;
instance - > state = MfClassicPollerStateRequestKey ;
} else if ( instance - > mfc_event_data . poller_mode . mode = = MfClassicPollerModeRead ) {
instance - > state = MfClassicPollerStateRequestReadSector ;
} else if ( instance - > mfc_event_data . poller_mode . mode = = MfClassicPollerModeWrite ) {
instance - > state = MfClassicPollerStateRequestSectorTrailer ;
} else {
furi_crash ( " Invalid mode selected " ) ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_request_sector_trailer ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerWriteContext * write_ctx = & instance - > mode_ctx . write_ctx ;
if ( write_ctx - > current_sector = = instance - > sectors_total ) {
instance - > state = MfClassicPollerStateSuccess ;
} else {
instance - > mfc_event . type = MfClassicPollerEventTypeRequestSectorTrailer ;
instance - > mfc_event_data . sec_tr_data . sector_num = write_ctx - > current_sector ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( instance - > mfc_event_data . sec_tr_data . sector_trailer_provided ) {
instance - > state = MfClassicPollerStateCheckWriteConditions ;
memcpy (
& write_ctx - > sec_tr ,
& instance - > mfc_event_data . sec_tr_data . sector_trailer ,
sizeof ( MfClassicSectorTrailer ) ) ;
write_ctx - > current_block =
MAX ( 1 , mf_classic_get_first_block_num_of_sector ( write_ctx - > current_sector ) ) ;
} else {
write_ctx - > current_sector + + ;
}
}
return command ;
}
NfcCommand mf_classic_handler_check_write_conditions ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerWriteContext * write_ctx = & instance - > mode_ctx . write_ctx ;
MfClassicSectorTrailer * sec_tr = & write_ctx - > sec_tr ;
do {
// Check last block in sector to write
uint8_t sec_tr_block_num =
mf_classic_get_sector_trailer_num_by_sector ( write_ctx - > current_sector ) ;
if ( write_ctx - > current_block = = sec_tr_block_num ) {
write_ctx - > current_sector + + ;
instance - > state = MfClassicPollerStateRequestSectorTrailer ;
break ;
}
// Check write and read access
if ( mf_classic_is_allowed_access_data_block (
sec_tr , write_ctx - > current_block , MfClassicKeyTypeA , MfClassicActionDataWrite ) ) {
write_ctx - > key_type_write = MfClassicKeyTypeA ;
} else if ( mf_classic_is_allowed_access_data_block (
sec_tr ,
write_ctx - > current_block ,
MfClassicKeyTypeB ,
MfClassicActionDataWrite ) ) {
write_ctx - > key_type_write = MfClassicKeyTypeB ;
} else if ( mf_classic_is_value_block ( sec_tr , write_ctx - > current_block ) ) {
write_ctx - > is_value_block = true ;
} else {
FURI_LOG_D ( TAG , " Not allowed to write block %d " , write_ctx - > current_block ) ;
write_ctx - > current_block + + ;
break ;
}
if ( mf_classic_is_allowed_access_data_block (
sec_tr ,
write_ctx - > current_block ,
write_ctx - > key_type_write ,
MfClassicActionDataRead ) ) {
write_ctx - > key_type_read = write_ctx - > key_type_write ;
} else {
write_ctx - > key_type_read = write_ctx - > key_type_write = = MfClassicKeyTypeA ?
MfClassicKeyTypeB :
MfClassicKeyTypeA ;
if ( ! mf_classic_is_allowed_access_data_block (
sec_tr ,
write_ctx - > current_block ,
write_ctx - > key_type_read ,
MfClassicActionDataRead ) ) {
FURI_LOG_D ( TAG , " Not allowed to read block %d " , write_ctx - > current_block ) ;
write_ctx - > current_block + + ;
break ;
}
}
write_ctx - > need_halt_before_write =
( write_ctx - > key_type_read ! = write_ctx - > key_type_write ) ;
instance - > state = MfClassicPollerStateReadBlock ;
} while ( false ) ;
return command ;
}
NfcCommand mf_classic_poller_handler_read_block ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerWriteContext * write_ctx = & instance - > mode_ctx . write_ctx ;
MfClassicKey * auth_key = write_ctx - > key_type_read = = MfClassicKeyTypeA ?
& write_ctx - > sec_tr . key_a :
& write_ctx - > sec_tr . key_b ;
MfClassicError error = MfClassicErrorNone ;
do {
// Authenticate to sector
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , write_ctx - > current_block , auth_key , write_ctx - > key_type_read , NULL ) ;
if ( error ! = MfClassicErrorNone ) {
FURI_LOG_D ( TAG , " Failed to auth to block %d " , write_ctx - > current_block ) ;
instance - > state = MfClassicPollerStateFail ;
break ;
}
// Read block from tag
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_read_block (
instance , write_ctx - > current_block , & write_ctx - > tag_block ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) {
FURI_LOG_D ( TAG , " Failed to read block %d " , write_ctx - > current_block ) ;
instance - > state = MfClassicPollerStateFail ;
break ;
}
if ( write_ctx - > is_value_block ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance - > state = MfClassicPollerStateWriteValueBlock ;
} else {
if ( write_ctx - > need_halt_before_write ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
}
instance - > state = MfClassicPollerStateWriteBlock ;
}
} while ( false ) ;
return command ;
}
NfcCommand mf_classic_poller_handler_write_block ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerWriteContext * write_ctx = & instance - > mode_ctx . write_ctx ;
MfClassicKey * auth_key = write_ctx - > key_type_write = = MfClassicKeyTypeA ?
& write_ctx - > sec_tr . key_a :
& write_ctx - > sec_tr . key_b ;
MfClassicError error = MfClassicErrorNone ;
do {
// Request block to write
instance - > mfc_event . type = MfClassicPollerEventTypeRequestWriteBlock ;
instance - > mfc_event_data . write_block_data . block_num = write_ctx - > current_block ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( ! instance - > mfc_event_data . write_block_data . write_block_provided ) break ;
// Compare tag and saved block
if ( memcmp (
write_ctx - > tag_block . data ,
instance - > mfc_event_data . write_block_data . write_block . data ,
sizeof ( MfClassicBlock ) ) = = 0 ) {
FURI_LOG_D ( TAG , " Block %d is equal. Skip writing " , write_ctx - > current_block ) ;
break ;
}
// Reauth if necessary
if ( write_ctx - > need_halt_before_write ) {
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , write_ctx - > current_block , auth_key , write_ctx - > key_type_write , NULL ) ;
if ( error ! = MfClassicErrorNone ) {
FURI_LOG_D (
TAG , " Failed to auth to block %d for writing " , write_ctx - > current_block ) ;
instance - > state = MfClassicPollerStateFail ;
break ;
}
}
// Write block
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_write_block (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance ,
write_ctx - > current_block ,
& instance - > mfc_event_data . write_block_data . write_block ) ;
if ( error ! = MfClassicErrorNone ) {
FURI_LOG_D ( TAG , " Failed to write block %d " , write_ctx - > current_block ) ;
instance - > state = MfClassicPollerStateFail ;
break ;
}
} while ( false ) ;
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
write_ctx - > current_block + + ;
instance - > state = MfClassicPollerStateCheckWriteConditions ;
return command ;
}
NfcCommand mf_classic_poller_handler_write_value_block ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerWriteContext * write_ctx = & instance - > mode_ctx . write_ctx ;
do {
// Request block to write
instance - > mfc_event . type = MfClassicPollerEventTypeRequestWriteBlock ;
instance - > mfc_event_data . write_block_data . block_num = write_ctx - > current_block ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( ! instance - > mfc_event_data . write_block_data . write_block_provided ) break ;
// Compare tag and saved block
if ( memcmp (
write_ctx - > tag_block . data ,
instance - > mfc_event_data . write_block_data . write_block . data ,
sizeof ( MfClassicBlock ) ) = = 0 ) {
FURI_LOG_D ( TAG , " Block %d is equal. Skip writing " , write_ctx - > current_block ) ;
break ;
}
bool key_a_inc_allowed = mf_classic_is_allowed_access_data_block (
& write_ctx - > sec_tr ,
write_ctx - > current_block ,
MfClassicKeyTypeA ,
MfClassicActionDataInc ) ;
bool key_b_inc_allowed = mf_classic_is_allowed_access_data_block (
& write_ctx - > sec_tr ,
write_ctx - > current_block ,
MfClassicKeyTypeB ,
MfClassicActionDataInc ) ;
bool key_a_dec_allowed = mf_classic_is_allowed_access_data_block (
& write_ctx - > sec_tr ,
write_ctx - > current_block ,
MfClassicKeyTypeA ,
MfClassicActionDataDec ) ;
bool key_b_dec_allowed = mf_classic_is_allowed_access_data_block (
& write_ctx - > sec_tr ,
write_ctx - > current_block ,
MfClassicKeyTypeB ,
MfClassicActionDataDec ) ;
int32_t source_value = 0 ;
int32_t target_value = 0 ;
if ( ! mf_classic_block_to_value (
& instance - > mfc_event_data . write_block_data . write_block , & source_value , NULL ) )
break ;
if ( ! mf_classic_block_to_value ( & write_ctx - > tag_block , & target_value , NULL ) ) break ;
MfClassicKeyType auth_key_type = MfClassicKeyTypeA ;
MfClassicValueCommand value_cmd = MfClassicValueCommandIncrement ;
int32_t diff = source_value - target_value ;
if ( diff > 0 ) {
if ( key_a_inc_allowed ) {
auth_key_type = MfClassicKeyTypeA ;
value_cmd = MfClassicValueCommandIncrement ;
} else if ( key_b_inc_allowed ) {
auth_key_type = MfClassicKeyTypeB ;
value_cmd = MfClassicValueCommandIncrement ;
} else {
FURI_LOG_D ( TAG , " Unable to increment value block " ) ;
break ;
}
} else {
if ( key_a_dec_allowed ) {
auth_key_type = MfClassicKeyTypeA ;
value_cmd = MfClassicValueCommandDecrement ;
diff * = - 1 ;
} else if ( key_b_dec_allowed ) {
auth_key_type = MfClassicKeyTypeB ;
value_cmd = MfClassicValueCommandDecrement ;
diff * = - 1 ;
} else {
FURI_LOG_D ( TAG , " Unable to decrement value block " ) ;
break ;
}
}
MfClassicKey * key = ( auth_key_type = = MfClassicKeyTypeA ) ? & write_ctx - > sec_tr . key_a :
& write_ctx - > sec_tr . key_b ;
MfClassicError error =
2023-11-15 12:32:45 +04:00
mf_classic_poller_auth ( instance , write_ctx - > current_block , key , auth_key_type , NULL ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) break ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_value_cmd ( instance , write_ctx - > current_block , value_cmd , diff ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) break ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_value_transfer ( instance , write_ctx - > current_block ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) break ;
} while ( false ) ;
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
write_ctx - > is_value_block = false ;
write_ctx - > current_block + + ;
instance - > state = MfClassicPollerStateCheckWriteConditions ;
return command ;
}
NfcCommand mf_classic_poller_handler_request_read_sector ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerReadContext * sec_read_ctx = & instance - > mode_ctx . read_ctx ;
MfClassicPollerEventDataReadSectorRequest * sec_read =
& instance - > mfc_event_data . read_sector_request_data ;
instance - > mfc_event . type = MfClassicPollerEventTypeRequestReadSector ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( ! sec_read - > key_provided ) {
instance - > state = MfClassicPollerStateSuccess ;
} else {
sec_read_ctx - > current_sector = sec_read - > sector_num ;
sec_read_ctx - > key = sec_read - > key ;
sec_read_ctx - > key_type = sec_read - > key_type ;
sec_read_ctx - > current_block =
mf_classic_get_first_block_num_of_sector ( sec_read - > sector_num ) ;
sec_read_ctx - > auth_passed = false ;
instance - > state = MfClassicPollerStateReadSectorBlocks ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_request_read_sector_blocks ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerReadContext * sec_read_ctx = & instance - > mode_ctx . read_ctx ;
do {
MfClassicError error = MfClassicErrorNone ;
if ( ! sec_read_ctx - > auth_passed ) {
2024-02-14 13:41:42 +09:00
uint64_t key = bit_lib_bytes_to_num_be ( sec_read_ctx - > key . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
FURI_LOG_D (
TAG ,
" Auth to block %d with key %c: %06llx " ,
sec_read_ctx - > current_block ,
sec_read_ctx - > key_type = = MfClassicKeyTypeA ? ' A ' : ' B ' ,
key ) ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance ,
sec_read_ctx - > current_block ,
& sec_read_ctx - > key ,
sec_read_ctx - > key_type ,
NULL ) ;
if ( error ! = MfClassicErrorNone ) break ;
sec_read_ctx - > auth_passed = true ;
if ( ! mf_classic_is_key_found (
instance - > data , sec_read_ctx - > current_sector , sec_read_ctx - > key_type ) ) {
mf_classic_set_key_found (
instance - > data , sec_read_ctx - > current_sector , sec_read_ctx - > key_type , key ) ;
}
}
if ( mf_classic_is_block_read ( instance - > data , sec_read_ctx - > current_block ) ) break ;
FURI_LOG_D ( TAG , " Reading block %d " , sec_read_ctx - > current_block ) ;
MfClassicBlock read_block = { } ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_read_block ( instance , sec_read_ctx - > current_block , & read_block ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error = = MfClassicErrorNone ) {
mf_classic_set_block_read ( instance - > data , sec_read_ctx - > current_block , & read_block ) ;
if ( sec_read_ctx - > key_type = = MfClassicKeyTypeA ) {
mf_classic_poller_check_key_b_is_readable (
instance , sec_read_ctx - > current_block , & read_block ) ;
}
} else {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
sec_read_ctx - > auth_passed = false ;
}
} while ( false ) ;
uint8_t sec_tr_num = mf_classic_get_sector_trailer_num_by_sector ( sec_read_ctx - > current_sector ) ;
sec_read_ctx - > current_block + + ;
if ( sec_read_ctx - > current_block > sec_tr_num ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance - > state = MfClassicPollerStateRequestReadSector ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_request_key ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
instance - > mfc_event . type = MfClassicPollerEventTypeRequestKey ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
if ( instance - > mfc_event_data . key_request_data . key_provided ) {
dict_attack_ctx - > current_key = instance - > mfc_event_data . key_request_data . key ;
instance - > state = MfClassicPollerStateAuthKeyA ;
} else {
instance - > state = MfClassicPollerStateNextSector ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_auth_a ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
if ( mf_classic_is_key_found (
instance - > data , dict_attack_ctx - > current_sector , MfClassicKeyTypeA ) ) {
instance - > state = MfClassicPollerStateAuthKeyB ;
} else {
uint8_t block = mf_classic_get_first_block_num_of_sector ( dict_attack_ctx - > current_sector ) ;
2024-02-14 13:41:42 +09:00
uint64_t key =
bit_lib_bytes_to_num_be ( dict_attack_ctx - > current_key . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
FURI_LOG_D ( TAG , " Auth to block %d with key A: %06llx " , block , key ) ;
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , block , & dict_attack_ctx - > current_key , MfClassicKeyTypeA , NULL ) ;
if ( error = = MfClassicErrorNone ) {
FURI_LOG_I ( TAG , " Key A found " ) ;
mf_classic_set_key_found (
instance - > data , dict_attack_ctx - > current_sector , MfClassicKeyTypeA , key ) ;
command = mf_classic_poller_handle_data_update ( instance ) ;
dict_attack_ctx - > current_key_type = MfClassicKeyTypeA ;
dict_attack_ctx - > current_block = block ;
dict_attack_ctx - > auth_passed = true ;
instance - > state = MfClassicPollerStateReadSector ;
} else {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance - > state = MfClassicPollerStateAuthKeyB ;
}
}
return command ;
}
NfcCommand mf_classic_poller_handler_auth_b ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
if ( mf_classic_is_key_found (
instance - > data , dict_attack_ctx - > current_sector , MfClassicKeyTypeB ) ) {
if ( mf_classic_is_key_found (
instance - > data , dict_attack_ctx - > current_sector , MfClassicKeyTypeA ) ) {
instance - > state = MfClassicPollerStateNextSector ;
} else {
instance - > state = MfClassicPollerStateRequestKey ;
}
} else {
uint8_t block = mf_classic_get_first_block_num_of_sector ( dict_attack_ctx - > current_sector ) ;
2024-02-14 13:41:42 +09:00
uint64_t key =
bit_lib_bytes_to_num_be ( dict_attack_ctx - > current_key . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
FURI_LOG_D ( TAG , " Auth to block %d with key B: %06llx " , block , key ) ;
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , block , & dict_attack_ctx - > current_key , MfClassicKeyTypeB , NULL ) ;
if ( error = = MfClassicErrorNone ) {
FURI_LOG_I ( TAG , " Key B found " ) ;
mf_classic_set_key_found (
instance - > data , dict_attack_ctx - > current_sector , MfClassicKeyTypeB , key ) ;
command = mf_classic_poller_handle_data_update ( instance ) ;
dict_attack_ctx - > current_key_type = MfClassicKeyTypeB ;
dict_attack_ctx - > current_block = block ;
dict_attack_ctx - > auth_passed = true ;
instance - > state = MfClassicPollerStateReadSector ;
} else {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance - > state = MfClassicPollerStateRequestKey ;
}
}
return command ;
}
NfcCommand mf_classic_poller_handler_next_sector ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
dict_attack_ctx - > current_sector + + ;
if ( dict_attack_ctx - > current_sector = = instance - > sectors_total ) {
instance - > state = MfClassicPollerStateSuccess ;
} else {
instance - > mfc_event . type = MfClassicPollerEventTypeNextSector ;
instance - > mfc_event_data . next_sector_data . current_sector = dict_attack_ctx - > current_sector ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
instance - > state = MfClassicPollerStateRequestKey ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_read_sector ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
MfClassicError error = MfClassicErrorNone ;
uint8_t block_num = dict_attack_ctx - > current_block ;
MfClassicBlock block = { } ;
do {
if ( mf_classic_is_block_read ( instance - > data , block_num ) ) break ;
if ( ! dict_attack_ctx - > auth_passed ) {
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance ,
block_num ,
& dict_attack_ctx - > current_key ,
dict_attack_ctx - > current_key_type ,
NULL ) ;
if ( error ! = MfClassicErrorNone ) {
instance - > state = MfClassicPollerStateNextSector ;
FURI_LOG_W ( TAG , " Failed to re-auth. Go to next sector " ) ;
break ;
}
}
FURI_LOG_D ( TAG , " Reading block %d " , block_num ) ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_read_block ( instance , block_num , & block ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
FURI_LOG_D ( TAG , " Failed to read block %d " , block_num ) ;
} else {
mf_classic_set_block_read ( instance - > data , block_num , & block ) ;
if ( dict_attack_ctx - > current_key_type = = MfClassicKeyTypeA ) {
mf_classic_poller_check_key_b_is_readable ( instance , block_num , & block ) ;
}
}
} while ( false ) ;
uint8_t sec_tr_block_num =
mf_classic_get_sector_trailer_num_by_sector ( dict_attack_ctx - > current_sector ) ;
dict_attack_ctx - > current_block + + ;
if ( dict_attack_ctx - > current_block > sec_tr_block_num ) {
mf_classic_poller_handle_data_update ( instance ) ;
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
if ( dict_attack_ctx - > current_sector = = instance - > sectors_total ) {
instance - > state = MfClassicPollerStateNextSector ;
} else {
dict_attack_ctx - > reuse_key_sector = dict_attack_ctx - > current_sector ;
instance - > mfc_event . type = MfClassicPollerEventTypeKeyAttackStart ;
instance - > mfc_event_data . key_attack_data . current_sector =
dict_attack_ctx - > reuse_key_sector ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
instance - > state = MfClassicPollerStateKeyReuseStart ;
}
}
return command ;
}
NfcCommand mf_classic_poller_handler_key_reuse_start ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
2024-08-01 09:10:02 -04:00
do {
if ( ! dict_attack_ctx - > prng_type ) {
instance - > state = MfClassicPollerStateNestedAnalyzePRNG ;
break ;
}
if ( dict_attack_ctx - > current_key_type = = MfClassicKeyTypeA ) {
dict_attack_ctx - > current_key_type = MfClassicKeyTypeB ;
instance - > state = MfClassicPollerStateKeyReuseAuthKeyB ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
} else {
2024-08-01 09:10:02 -04:00
dict_attack_ctx - > reuse_key_sector + + ;
if ( dict_attack_ctx - > reuse_key_sector = = instance - > sectors_total ) {
instance - > mfc_event . type = MfClassicPollerEventTypeKeyAttackStop ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
instance - > state = MfClassicPollerStateRequestKey ;
} else {
instance - > mfc_event . type = MfClassicPollerEventTypeKeyAttackStart ;
instance - > mfc_event_data . key_attack_data . current_sector =
dict_attack_ctx - > reuse_key_sector ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
2024-08-01 09:10:02 -04:00
dict_attack_ctx - > current_key_type = MfClassicKeyTypeA ;
instance - > state = MfClassicPollerStateKeyReuseAuthKeyA ;
}
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
}
2024-08-01 09:10:02 -04:00
} while ( false ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
return command ;
}
NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
if ( mf_classic_is_key_found (
instance - > data , dict_attack_ctx - > reuse_key_sector , MfClassicKeyTypeA ) ) {
instance - > state = MfClassicPollerStateKeyReuseStart ;
} else {
uint8_t block =
mf_classic_get_first_block_num_of_sector ( dict_attack_ctx - > reuse_key_sector ) ;
2024-02-14 13:41:42 +09:00
uint64_t key =
bit_lib_bytes_to_num_be ( dict_attack_ctx - > current_key . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
FURI_LOG_D ( TAG , " Key attack auth to block %d with key A: %06llx " , block , key ) ;
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , block , & dict_attack_ctx - > current_key , MfClassicKeyTypeA , NULL ) ;
if ( error = = MfClassicErrorNone ) {
FURI_LOG_I ( TAG , " Key A found " ) ;
mf_classic_set_key_found (
instance - > data , dict_attack_ctx - > reuse_key_sector , MfClassicKeyTypeA , key ) ;
command = mf_classic_poller_handle_data_update ( instance ) ;
dict_attack_ctx - > current_key_type = MfClassicKeyTypeA ;
dict_attack_ctx - > current_block = block ;
dict_attack_ctx - > auth_passed = true ;
instance - > state = MfClassicPollerStateKeyReuseReadSector ;
} else {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
instance - > state = MfClassicPollerStateKeyReuseStart ;
}
}
return command ;
}
NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
if ( mf_classic_is_key_found (
instance - > data , dict_attack_ctx - > reuse_key_sector , MfClassicKeyTypeB ) ) {
instance - > state = MfClassicPollerStateKeyReuseStart ;
} else {
uint8_t block =
mf_classic_get_first_block_num_of_sector ( dict_attack_ctx - > reuse_key_sector ) ;
2024-02-14 13:41:42 +09:00
uint64_t key =
bit_lib_bytes_to_num_be ( dict_attack_ctx - > current_key . data , sizeof ( MfClassicKey ) ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
FURI_LOG_D ( TAG , " Key attack auth to block %d with key B: %06llx " , block , key ) ;
2023-11-15 12:32:45 +04:00
MfClassicError error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance , block , & dict_attack_ctx - > current_key , MfClassicKeyTypeB , NULL ) ;
if ( error = = MfClassicErrorNone ) {
FURI_LOG_I ( TAG , " Key B found " ) ;
mf_classic_set_key_found (
instance - > data , dict_attack_ctx - > reuse_key_sector , MfClassicKeyTypeB , key ) ;
command = mf_classic_poller_handle_data_update ( instance ) ;
dict_attack_ctx - > current_key_type = MfClassicKeyTypeB ;
dict_attack_ctx - > current_block = block ;
dict_attack_ctx - > auth_passed = true ;
instance - > state = MfClassicPollerStateKeyReuseReadSector ;
} else {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
instance - > state = MfClassicPollerStateKeyReuseStart ;
}
}
return command ;
}
NfcCommand mf_classic_poller_handler_key_reuse_read_sector ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
MfClassicError error = MfClassicErrorNone ;
uint8_t block_num = dict_attack_ctx - > current_block ;
MfClassicBlock block = { } ;
do {
if ( mf_classic_is_block_read ( instance - > data , block_num ) ) break ;
if ( ! dict_attack_ctx - > auth_passed ) {
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_auth (
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
instance ,
block_num ,
& dict_attack_ctx - > current_key ,
dict_attack_ctx - > current_key_type ,
NULL ) ;
if ( error ! = MfClassicErrorNone ) {
instance - > state = MfClassicPollerStateKeyReuseStart ;
break ;
}
}
FURI_LOG_D ( TAG , " Reading block %d " , block_num ) ;
2023-11-15 12:32:45 +04:00
error = mf_classic_poller_read_block ( instance , block_num , & block ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
if ( error ! = MfClassicErrorNone ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
FURI_LOG_D ( TAG , " Failed to read block %d " , block_num ) ;
} else {
mf_classic_set_block_read ( instance - > data , block_num , & block ) ;
if ( dict_attack_ctx - > current_key_type = = MfClassicKeyTypeA ) {
mf_classic_poller_check_key_b_is_readable ( instance , block_num , & block ) ;
}
}
} while ( false ) ;
uint16_t sec_tr_block_num =
mf_classic_get_sector_trailer_num_by_sector ( dict_attack_ctx - > reuse_key_sector ) ;
dict_attack_ctx - > current_block + + ;
if ( dict_attack_ctx - > current_block > sec_tr_block_num ) {
2023-11-15 12:32:45 +04:00
mf_classic_poller_halt ( instance ) ;
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
dict_attack_ctx - > auth_passed = false ;
mf_classic_poller_handle_data_update ( instance ) ;
instance - > state = MfClassicPollerStateKeyReuseStart ;
}
return command ;
}
2024-08-01 09:10:02 -04:00
void nonce_distance ( uint32_t * msb , uint32_t * lsb ) {
uint16_t x = 1 , pos ;
uint8_t calc_ok = 0 ;
for ( uint16_t i = 1 ; i ; + + i ) {
pos = ( x & 0xff ) < < 8 | x > > 8 ;
if ( ( pos = = * msb ) & ! ( calc_ok > > 0 & 0x01 ) ) {
* msb = i ;
calc_ok | = 0x01 ;
}
if ( ( pos = = * lsb ) & ! ( calc_ok > > 1 & 0x01 ) ) {
* lsb = i ;
calc_ok | = 0x02 ;
}
if ( calc_ok = = 0x03 ) {
return ;
}
x = x > > 1 | ( x ^ x > > 2 ^ x > > 3 ^ x > > 5 ) < < 15 ;
}
}
// TODO: Faster? https://github.com/RfidResearchGroup/proxmark3/commit/bd3e8db852186d4ab9d5dda890d1cd52389b1254
bool validate_prng_nonce ( uint32_t nonce ) {
uint32_t msb = nonce > > 16 ;
uint32_t lsb = nonce & 0xffff ;
nonce_distance ( & msb , & lsb ) ;
return ( ( 65535 - msb + lsb ) % 65535 ) = = 16 ;
}
2024-08-01 22:16:10 -04:00
// Return 1 if the nonce is invalid else return 0
2024-08-02 08:15:53 -04:00
/*
2024-08-01 22:16:10 -04:00
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 ;
}
2024-08-02 08:15:53 -04:00
*/
2024-08-01 22:16:10 -04:00
2024-08-01 09:10:02 -04:00
// Helper function to add a nonce to the array
static bool add_nested_nonce ( MfClassicNestedNonceArray * array , uint32_t cuid , uint8_t key_idx , uint32_t nt , uint32_t nt_enc , uint8_t par , uint16_t dist ) {
MfClassicNestedNonce * new_nonces = realloc ( array - > nonces , ( array - > count + 1 ) * sizeof ( MfClassicNestedNonce ) ) ;
if ( new_nonces = = NULL ) return false ;
array - > nonces = new_nonces ;
array - > nonces [ array - > count ] . cuid = cuid ;
array - > nonces [ array - > count ] . key_idx = key_idx ;
array - > nonces [ array - > count ] . nt = nt ;
array - > nonces [ array - > count ] . nt_enc = nt_enc ;
array - > nonces [ array - > count ] . par = par ;
array - > nonces [ array - > count ] . dist = dist ;
array - > count + + ;
return true ;
}
NfcCommand mf_classic_poller_handler_nested_analyze_prng ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
// Analyze PRNG by collecting nt
uint8_t nonce_limit = 10 ;
if ( dict_attack_ctx - > nt_count > 0 ) {
if ( ! validate_prng_nonce ( dict_attack_ctx - > nt_prev ) ) dict_attack_ctx - > hard_nt_count + + ;
}
if ( dict_attack_ctx - > nt_count < = nonce_limit ) {
instance - > state = MfClassicPollerStateNestedCollectNt ;
return command ;
}
if ( dict_attack_ctx - > hard_nt_count > 3 ) {
dict_attack_ctx - > prng_type = MfClassicPrngTypeHard ;
// FIXME: E -> D
FURI_LOG_E ( TAG , " Detected Hard PRNG " ) ;
} else {
dict_attack_ctx - > prng_type = MfClassicPrngTypeWeak ;
// FIXME: E -> D
FURI_LOG_E ( TAG , " Detected Weak PRNG " ) ;
}
instance - > state = MfClassicPollerStateNestedController ;
return command ;
}
NfcCommand mf_classic_poller_handler_nested_analyze_backdoor ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
2024-08-01 22:16:10 -04:00
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
// TODO: Check for Fudan backdoor
dict_attack_ctx - > backdoor = MfClassicBackdoorNone ;
2024-08-01 09:10:02 -04:00
return command ;
}
NfcCommand mf_classic_poller_handler_nested_collect_nt ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandReset ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
MfClassicNt nt = { } ;
MfClassicError error = mf_classic_poller_get_nt ( instance , 0 , MfClassicKeyTypeA , & nt ) ;
if ( error ! = MfClassicErrorNone ) {
instance - > state = MfClassicPollerStateKeyReuseStart ;
dict_attack_ctx - > prng_type = MfClassicPrngTypeNoTag ;
// FIXME: E -> D
FURI_LOG_E ( TAG , " Failed to collect nt " ) ;
} else {
// FIXME: E -> D
FURI_LOG_E ( TAG , " nt: %02x%02x%02x%02x " , nt . data [ 0 ] , nt . data [ 1 ] , nt . data [ 2 ] , nt . data [ 3 ] ) ;
uint32_t nt_data = bit_lib_bytes_to_num_be ( nt . data , sizeof ( MfClassicNt ) ) ;
dict_attack_ctx - > nt_prev = nt_data ;
dict_attack_ctx - > nt_count + + ;
instance - > state = MfClassicPollerStateNestedAnalyzePRNG ;
}
return command ;
}
NfcCommand mf_classic_poller_handler_nested_collect_nt_enc ( MfClassicPoller * instance ) {
// TODO: Collect parity
2024-08-01 22:16:10 -04:00
// TODO: FURI_CRITICAL_ENTER
// xTickCount
// Modify targets/f7/furi_hal/furi_hal_rtc.c to expose sub-second time (https://stackoverflow.com/questions/55534873/how-to-setup-the-stm32f4-real-time-clockrtc-to-get-valid-values-in-the-sub-sec)
// furi_hal_rtc_get_timestamp isn't precise enough
// TODO: Measure ticks with https://github.com/flipperdevices/flipperzero-firmware/blob/bec6bd381f222cf14658fd862a2c7f6e620bbf00/targets/f7/furi_hal/furi_hal_idle_timer.h#L51
/*
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 ) ;
( . . )
*/
2024-08-01 09:10:02 -04:00
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
MfClassicNestedNonceArray result = { NULL , 0 } ;
2024-08-02 07:04:43 -04:00
// TODO: Target sector, key A/B
2024-08-01 09:10:02 -04:00
do {
if ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeHard ) {
FURI_LOG_E ( TAG , " Hard PRNG, skipping calibration " ) ;
// TODO: Collect hardnested nonces (cuid, sec, par, nt_enc, A/B)
// https://github.com/AloneLiberty/FlipperNested/blob/eba6163d7ef22adef5f9fe4d77a78ccfcc27a952/lib/nested/nested.c#L564-L645
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 ) ;
MfClassicAuthContext auth_ctx = { } ;
MfClassicError error ;
2024-08-02 08:15:53 -04:00
const uint32_t rounds = 11 ;
2024-08-01 09:10:02 -04:00
uint32_t nt_enc_arr [ rounds ] ;
uint32_t nt_prev = 0 ;
uint32_t nt_enc_prev = 0 ;
uint32_t same_nt_enc_cnt = 0 ;
bool static_encrypted = false ;
2024-08-01 22:16:10 -04:00
// Store last timestamp
2024-08-01 09:10:02 -04:00
// Step 1: Perform full authentication once
error = mf_classic_poller_auth (
instance ,
block ,
& dict_attack_ctx - > current_key ,
dict_attack_ctx - > current_key_type ,
& auth_ctx ) ;
if ( error ! = MfClassicErrorNone ) {
FURI_LOG_E ( TAG , " Failed to perform full authentication " ) ;
break ;
}
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 multiple times
for ( uint32_t round_no = 0 ; round_no < rounds ; round_no + + ) {
2024-08-01 22:16:10 -04:00
error = mf_classic_poller_auth_nested (
instance ,
block ,
& dict_attack_ctx - > current_key ,
dict_attack_ctx - > current_key_type ,
& auth_ctx ) ;
2024-08-01 09:10:02 -04:00
2024-08-01 22:16:10 -04:00
if ( error ! = MfClassicErrorNone ) {
2024-08-01 09:10:02 -04:00
FURI_LOG_E ( TAG , " Failed to perform nested authentication %lu " , round_no ) ;
continue ;
}
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 ;
2024-08-01 22:16:10 -04:00
break ;
}
2024-08-01 09:10:02 -04:00
} else {
same_nt_enc_cnt = 0 ;
nt_enc_prev = nt_enc ;
}
nt_enc_arr [ round_no ] = nt_enc ;
}
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
2024-08-02 07:04:43 -04:00
bool success = add_nested_nonce ( & result , cuid , dict_attack_ctx - > reuse_key_sector , nt_prev , nt_enc_prev , 0 , 65535 ) ;
2024-08-01 09:10:02 -04:00
if ( ! success ) {
FURI_LOG_E ( TAG , " Failed to add nested nonce to array. OOM? " ) ;
}
break ;
}
}
// Find the distance between each nonce
// TODO: Distance calculation
uint64_t known_key = bit_lib_bytes_to_num_be ( dict_attack_ctx - > current_key . data , 6 ) ;
Crypto1 crypto ;
crypto1_init ( & crypto , known_key ) ;
2024-08-02 08:15:53 -04:00
// Skip the first round (typically an outlier)
for ( uint32_t rtr = 1 ; rtr < rounds ; rtr + + ) {
2024-08-01 09:10:02 -04:00
bool found = false ;
for ( int i = 0 ; i < 65535 ; i + + ) {
Crypto1 crypto_temp = { . odd = crypto . odd , . even = crypto . even } ;
uint32_t nth_successor = prng_successor ( nt_prev , i ) ;
if ( ( nth_successor ^ crypto1_word ( & crypto_temp , cuid ^ nth_successor , 0 ) ) = = nt_enc_arr [ rtr ] ) {
FURI_LOG_E ( TAG , " nt_enc (plain) %08lx " , nth_successor ) ;
FURI_LOG_E ( TAG , " dist from nt prev: %i " , i ) ;
2024-08-02 08:15:53 -04:00
if ( i > dict_attack_ctx - > d_max ) {
dict_attack_ctx - > d_max = i ;
}
if ( i < dict_attack_ctx - > d_min ) {
dict_attack_ctx - > d_min = i ;
}
2024-08-01 09:10:02 -04:00
nt_prev = nth_successor ;
found = true ;
break ;
}
}
if ( ! found ) {
FURI_LOG_E ( TAG , " Failed to find distance for nt_enc %08lx " , nt_enc_arr [ rtr ] ) ;
FURI_LOG_E ( TAG , " using key %06llx and uid %08lx, nt_prev is %08lx " , known_key , cuid , nt_prev ) ;
}
}
2024-08-02 08:15:53 -04:00
bool is_static = ( dict_attack_ctx - > d_min = = dict_attack_ctx - > d_max ) ;
2024-08-01 09:10:02 -04:00
FURI_LOG_E (
TAG ,
2024-08-02 08:15:53 -04:00
" Calibration completed: min=%u max=%u static: %s " ,
dict_attack_ctx - > d_min ,
dict_attack_ctx - > d_max ,
is_static ? " true " : " false " ) ;
//printf("ks: %08x\n", nth_successor ^ nt_enc);
2024-08-01 09:10:02 -04:00
} while ( false ) ;
instance - > state = MfClassicPollerStateNestedController ;
mf_classic_poller_halt ( instance ) ;
return command ;
}
2024-08-02 07:04:43 -04:00
NfcCommand mf_classic_poller_handler_nested_dict_attack ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
2024-08-02 08:15:53 -04:00
//MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx;
2024-08-02 07:04:43 -04:00
// TODO: Nested dictionary attack with ks1
instance - > state = MfClassicPollerStateNestedLog ;
return command ;
}
2024-08-01 09:10:02 -04:00
NfcCommand mf_classic_poller_handler_nested_log ( MfClassicPoller * instance ) {
2024-08-01 22:16:10 -04:00
furi_assert ( instance - > mode_ctx . dict_attack_ctx . nested_nonce . count > 0 ) ;
furi_assert ( instance - > mode_ctx . dict_attack_ctx . nested_nonce . nonces ) ;
2024-08-01 09:10:02 -04:00
NfcCommand command = NfcCommandContinue ;
2024-08-01 22:16:10 -04:00
bool params_saved = false ;
2024-08-01 09:10:02 -04:00
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
2024-08-01 22:16:10 -04:00
Storage * storage = furi_record_open ( RECORD_STORAGE ) ;
Stream * stream = buffered_file_stream_alloc ( storage ) ;
FuriString * temp_str = furi_string_alloc ( ) ;
do {
if ( ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeWeak ) & & ( dict_attack_ctx - > nested_nonce . count ! = 2 ) ) {
2024-08-02 08:15:53 -04:00
FURI_LOG_E ( TAG , " MfClassicPollerStateNestedLog expected 2 nonces, received %u " , dict_attack_ctx - > nested_nonce . count ) ;
2024-08-01 22:16:10 -04:00
break ;
}
if ( ! buffered_file_stream_open ( stream , MF_CLASSIC_NESTED_LOGS_FILE_PATH , FSAM_WRITE , FSOM_OPEN_APPEND ) ) break ;
bool params_write_success = true ;
for ( size_t i = 0 ; i < dict_attack_ctx - > nested_nonce . count ; i + + ) {
MfClassicNestedNonce * nonce = & dict_attack_ctx - > nested_nonce . nonces [ i ] ;
furi_string_printf ( temp_str , " Sec %d key %c cuid %08lx " , ( nonce - > key_idx / 2 ) , ( nonce - > key_idx % 2 = = 0 ) ? ' A ' : ' B ' , nonce - > cuid ) ;
for ( uint8_t nt_idx = 0 ; nt_idx < ( ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeWeak ) ? 2 : 1 ) ; nt_idx + + ) {
furi_string_cat_printf (
temp_str ,
" nt%u %08lx ks%u %08lx par%u " ,
nt_idx ,
nonce - > nt ,
nt_idx ,
nonce - > nt_enc ^ nonce - > nt ,
nt_idx ) ;
for ( uint8_t pb = 0 ; pb < 4 ; pb + + ) {
furi_string_cat_printf ( temp_str , " %u " , ( nonce - > par > > ( 3 - pb ) ) & 1 ) ;
}
}
if ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeWeak ) {
furi_string_cat_printf ( temp_str , " dist %u \n " , nonce - > dist ) ;
} else {
furi_string_cat_printf ( temp_str , " \n " ) ;
}
if ( ! stream_write_string ( stream , temp_str ) ) {
params_write_success = false ;
break ;
}
}
if ( ! params_write_success ) break ;
params_saved = true ;
} while ( false ) ;
furi_assert ( params_saved ) ;
2024-08-01 09:10:02 -04:00
free ( dict_attack_ctx - > nested_nonce . nonces ) ;
2024-08-01 22:16:10 -04:00
dict_attack_ctx - > nested_nonce . count = 0 ;
furi_string_free ( temp_str ) ;
buffered_file_stream_close ( stream ) ;
stream_free ( stream ) ;
furi_record_close ( RECORD_STORAGE ) ;
instance - > state = MfClassicPollerStateNestedController ;
2024-08-01 09:10:02 -04:00
return command ;
}
NfcCommand mf_classic_poller_handler_nested_controller ( MfClassicPoller * instance ) {
// Iterate through keys
NfcCommand command = NfcCommandContinue ;
MfClassicPollerDictAttackContext * dict_attack_ctx = & instance - > mode_ctx . dict_attack_ctx ;
if ( dict_attack_ctx - > nested_nonce . count > 0 ) {
2024-08-02 07:04:43 -04:00
if ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeWeak ) {
instance - > state = MfClassicPollerStateNestedDictAttack ;
return command ;
} else if ( dict_attack_ctx - > prng_type = = MfClassicPrngTypeHard ) {
instance - > state = MfClassicPollerStateNestedLog ;
return command ;
}
2024-08-01 09:10:02 -04:00
}
if ( dict_attack_ctx - > backdoor = = MfClassicBackdoorUnknown ) {
instance - > state = MfClassicPollerStateNestedAnalyzeBackdoor ;
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 ;
instance - > state = MfClassicPollerStateNestedCollectNtEnc ;
return command ;
}
// TODO: If we've recovered all keys, read blocks and go to complete
instance - > state = MfClassicPollerStateKeyReuseStart ;
return command ;
}
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
NfcCommand mf_classic_poller_handler_success ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
instance - > mfc_event . type = MfClassicPollerEventTypeSuccess ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
return command ;
}
NfcCommand mf_classic_poller_handler_fail ( MfClassicPoller * instance ) {
NfcCommand command = NfcCommandContinue ;
instance - > mfc_event . type = MfClassicPollerEventTypeFail ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
instance - > state = MfClassicPollerStateDetectType ;
return command ;
}
static const MfClassicPollerReadHandler
mf_classic_poller_dict_attack_handler [ MfClassicPollerStateNum ] = {
[ MfClassicPollerStateDetectType ] = mf_classic_poller_handler_detect_type ,
[ MfClassicPollerStateStart ] = mf_classic_poller_handler_start ,
[ MfClassicPollerStateRequestSectorTrailer ] =
mf_classic_poller_handler_request_sector_trailer ,
[ MfClassicPollerStateCheckWriteConditions ] = mf_classic_handler_check_write_conditions ,
[ MfClassicPollerStateReadBlock ] = mf_classic_poller_handler_read_block ,
[ MfClassicPollerStateWriteBlock ] = mf_classic_poller_handler_write_block ,
[ MfClassicPollerStateWriteValueBlock ] = mf_classic_poller_handler_write_value_block ,
[ MfClassicPollerStateNextSector ] = mf_classic_poller_handler_next_sector ,
[ MfClassicPollerStateRequestKey ] = mf_classic_poller_handler_request_key ,
[ MfClassicPollerStateRequestReadSector ] = mf_classic_poller_handler_request_read_sector ,
[ MfClassicPollerStateReadSectorBlocks ] =
mf_classic_poller_handler_request_read_sector_blocks ,
[ MfClassicPollerStateAuthKeyA ] = mf_classic_poller_handler_auth_a ,
[ MfClassicPollerStateAuthKeyB ] = mf_classic_poller_handler_auth_b ,
[ MfClassicPollerStateReadSector ] = mf_classic_poller_handler_read_sector ,
[ MfClassicPollerStateKeyReuseStart ] = mf_classic_poller_handler_key_reuse_start ,
[ MfClassicPollerStateKeyReuseAuthKeyA ] = mf_classic_poller_handler_key_reuse_auth_key_a ,
[ MfClassicPollerStateKeyReuseAuthKeyB ] = mf_classic_poller_handler_key_reuse_auth_key_b ,
[ MfClassicPollerStateKeyReuseReadSector ] = mf_classic_poller_handler_key_reuse_read_sector ,
2024-08-01 09:10:02 -04:00
[ MfClassicPollerStateNestedAnalyzePRNG ] = mf_classic_poller_handler_nested_analyze_prng ,
[ MfClassicPollerStateNestedAnalyzeBackdoor ] = mf_classic_poller_handler_nested_analyze_backdoor ,
[ MfClassicPollerStateNestedCollectNt ] =
mf_classic_poller_handler_nested_collect_nt ,
[ MfClassicPollerStateNestedController ] =
mf_classic_poller_handler_nested_controller ,
[ MfClassicPollerStateNestedCollectNtEnc ] =
mf_classic_poller_handler_nested_collect_nt_enc ,
2024-08-02 07:04:43 -04:00
[ MfClassicPollerStateNestedDictAttack ] =
mf_classic_poller_handler_nested_dict_attack ,
2024-08-01 09:10:02 -04:00
[ MfClassicPollerStateNestedLog ] = mf_classic_poller_handler_nested_log ,
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.
Starring:
- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer
Supporting roles:
- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance
Special thanks:
@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 07:08:09 +04:00
[ MfClassicPollerStateSuccess ] = mf_classic_poller_handler_success ,
[ MfClassicPollerStateFail ] = mf_classic_poller_handler_fail ,
} ;
NfcCommand mf_classic_poller_run ( NfcGenericEvent event , void * context ) {
furi_assert ( event . event_data ) ;
furi_assert ( event . protocol = = NfcProtocolIso14443_3a ) ;
furi_assert ( context ) ;
MfClassicPoller * instance = context ;
Iso14443_3aPollerEvent * iso14443_3a_event = event . event_data ;
NfcCommand command = NfcCommandContinue ;
if ( iso14443_3a_event - > type = = Iso14443_3aPollerEventTypeReady ) {
if ( instance - > card_state = = MfClassicCardStateLost ) {
instance - > card_state = MfClassicCardStateDetected ;
instance - > mfc_event . type = MfClassicPollerEventTypeCardDetected ;
instance - > callback ( instance - > general_event , instance - > context ) ;
}
command = mf_classic_poller_dict_attack_handler [ instance - > state ] ( instance ) ;
} else if ( iso14443_3a_event - > type = = Iso14443_3aPollerEventTypeError ) {
if ( instance - > card_state = = MfClassicCardStateDetected ) {
instance - > card_state = MfClassicCardStateLost ;
instance - > mfc_event . type = MfClassicPollerEventTypeCardLost ;
command = instance - > callback ( instance - > general_event , instance - > context ) ;
}
}
return command ;
}
bool mf_classic_poller_detect ( NfcGenericEvent event , void * context ) {
furi_assert ( event . event_data ) ;
furi_assert ( event . protocol = = NfcProtocolIso14443_3a ) ;
furi_assert ( context ) ;
Iso14443_3aPoller * iso3_poller = event . instance ;
Iso14443_3aPollerEvent * iso14443_3a_event = event . event_data ;
bool detected = false ;
const uint8_t auth_cmd [ ] = { MF_CLASSIC_CMD_AUTH_KEY_A , 0 } ;
BitBuffer * tx_buffer = bit_buffer_alloc ( COUNT_OF ( auth_cmd ) ) ;
bit_buffer_copy_bytes ( tx_buffer , auth_cmd , COUNT_OF ( auth_cmd ) ) ;
BitBuffer * rx_buffer = bit_buffer_alloc ( sizeof ( MfClassicNt ) ) ;
if ( iso14443_3a_event - > type = = Iso14443_3aPollerEventTypeReady ) {
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame (
iso3_poller , tx_buffer , rx_buffer , MF_CLASSIC_FWT_FC ) ;
if ( error = = Iso14443_3aErrorWrongCrc ) {
if ( bit_buffer_get_size_bytes ( rx_buffer ) = = sizeof ( MfClassicNt ) ) {
detected = true ;
}
}
}
bit_buffer_free ( tx_buffer ) ;
bit_buffer_free ( rx_buffer ) ;
return detected ;
}
void mf_classic_poller_set_callback (
MfClassicPoller * instance ,
NfcGenericCallback callback ,
void * context ) {
furi_assert ( instance ) ;
furi_assert ( callback ) ;
instance - > callback = callback ;
instance - > context = context ;
}
const MfClassicData * mf_classic_poller_get_data ( const MfClassicPoller * instance ) {
furi_assert ( instance ) ;
furi_assert ( instance - > data ) ;
return instance - > data ;
}
const NfcPollerBase mf_classic_poller = {
. alloc = ( NfcPollerAlloc ) mf_classic_poller_alloc ,
. free = ( NfcPollerFree ) mf_classic_poller_free ,
. set_callback = ( NfcPollerSetCallback ) mf_classic_poller_set_callback ,
. run = ( NfcPollerRun ) mf_classic_poller_run ,
. detect = ( NfcPollerDetect ) mf_classic_poller_detect ,
. get_data = ( NfcPollerGetData ) mf_classic_poller_get_data ,
2024-08-01 09:10:02 -04:00
} ;