Mifare Classic nested auth support (#3238)
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							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*" | ||||||
|  | |||||||
| 
 | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Augusto Zanellato
						Augusto Zanellato