metroflip_scene_ovc.c 12 KB

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