nfc: m1k-based Aime (non-AIC) card support (#3241)
Co-authored-by: gornekich <n.gorbadey@gmail.com>
This commit is contained in:
		
							parent
							
								
									eb6fe0a4db
								
							
						
					
					
						commit
						c477d1321a
					
				| @ -74,6 +74,15 @@ App( | |||||||
|     sources=["plugins/supported_cards/two_cities.c"], |     sources=["plugins/supported_cards/two_cities.c"], | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | App( | ||||||
|  |     appid="aime_parser", | ||||||
|  |     apptype=FlipperAppType.PLUGIN, | ||||||
|  |     entry_point="aime_plugin_ep", | ||||||
|  |     targets=["f7"], | ||||||
|  |     requires=["nfc"], | ||||||
|  |     sources=["plugins/supported_cards/aime.c"], | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| App( | App( | ||||||
|     appid="nfc_start", |     appid="nfc_start", | ||||||
|     targets=["f7"], |     targets=["f7"], | ||||||
|  | |||||||
							
								
								
									
										164
									
								
								applications/main/nfc/plugins/supported_cards/aime.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								applications/main/nfc/plugins/supported_cards/aime.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,164 @@ | |||||||
|  | #include "nfc_supported_card_plugin.h" | ||||||
|  | 
 | ||||||
|  | #include <flipper_application/flipper_application.h> | ||||||
|  | 
 | ||||||
|  | #include <nfc/nfc_device.h> | ||||||
|  | #include <nfc/helpers/nfc_util.h> | ||||||
|  | #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "Aime" | ||||||
|  | 
 | ||||||
|  | static const uint64_t aime_key = 0x574343467632; | ||||||
|  | 
 | ||||||
|  | bool aime_verify(Nfc* nfc) { | ||||||
|  |     bool verified = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         const uint8_t verify_sector = 0; | ||||||
|  |         uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); | ||||||
|  |         FURI_LOG_D(TAG, "Verifying sector %u", verify_sector); | ||||||
|  | 
 | ||||||
|  |         MfClassicKey key = {}; | ||||||
|  |         nfc_util_num2bytes(aime_key, COUNT_OF(key.data), key.data); | ||||||
|  | 
 | ||||||
|  |         MfClassicAuthContext auth_ctx = {}; | ||||||
|  |         MfClassicError error = | ||||||
|  |             mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); | ||||||
|  | 
 | ||||||
|  |         if(error != MfClassicErrorNone) { | ||||||
|  |             FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         verified = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return verified; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool aime_read(Nfc* nfc, NfcDevice* device) { | ||||||
|  |     furi_assert(nfc); | ||||||
|  |     furi_assert(device); | ||||||
|  | 
 | ||||||
|  |     bool is_read = false; | ||||||
|  | 
 | ||||||
|  |     MfClassicData* data = mf_classic_alloc(); | ||||||
|  |     nfc_device_copy_data(device, NfcProtocolMfClassic, data); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         MfClassicType type = MfClassicType1k; | ||||||
|  |         MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); | ||||||
|  |         if(error != MfClassicErrorNone) break; | ||||||
|  | 
 | ||||||
|  |         data->type = type; | ||||||
|  |         MfClassicDeviceKeys keys = {}; | ||||||
|  |         for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { | ||||||
|  |             nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_a[i].data); | ||||||
|  |             FURI_BIT_SET(keys.key_a_mask, i); | ||||||
|  |             nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_b[i].data); | ||||||
|  |             FURI_BIT_SET(keys.key_b_mask, i); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         error = mf_classic_poller_sync_read(nfc, &keys, data); | ||||||
|  |         if(error != MfClassicErrorNone) { | ||||||
|  |             FURI_LOG_W(TAG, "Failed to read data"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         nfc_device_set_data(device, NfcProtocolMfClassic, data); | ||||||
|  | 
 | ||||||
|  |         is_read = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     mf_classic_free(data); | ||||||
|  | 
 | ||||||
|  |     return is_read; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) { | ||||||
|  |     furi_assert(device); | ||||||
|  | 
 | ||||||
|  |     const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); | ||||||
|  | 
 | ||||||
|  |     bool parsed = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // verify key
 | ||||||
|  |         MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 0); | ||||||
|  |         uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); | ||||||
|  |         if(key != aime_key) break; | ||||||
|  | 
 | ||||||
|  |         // Aime Magic is stored at block 1, starts from byte 0, len 4 bytes
 | ||||||
|  |         const uint8_t* aime_magic = &data->block[1].data[0]; | ||||||
|  | 
 | ||||||
|  |         // verify aime magic
 | ||||||
|  |         if(aime_magic[0] != 'S' || aime_magic[1] != 'B' || aime_magic[2] != 'S' || | ||||||
|  |            aime_magic[3] != 'D') | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         // Aime checksum is stored at block 1, starts from byte 13, len 3 bytes
 | ||||||
|  |         // seems like only old games checks this? e.g., old versions of Chunithm
 | ||||||
|  |         const uint8_t* aime_checksum = &data->block[1].data[13]; | ||||||
|  | 
 | ||||||
|  |         // Aime access code is stored as decimal hex representation in block 2, starts from byte 6, len 10 bytes
 | ||||||
|  |         const uint8_t* aime_accesscode = &data->block[2].data[6]; | ||||||
|  | 
 | ||||||
|  |         char aime_accesscode_str[24 + 1]; | ||||||
|  |         snprintf( | ||||||
|  |             aime_accesscode_str, | ||||||
|  |             sizeof(aime_accesscode_str), | ||||||
|  |             "%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x", | ||||||
|  |             aime_accesscode[0], | ||||||
|  |             aime_accesscode[1], | ||||||
|  |             aime_accesscode[2], | ||||||
|  |             aime_accesscode[3], | ||||||
|  |             aime_accesscode[4], | ||||||
|  |             aime_accesscode[5], | ||||||
|  |             aime_accesscode[6], | ||||||
|  |             aime_accesscode[7], | ||||||
|  |             aime_accesscode[8], | ||||||
|  |             aime_accesscode[9]); | ||||||
|  | 
 | ||||||
|  |         // validate decimal hex representation
 | ||||||
|  |         for(int i = 0; i < 24; i++) { | ||||||
|  |             if(aime_accesscode_str[i] == ' ') continue; | ||||||
|  |             if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Note: Aime access code has some other self-check algorithms that are not public.
 | ||||||
|  |         // This parser does not try to verify the number.
 | ||||||
|  | 
 | ||||||
|  |         furi_string_printf( | ||||||
|  |             parsed_data, | ||||||
|  |             "\e#Aime Card\nAccess Code: \n%s\nChecksum: %02X%02X%02X\n", | ||||||
|  |             aime_accesscode_str, | ||||||
|  |             aime_checksum[0], | ||||||
|  |             aime_checksum[1], | ||||||
|  |             aime_checksum[2]); | ||||||
|  | 
 | ||||||
|  |         parsed = true; | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return parsed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Actual implementation of app<>plugin interface */ | ||||||
|  | static const NfcSupportedCardsPlugin aime_plugin = { | ||||||
|  |     .protocol = NfcProtocolMfClassic, | ||||||
|  |     .verify = aime_verify, | ||||||
|  |     .read = aime_read, | ||||||
|  |     .parse = aime_parse, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Plugin descriptor to comply with basic plugin specification */ | ||||||
|  | static const FlipperAppPluginDescriptor aime_plugin_descriptor = { | ||||||
|  |     .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, | ||||||
|  |     .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, | ||||||
|  |     .entry_point = &aime_plugin, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Plugin entry point - must return a pointer to const descriptor  */ | ||||||
|  | const FlipperAppPluginDescriptor* aime_plugin_ep() { | ||||||
|  |     return &aime_plugin_descriptor; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Honghao Zeng
						Honghao Zeng