mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2025-10-11 07:32:34 +02:00
Mifare Classic nested auth support (#3238)
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c1e0d02afc
commit
b51a754fd9
@@ -143,7 +143,8 @@ void crypto1_encrypt_reader_nonce(
|
|||||||
uint32_t cuid,
|
uint32_t cuid,
|
||||||
uint8_t* nt,
|
uint8_t* nt,
|
||||||
uint8_t* nr,
|
uint8_t* nr,
|
||||||
BitBuffer* out) {
|
BitBuffer* out,
|
||||||
|
bool is_nested) {
|
||||||
furi_assert(crypto);
|
furi_assert(crypto);
|
||||||
furi_assert(nt);
|
furi_assert(nt);
|
||||||
furi_assert(nr);
|
furi_assert(nr);
|
||||||
@@ -153,7 +154,11 @@ void crypto1_encrypt_reader_nonce(
|
|||||||
uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t));
|
uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t));
|
||||||
|
|
||||||
crypto1_init(crypto, key);
|
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++) {
|
for(size_t i = 0; i < 4; i++) {
|
||||||
uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
|
uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
|
||||||
|
@@ -35,7 +35,8 @@ void crypto1_encrypt_reader_nonce(
|
|||||||
uint32_t cuid,
|
uint32_t cuid,
|
||||||
uint8_t* nt,
|
uint8_t* nt,
|
||||||
uint8_t* nr,
|
uint8_t* nr,
|
||||||
BitBuffer* out);
|
BitBuffer* out,
|
||||||
|
bool is_nested);
|
||||||
|
|
||||||
uint32_t prng_successor(uint32_t x, uint32_t n);
|
uint32_t prng_successor(uint32_t x, uint32_t n);
|
||||||
|
|
||||||
|
@@ -178,6 +178,25 @@ MfClassicError mf_classic_poller_get_nt(
|
|||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicNt* nt);
|
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.
|
* @brief Perform authentication.
|
||||||
*
|
*
|
||||||
@@ -200,6 +219,27 @@ MfClassicError mf_classic_poller_auth(
|
|||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicAuthContext* data);
|
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.
|
* @brief Halt the tag.
|
||||||
*
|
*
|
||||||
|
@@ -33,11 +33,12 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_get_nt(
|
static MfClassicError mf_classic_poller_get_nt_common(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicNt* nt) {
|
MfClassicNt* nt,
|
||||||
|
bool is_nested) {
|
||||||
MfClassicError ret = MfClassicErrorNone;
|
MfClassicError ret = MfClassicErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@@ -47,14 +48,29 @@ MfClassicError mf_classic_poller_get_nt(
|
|||||||
uint8_t auth_cmd[2] = {auth_type, block_num};
|
uint8_t auth_cmd[2] = {auth_type, block_num};
|
||||||
bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd));
|
bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd));
|
||||||
|
|
||||||
error = iso14443_3a_poller_send_standard_frame(
|
if(is_nested) {
|
||||||
instance->iso14443_3a_poller,
|
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
|
||||||
instance->tx_plain_buffer,
|
crypto1_encrypt(
|
||||||
instance->rx_plain_buffer,
|
instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
|
||||||
MF_CLASSIC_FWT_FC);
|
error = iso14443_3a_poller_txrx_custom_parity(
|
||||||
if(error != Iso14443_3aErrorWrongCrc) {
|
instance->iso14443_3a_poller,
|
||||||
ret = mf_classic_process_error(error);
|
instance->tx_encrypted_buffer,
|
||||||
break;
|
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)) {
|
if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) {
|
||||||
ret = MfClassicErrorProtocol;
|
ret = MfClassicErrorProtocol;
|
||||||
@@ -69,12 +85,29 @@ MfClassicError mf_classic_poller_get_nt(
|
|||||||
return ret;
|
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,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicAuthContext* data) {
|
MfClassicAuthContext* data,
|
||||||
|
bool is_nested) {
|
||||||
MfClassicError ret = MfClassicErrorNone;
|
MfClassicError ret = MfClassicErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@@ -84,7 +117,11 @@ MfClassicError mf_classic_poller_auth(
|
|||||||
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
||||||
|
|
||||||
MfClassicNt nt = {};
|
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(ret != MfClassicErrorNone) break;
|
||||||
if(data) {
|
if(data) {
|
||||||
data->nt = nt;
|
data->nt = nt;
|
||||||
@@ -96,7 +133,13 @@ MfClassicError mf_classic_poller_auth(
|
|||||||
furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr));
|
furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr));
|
||||||
|
|
||||||
crypto1_encrypt_reader_nonce(
|
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(
|
error = iso14443_3a_poller_txrx_custom_parity(
|
||||||
instance->iso14443_3a_poller,
|
instance->iso14443_3a_poller,
|
||||||
instance->tx_encrypted_buffer,
|
instance->tx_encrypted_buffer,
|
||||||
@@ -130,6 +173,24 @@ MfClassicError mf_classic_poller_auth(
|
|||||||
return ret;
|
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 mf_classic_poller_halt(MfClassicPoller* instance) {
|
||||||
MfClassicError ret = MfClassicErrorNone;
|
MfClassicError ret = MfClassicErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,49.0,,
|
Version,+,49.1,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,49.0,,
|
Version,+,49.1,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.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_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t"
|
||||||
Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_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,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_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*"
|
||||||
Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller*
|
Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller*
|
||||||
Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*"
|
Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*"
|
||||||
|
|
Reference in New Issue
Block a user