metroflip_scene_ovc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #include <flipper_application.h>
  2. #include "../metroflip_i.h"
  3. #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
  4. #include <nfc/protocols/mf_classic/mf_classic.h>
  5. #include <nfc/protocols/mf_classic/mf_classic_poller.h>
  6. #include "../api/metroflip/metroflip_api.h"
  7. #include <dolphin/dolphin.h>
  8. #include <bit_lib.h>
  9. #include <furi_hal.h>
  10. #include <nfc/nfc.h>
  11. #include <nfc/nfc_device.h>
  12. #include <nfc/nfc_listener.h>
  13. typedef struct {
  14. int year;
  15. int month;
  16. int day;
  17. } OvcBcdDate;
  18. int bcd2int(int bcd) {
  19. return ((bcd >> 4) * 10) + (bcd & 0x0F);
  20. }
  21. #define TAG "Metroflip:Scene:OVC"
  22. uint8_t ovc_sector_num = 0;
  23. OvcBcdDate* ovc_bcd_date_new(int x) {
  24. OvcBcdDate* date = malloc(sizeof(OvcBcdDate));
  25. if(!date) {
  26. FURI_LOG_I(TAG, "Failed to allocate memory");
  27. return NULL;
  28. }
  29. date->day = bcd2int((x >> 0) & 0xFF);
  30. date->month = bcd2int((x >> 8) & 0xFF);
  31. date->year = bcd2int((x >> 16) & 0xFFFF);
  32. // Check if the year is valid
  33. if(date->year == 0) {
  34. free(date);
  35. return NULL;
  36. }
  37. return date;
  38. }
  39. static bool ovc_parse(FuriString* parsed_data, const MfClassicData* data) {
  40. bool parsed = false;
  41. do {
  42. // Parse data
  43. //Card ID (UID in Dec)
  44. size_t uid_len = 0;
  45. const uint8_t* uid = mf_classic_get_uid(data, &uid_len);
  46. uint32_t cardID = bit_lib_bytes_to_num_le(uid, 4);
  47. const MfClassicBlock* block1 = &data->block[1]; // basic info block
  48. const MfClassicBlock* block2 = &data->block[2]; // basic info block
  49. char bit_representation[32 * 8 + 1];
  50. bit_representation[0] = '\0';
  51. for(size_t i = 0; i < 32; i++) {
  52. char bits[9];
  53. uint8_t byte = 0;
  54. if(i < 16) { // First block
  55. byte = block1->data[i];
  56. } else { // Second block
  57. byte = block2->data[i - 16];
  58. }
  59. byte_to_binary(byte, bits);
  60. strlcat(bit_representation, bits, sizeof(bit_representation));
  61. }
  62. bit_representation[32 * 8] = '\0';
  63. FURI_LOG_I(TAG, "bit_repr %s", bit_representation);
  64. int card_type = bit_slice_to_dec(bit_representation, 145, 151);
  65. int days_from_epoch = bit_slice_to_dec(bit_representation, 95, 107);
  66. FURI_LOG_I(TAG, "%d", days_from_epoch);
  67. int seconds_with_epoch = (days_from_epoch * 3600 * 24) + epoch + 3600;
  68. furi_string_printf(
  69. parsed_data, "\e#Ov-Chipkaart\nCard ID: %lu\nCard Type: %d", cardID, card_type);
  70. DateTime dt = {0};
  71. datetime_timestamp_to_datetime(seconds_with_epoch, &dt);
  72. furi_string_cat_printf(parsed_data, "\nEnd Validity:\n");
  73. locale_format_datetime_cat(parsed_data, &dt, true);
  74. furi_string_cat_printf(parsed_data, "\n\n");
  75. const MfClassicBlock* block248 = &data->block[248];
  76. memset(bit_representation, 0, sizeof(bit_representation));
  77. for(size_t i = 0; i < 16; i++) {
  78. char bits[9];
  79. uint8_t byte = 0;
  80. byte = block248->data[i];
  81. byte_to_binary(byte, bits);
  82. strlcat(bit_representation, bits, sizeof(bit_representation));
  83. }
  84. int first_3_bits = bit_slice_to_dec(bit_representation, 0, 3);
  85. int credit_slot = (first_3_bits & 1) ? 250 : 249; // False is block 249 True is block 250
  86. FURI_LOG_I(TAG, "credit block: %d", credit_slot);
  87. const MfClassicBlock* credit_block = &data->block[credit_slot];
  88. memset(bit_representation, 0, sizeof(bit_representation));
  89. for(size_t i = 0; i < 16; i++) {
  90. char bits[9];
  91. uint8_t byte = 0;
  92. byte = credit_block->data[i];
  93. byte_to_binary(byte, bits);
  94. strlcat(bit_representation, bits, sizeof(bit_representation));
  95. }
  96. // credit
  97. float credit = bit_slice_to_dec(bit_representation, 78, 92) / 100.0;
  98. FURI_LOG_I(TAG, "bit_repr block credit: %s", bit_representation);
  99. FURI_LOG_I(TAG, "credit: %f", (double)credit);
  100. furi_string_cat_printf(parsed_data, "Credit: %f", (double)credit);
  101. // birthdate
  102. OvcBcdDate* date = ovc_bcd_date_new(bit_slice_to_dec(bit_representation, 78, 92));
  103. if(card_type == 2) {
  104. furi_string_cat_printf(
  105. parsed_data, "Date: %04d-%02d-%02d\n", date->year, date->month, date->day);
  106. }
  107. for(int sector = 32; sector < 35; sector++) {
  108. memset(bit_representation, 0, sizeof(bit_representation));
  109. char bit_representation[240 * 8 + 1]; // 15 x 16 bytes (the whole sector - sector trailer)
  110. bit_representation[0] = '\0';
  111. for(int block = (16 * (sector - 32) + 128); block < (16 * (sector - 32) + 143);
  112. block++) {
  113. const MfClassicBlock* current_block = &data->block[block];
  114. for(size_t i = 0; i < 16; i++) {
  115. char bits[9];
  116. uint8_t byte = 0;
  117. byte = current_block->data[i];
  118. byte_to_binary(byte, bits);
  119. strlcat(bit_representation, bits, sizeof(bit_representation));
  120. }
  121. }
  122. bit_representation[240 * 8] = '\0';
  123. FURI_LOG_I(TAG, "sector %d bit repr: %s\n", sector, bit_representation);
  124. }
  125. parsed = true;
  126. } while(false);
  127. return parsed;
  128. }
  129. static NfcCommand metroflip_scene_ovc_poller_callback(NfcGenericEvent event, void* context) {
  130. furi_assert(context);
  131. furi_assert(event.event_data);
  132. furi_assert(event.protocol == NfcProtocolMfClassic);
  133. NfcCommand command = NfcCommandContinue;
  134. const MfClassicPollerEvent* mfc_event = event.event_data;
  135. Metroflip* app = context;
  136. FuriString* parsed_data = furi_string_alloc();
  137. Widget* widget = app->widget;
  138. if(mfc_event->type == MfClassicPollerEventTypeCardDetected) {
  139. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardDetected);
  140. command = NfcCommandContinue;
  141. } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) {
  142. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventCardLost);
  143. command = NfcCommandStop;
  144. } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) {
  145. mfc_event->data->poller_mode.mode = MfClassicPollerModeRead;
  146. nfc_device_set_data(
  147. app->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(app->poller));
  148. nfc_device_get_data(app->nfc_device, NfcProtocolMfClassic);
  149. size_t uid_len = 0;
  150. const uint8_t* uid = nfc_device_get_uid(app->nfc_device, &uid_len);
  151. /*-----------------All of this is to store a keyfile in a permanent way for the user to always access------------*/
  152. /*-----------------Open cache file (if exists)------------*/
  153. char uid_str[uid_len * 2 + 1];
  154. uid_to_string(uid, uid_len, uid_str, sizeof(uid_str));
  155. uint64_t ovc_key_mask_a_required =
  156. 1095220854785; // 1111111100000000010000000000000000000001 key mask
  157. KeyfileManager manage =
  158. manage_keyfiles(uid_str, uid, uid_len, app->mfc_key_cache, ovc_key_mask_a_required, 0);
  159. char card_type[] = "OV-Chipkaart";
  160. switch(manage) {
  161. case MISSING_KEYFILE:
  162. handle_keyfile_case(app, "No keys found", "Missing keyfile", parsed_data, card_type);
  163. command = NfcCommandStop;
  164. break;
  165. case INCOMPLETE_KEYFILE:
  166. handle_keyfile_case(
  167. app, "Incomplete keyfile", "incomplete keyfile", parsed_data, card_type);
  168. command = NfcCommandStop;
  169. break;
  170. case SUCCESSFUL:
  171. FURI_LOG_I(TAG, "success");
  172. break;
  173. }
  174. } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) {
  175. FURI_LOG_I(TAG, "sec_num: %d", ovc_sector_num);
  176. MfClassicKey key = {};
  177. MfClassicKeyType key_type = MfClassicKeyTypeA;
  178. if(mf_classic_key_cache_get_next_key(
  179. app->mfc_key_cache, &ovc_sector_num, &key, &key_type)) {
  180. mfc_event->data->read_sector_request_data.sector_num = ovc_sector_num;
  181. mfc_event->data->read_sector_request_data.key = key;
  182. mfc_event->data->read_sector_request_data.key_type = key_type;
  183. mfc_event->data->read_sector_request_data.key_provided = true;
  184. } else {
  185. mfc_event->data->read_sector_request_data.key_provided = false;
  186. }
  187. } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) {
  188. nfc_device_set_data(
  189. app->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(app->poller));
  190. dolphin_deed(DolphinDeedNfcReadSuccess);
  191. furi_string_reset(app->text_box_store);
  192. const MfClassicData* mfc_data = nfc_device_get_data(app->nfc_device, NfcProtocolMfClassic);
  193. if(!ovc_parse(parsed_data, mfc_data)) {
  194. FURI_LOG_I(TAG, "Unknown card type");
  195. furi_string_printf(parsed_data, "\e#Unknown card\n");
  196. }
  197. widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  198. widget_add_button_element(
  199. widget, GuiButtonTypeRight, "Exit", metroflip_exit_widget_callback, app);
  200. furi_string_free(parsed_data);
  201. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewWidget);
  202. metroflip_app_blink_stop(app);
  203. UNUSED(ovc_parse);
  204. command = NfcCommandStop;
  205. } else if(mfc_event->type == MfClassicPollerEventTypeFail) {
  206. FURI_LOG_I(TAG, "fail");
  207. command = NfcCommandStop;
  208. }
  209. return command;
  210. }
  211. void metroflip_scene_ovc_on_enter(void* context) {
  212. Metroflip* app = context;
  213. dolphin_deed(DolphinDeedNfcRead);
  214. mf_classic_key_cache_reset(app->mfc_key_cache);
  215. // Setup view
  216. Popup* popup = app->popup;
  217. popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop);
  218. popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
  219. // Start worker
  220. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup);
  221. nfc_scanner_alloc(app->nfc);
  222. app->poller = nfc_poller_alloc(app->nfc, NfcProtocolMfClassic);
  223. nfc_poller_start(app->poller, metroflip_scene_ovc_poller_callback, app);
  224. metroflip_app_blink_start(app);
  225. }
  226. bool metroflip_scene_ovc_on_event(void* context, SceneManagerEvent event) {
  227. Metroflip* app = context;
  228. bool consumed = false;
  229. if(event.type == SceneManagerEventTypeCustom) {
  230. if(event.event == MetroflipCustomEventCardDetected) {
  231. Popup* popup = app->popup;
  232. popup_set_header(popup, "DON'T\nMOVE", 68, 30, AlignLeft, AlignTop);
  233. consumed = true;
  234. } else if(event.event == MetroflipCustomEventCardLost) {
  235. Popup* popup = app->popup;
  236. popup_set_header(popup, "Card \n lost", 68, 30, AlignLeft, AlignTop);
  237. consumed = true;
  238. } else if(event.event == MetroflipCustomEventWrongCard) {
  239. Popup* popup = app->popup;
  240. popup_set_header(popup, "WRONG \n CARD", 68, 30, AlignLeft, AlignTop);
  241. consumed = true;
  242. } else if(event.event == MetroflipCustomEventPollerFail) {
  243. Popup* popup = app->popup;
  244. popup_set_header(popup, "Failed", 68, 30, AlignLeft, AlignTop);
  245. consumed = true;
  246. }
  247. } else if(event.type == SceneManagerEventTypeBack) {
  248. scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
  249. consumed = true;
  250. }
  251. return consumed;
  252. }
  253. void metroflip_scene_ovc_on_exit(void* context) {
  254. Metroflip* app = context;
  255. widget_reset(app->widget);
  256. if(app->poller) {
  257. nfc_poller_stop(app->poller);
  258. nfc_poller_free(app->poller);
  259. }
  260. // Clear view
  261. popup_reset(app->popup);
  262. metroflip_app_blink_stop(app);
  263. }