parent
							
								
									c9e3f20314
								
							
						
					
					
						commit
						76ed466eb4
					
				| @ -101,6 +101,15 @@ App( | |||||||
|     sources=["plugins/supported_cards/umarsh.c"], |     sources=["plugins/supported_cards/umarsh.c"], | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | App( | ||||||
|  |     appid="hid_parser", | ||||||
|  |     apptype=FlipperAppType.PLUGIN, | ||||||
|  |     entry_point="hid_plugin_ep", | ||||||
|  |     targets=["f7"], | ||||||
|  |     requires=["nfc"], | ||||||
|  |     sources=["plugins/supported_cards/hid.c"], | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| App( | App( | ||||||
|     appid="nfc_start", |     appid="nfc_start", | ||||||
|     targets=["f7"], |     targets=["f7"], | ||||||
|  | |||||||
							
								
								
									
										153
									
								
								applications/main/nfc/plugins/supported_cards/hid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								applications/main/nfc/plugins/supported_cards/hid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,153 @@ | |||||||
|  | #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 "HID" | ||||||
|  | 
 | ||||||
|  | static const uint64_t hid_key = 0x484944204953; | ||||||
|  | 
 | ||||||
|  | bool hid_verify(Nfc* nfc) { | ||||||
|  |     bool verified = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         const uint8_t verify_sector = 1; | ||||||
|  |         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(hid_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 hid_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(hid_key, sizeof(MfClassicKey), keys.key_a[i].data); | ||||||
|  |             FURI_BIT_SET(keys.key_a_mask, i); | ||||||
|  |             nfc_util_num2bytes(hid_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 uint8_t get_bit_length(const uint8_t* half_block) { | ||||||
|  |     uint8_t bitLength = 0; | ||||||
|  |     uint32_t* halves = (uint32_t*)half_block; | ||||||
|  |     if(halves[0] == 0) { | ||||||
|  |         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); | ||||||
|  |         bitLength = 31 - leading0s; | ||||||
|  |     } else { | ||||||
|  |         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0])); | ||||||
|  |         bitLength = 63 - leading0s; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return bitLength; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint64_t get_pacs_bits(const uint8_t* block, uint8_t bitLength) { | ||||||
|  |     // Remove sentinel bit from credential.  Byteswapping to handle array of bytes vs 64bit value
 | ||||||
|  |     uint64_t sentinel = __builtin_bswap64(1ULL << bitLength); | ||||||
|  |     uint64_t swapped = 0; | ||||||
|  |     memcpy(&swapped, block, sizeof(uint64_t)); | ||||||
|  |     swapped = __builtin_bswap64(swapped ^ sentinel); | ||||||
|  |     FURI_LOG_D(TAG, "PACS: (%d) %016llx", bitLength, swapped); | ||||||
|  |     return swapped; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool hid_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
 | ||||||
|  |         const uint8_t verify_sector = 1; | ||||||
|  |         MfClassicSectorTrailer* sec_tr = | ||||||
|  |             mf_classic_get_sector_trailer_by_sector(data, verify_sector); | ||||||
|  |         uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); | ||||||
|  |         if(key != hid_key) break; | ||||||
|  | 
 | ||||||
|  |         // Currently doesn't support bit length > 63
 | ||||||
|  |         const uint8_t* credential_block = data->block[5].data + 8; | ||||||
|  | 
 | ||||||
|  |         uint8_t bitLength = get_bit_length(credential_block); | ||||||
|  |         if(bitLength == 0) break; | ||||||
|  | 
 | ||||||
|  |         uint64_t credential = get_pacs_bits(credential_block, bitLength); | ||||||
|  |         if(credential == 0) break; | ||||||
|  | 
 | ||||||
|  |         furi_string_printf(parsed_data, "\e#HID Card\n%dbit\n%llx", bitLength, credential); | ||||||
|  | 
 | ||||||
|  |         parsed = true; | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return parsed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Actual implementation of app<>plugin interface */ | ||||||
|  | static const NfcSupportedCardsPlugin hid_plugin = { | ||||||
|  |     .protocol = NfcProtocolMfClassic, | ||||||
|  |     .verify = hid_verify, | ||||||
|  |     .read = hid_read, | ||||||
|  |     .parse = hid_parse, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Plugin descriptor to comply with basic plugin specification */ | ||||||
|  | static const FlipperAppPluginDescriptor hid_plugin_descriptor = { | ||||||
|  |     .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, | ||||||
|  |     .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, | ||||||
|  |     .entry_point = &hid_plugin, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Plugin entry point - must return a pointer to const descriptor  */ | ||||||
|  | const FlipperAppPluginDescriptor* hid_plugin_ep() { | ||||||
|  |     return &hid_plugin_descriptor; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Eric Betts
						Eric Betts