picopass_poller.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. #include "picopass_poller_i.h"
  2. #include "../loclass/optimized_cipher.h"
  3. #include <furi/furi.h>
  4. #define TAG "Picopass"
  5. typedef NfcCommand (*PicopassPollerStateHandler)(PicopassPoller* instance);
  6. static void picopass_poller_reset(PicopassPoller* instance) {
  7. instance->current_block = 0;
  8. }
  9. static void picopass_poller_prepare_read(PicopassPoller* instance) {
  10. instance->app_limit = instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] <
  11. PICOPASS_MAX_APP_LIMIT ?
  12. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
  13. PICOPASS_MAX_APP_LIMIT;
  14. instance->current_block = 2;
  15. }
  16. NfcCommand picopass_poller_request_mode_handler(PicopassPoller* instance) {
  17. NfcCommand command = NfcCommandContinue;
  18. instance->event.type = PicopassPollerEventTypeRequestMode;
  19. command = instance->callback(instance->event, instance->context);
  20. instance->mode = instance->event_data.req_mode.mode;
  21. instance->state = PicopassPollerStateDetect;
  22. return command;
  23. }
  24. NfcCommand picopass_poller_detect_handler(PicopassPoller* instance) {
  25. NfcCommand command = NfcCommandContinue;
  26. PicopassError error = picopass_poller_actall(instance);
  27. if(error == PicopassErrorNone) {
  28. instance->state = PicopassPollerStateSelect;
  29. instance->event.type = PicopassPollerEventTypeCardDetected;
  30. command = instance->callback(instance->event, instance->context);
  31. } else {
  32. furi_delay_ms(100);
  33. }
  34. return command;
  35. }
  36. NfcCommand picopass_poller_select_handler(PicopassPoller* instance) {
  37. NfcCommand command = NfcCommandContinue;
  38. do {
  39. PicopassError error = picopass_poller_identify(instance, &instance->col_res_serial_num);
  40. if(error != PicopassErrorNone) {
  41. instance->state = PicopassPollerStateFail;
  42. break;
  43. }
  44. error =
  45. picopass_poller_select(instance, &instance->col_res_serial_num, &instance->serial_num);
  46. if(error != PicopassErrorNone) {
  47. instance->state = PicopassPollerStateFail;
  48. break;
  49. }
  50. if(instance->mode == PicopassPollerModeRead) {
  51. instance->state = PicopassPollerStatePreAuth;
  52. } else {
  53. instance->state = PicopassPollerStateAuth;
  54. }
  55. } while(false);
  56. return command;
  57. }
  58. NfcCommand picopass_poller_pre_auth_handler(PicopassPoller* instance) {
  59. NfcCommand command = NfcCommandContinue;
  60. PicopassError error = PicopassErrorNone;
  61. do {
  62. memcpy(
  63. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data,
  64. instance->serial_num.data,
  65. sizeof(PicopassSerialNum));
  66. FURI_LOG_D(
  67. TAG,
  68. "csn %02x%02x%02x%02x%02x%02x%02x%02x",
  69. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[0],
  70. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[1],
  71. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[2],
  72. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[3],
  73. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[4],
  74. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[5],
  75. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[6],
  76. instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
  77. PicopassBlock block = {};
  78. error = picopass_poller_read_block(instance, 1, &block);
  79. if(error != PicopassErrorNone) {
  80. instance->state = PicopassPollerStateFail;
  81. break;
  82. }
  83. memcpy(
  84. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data,
  85. block.data,
  86. sizeof(PicopassBlock));
  87. FURI_LOG_D(
  88. TAG,
  89. "config %02x%02x%02x%02x%02x%02x%02x%02x",
  90. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
  91. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
  92. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
  93. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
  94. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
  95. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
  96. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
  97. instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
  98. error = picopass_poller_read_block(instance, 5, &block);
  99. if(error != PicopassErrorNone) {
  100. instance->state = PicopassPollerStateFail;
  101. break;
  102. }
  103. memcpy(
  104. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
  105. block.data,
  106. sizeof(PicopassBlock));
  107. FURI_LOG_D(
  108. TAG,
  109. "aia %02x%02x%02x%02x%02x%02x%02x%02x",
  110. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[0],
  111. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[1],
  112. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[2],
  113. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[3],
  114. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[4],
  115. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[5],
  116. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[6],
  117. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data[7]);
  118. instance->state = PicopassPollerStateCheckSecurity;
  119. } while(false);
  120. return command;
  121. }
  122. NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
  123. NfcCommand command = NfcCommandContinue;
  124. // Thank you proxmark!
  125. PicopassBlock temp_block = {};
  126. memset(temp_block.data, 0xff, sizeof(PicopassBlock));
  127. instance->data->pacs.legacy =
  128. (memcmp(
  129. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
  130. temp_block.data,
  131. sizeof(PicopassBlock)) == 0);
  132. temp_block.data[3] = 0x00;
  133. temp_block.data[4] = 0x06;
  134. instance->data->pacs.se_enabled =
  135. (memcmp(
  136. instance->data->AA1[PICOPASS_SECURE_AIA_BLOCK_INDEX].data,
  137. temp_block.data,
  138. sizeof(PicopassBlock)) == 0);
  139. if(instance->data->pacs.se_enabled) {
  140. FURI_LOG_D(TAG, "SE enabled");
  141. instance->state = PicopassPollerStateFail;
  142. } else {
  143. instance->state = PicopassPollerStateAuth;
  144. }
  145. return command;
  146. }
  147. NfcCommand picopass_poller_auth_handler(PicopassPoller* instance) {
  148. NfcCommand command = NfcCommandContinue;
  149. do {
  150. // Request key
  151. instance->event.type = PicopassPollerEventTypeRequestKey;
  152. command = instance->callback(instance->event, instance->context);
  153. if(command != NfcCommandContinue) break;
  154. if(!instance->event_data.req_key.is_key_provided) {
  155. instance->state = PicopassPollerStateFail;
  156. break;
  157. }
  158. FURI_LOG_D(
  159. TAG,
  160. "Try to %s auth with key %02x%02x%02x%02x%02x%02x%02x%02x",
  161. instance->event_data.req_key.is_elite_key ? "elite" : "standard",
  162. instance->event_data.req_key.key[0],
  163. instance->event_data.req_key.key[1],
  164. instance->event_data.req_key.key[2],
  165. instance->event_data.req_key.key[3],
  166. instance->event_data.req_key.key[4],
  167. instance->event_data.req_key.key[5],
  168. instance->event_data.req_key.key[6],
  169. instance->event_data.req_key.key[7]);
  170. PicopassReadCheckResp read_check_resp = {};
  171. uint8_t* csn = instance->serial_num.data;
  172. memset(instance->div_key, 0, sizeof(instance->div_key));
  173. uint8_t* div_key = NULL;
  174. if(instance->mode == PicopassPollerModeRead) {
  175. div_key = instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data;
  176. } else {
  177. div_key = instance->div_key;
  178. }
  179. uint8_t ccnr[12] = {};
  180. PicopassMac mac = {};
  181. PicopassError error = picopass_poller_read_check(instance, &read_check_resp);
  182. if(error == PicopassErrorTimeout) {
  183. instance->event.type = PicopassPollerEventTypeCardLost;
  184. command = instance->callback(instance->event, instance->context);
  185. instance->state = PicopassPollerStateDetect;
  186. break;
  187. } else if(error != PicopassErrorNone) {
  188. FURI_LOG_E(TAG, "Read check failed: %d", error);
  189. break;
  190. }
  191. memcpy(ccnr, read_check_resp.data, sizeof(PicopassReadCheckResp)); // last 4 bytes left 0
  192. loclass_iclass_calc_div_key(
  193. csn,
  194. instance->event_data.req_key.key,
  195. div_key,
  196. instance->event_data.req_key.is_elite_key);
  197. loclass_opt_doReaderMAC(ccnr, div_key, mac.data);
  198. PicopassCheckResp check_resp = {};
  199. error = picopass_poller_check(instance, &mac, &check_resp);
  200. if(error == PicopassErrorNone) {
  201. FURI_LOG_I(TAG, "Found key");
  202. memcpy(instance->mac.data, mac.data, sizeof(PicopassMac));
  203. if(instance->mode == PicopassPollerModeRead) {
  204. memcpy(
  205. instance->data->pacs.key, instance->event_data.req_key.key, PICOPASS_KEY_LEN);
  206. instance->data->pacs.elite_kdf = instance->event_data.req_key.is_elite_key;
  207. picopass_poller_prepare_read(instance);
  208. instance->state = PicopassPollerStateReadBlock;
  209. } else if(instance->mode == PicopassPollerModeWrite) {
  210. instance->state = PicopassPollerStateWriteBlock;
  211. } else {
  212. instance->state = PicopassPollerStateWriteKey;
  213. }
  214. }
  215. } while(false);
  216. return command;
  217. }
  218. NfcCommand picopass_poller_read_block_handler(PicopassPoller* instance) {
  219. NfcCommand command = NfcCommandContinue;
  220. do {
  221. if(instance->current_block == instance->app_limit) {
  222. instance->state = PicopassPollerStateParseCredential;
  223. break;
  224. }
  225. if(instance->current_block == PICOPASS_SECURE_KD_BLOCK_INDEX) {
  226. // Skip over Kd block which is populated earlier (READ of Kd returns all FF's)
  227. instance->current_block++;
  228. }
  229. PicopassBlock block = {};
  230. PicopassError error =
  231. picopass_poller_read_block(instance, instance->current_block, &block);
  232. if(error != PicopassErrorNone) {
  233. FURI_LOG_E(TAG, "Failed to read block %d: %d", instance->current_block, error);
  234. instance->state = PicopassPollerStateFail;
  235. break;
  236. }
  237. FURI_LOG_D(
  238. TAG,
  239. "Block %d: %02x%02x%02x%02x%02x%02x%02x%02x",
  240. instance->current_block,
  241. block.data[0],
  242. block.data[1],
  243. block.data[2],
  244. block.data[3],
  245. block.data[4],
  246. block.data[5],
  247. block.data[6],
  248. block.data[7]);
  249. memcpy(
  250. instance->data->AA1[instance->current_block].data, block.data, sizeof(PicopassBlock));
  251. instance->current_block++;
  252. } while(false);
  253. return command;
  254. }
  255. NfcCommand picopass_poller_parse_credential_handler(PicopassPoller* instance) {
  256. NfcCommand command = NfcCommandContinue;
  257. picopass_device_parse_credential(instance->data->AA1, &instance->data->pacs);
  258. instance->state = PicopassPollerStateParseWiegand;
  259. return command;
  260. }
  261. NfcCommand picopass_poller_parse_wiegand_handler(PicopassPoller* instance) {
  262. NfcCommand command = NfcCommandContinue;
  263. picopass_device_parse_wiegand(instance->data->pacs.credential, &instance->data->pacs);
  264. instance->state = PicopassPollerStateSuccess;
  265. return command;
  266. }
  267. NfcCommand picopass_poller_write_block_handler(PicopassPoller* instance) {
  268. NfcCommand command = NfcCommandContinue;
  269. PicopassError error = PicopassErrorNone;
  270. do {
  271. instance->event.type = PicopassPollerEventTypeRequestWriteBlock;
  272. command = instance->callback(instance->event, instance->context);
  273. if(command != NfcCommandContinue) break;
  274. PicopassPollerEventDataRequestWriteBlock* write_block = &instance->event_data.req_write;
  275. if(!write_block->perform_write) {
  276. instance->state = PicopassPollerStateSuccess;
  277. break;
  278. }
  279. FURI_LOG_D(TAG, "Writing %d block", write_block->block_num);
  280. uint8_t data[9] = {};
  281. data[0] = write_block->block_num;
  282. memcpy(&data[1], write_block->block->data, PICOPASS_BLOCK_LEN);
  283. loclass_doMAC_N(data, sizeof(data), instance->div_key, instance->mac.data);
  284. FURI_LOG_D(
  285. TAG,
  286. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  287. write_block->block_num,
  288. data[1],
  289. data[2],
  290. data[3],
  291. data[4],
  292. data[5],
  293. data[6],
  294. data[7],
  295. data[8],
  296. instance->mac.data[0],
  297. instance->mac.data[1],
  298. instance->mac.data[2],
  299. instance->mac.data[3]);
  300. error = picopass_poller_write_block(
  301. instance, write_block->block_num, write_block->block, &instance->mac);
  302. if(error != PicopassErrorNone) {
  303. FURI_LOG_E(TAG, "Failed to write block %d. Error %d", write_block->block_num, error);
  304. instance->state = PicopassPollerStateFail;
  305. break;
  306. }
  307. } while(false);
  308. return command;
  309. }
  310. NfcCommand picopass_poller_write_key_handler(PicopassPoller* instance) {
  311. NfcCommand command = NfcCommandContinue;
  312. PicopassError error = PicopassErrorNone;
  313. do {
  314. instance->event.type = PicopassPollerEventTypeRequestWriteKey;
  315. command = instance->callback(instance->event, instance->context);
  316. if(command != NfcCommandContinue) break;
  317. const PicopassDeviceData* picopass_data = instance->event_data.req_write_key.data;
  318. const uint8_t* new_key = instance->event_data.req_write_key.key;
  319. bool is_elite_key = instance->event_data.req_write_key.is_elite_key;
  320. const uint8_t* csn = picopass_data->AA1[PICOPASS_CSN_BLOCK_INDEX].data;
  321. const uint8_t* config_block = picopass_data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data;
  322. uint8_t fuses = config_block[7];
  323. const uint8_t* old_key = picopass_data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data;
  324. PicopassBlock new_block = {};
  325. loclass_iclass_calc_div_key(csn, new_key, new_block.data, is_elite_key);
  326. if((fuses & 0x80) == 0x80) {
  327. FURI_LOG_D(TAG, "Plain write for personalized mode key change");
  328. } else {
  329. FURI_LOG_D(TAG, "XOR write for application mode key change");
  330. // XOR when in application mode
  331. for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
  332. new_block.data[i] ^= old_key[i];
  333. }
  334. }
  335. FURI_LOG_D(TAG, "Writing key to %d block", PICOPASS_SECURE_KD_BLOCK_INDEX);
  336. uint8_t data[9] = {};
  337. data[0] = PICOPASS_SECURE_KD_BLOCK_INDEX;
  338. memcpy(&data[1], new_block.data, PICOPASS_BLOCK_LEN);
  339. loclass_doMAC_N(data, sizeof(data), instance->div_key, instance->mac.data);
  340. FURI_LOG_D(
  341. TAG,
  342. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  343. PICOPASS_SECURE_KD_BLOCK_INDEX,
  344. data[1],
  345. data[2],
  346. data[3],
  347. data[4],
  348. data[5],
  349. data[6],
  350. data[7],
  351. data[8],
  352. instance->mac.data[0],
  353. instance->mac.data[1],
  354. instance->mac.data[2],
  355. instance->mac.data[3]);
  356. error = picopass_poller_write_block(
  357. instance, PICOPASS_SECURE_KD_BLOCK_INDEX, &new_block, &instance->mac);
  358. if(error != PicopassErrorNone) {
  359. FURI_LOG_E(
  360. TAG, "Failed to write block %d. Error %d", PICOPASS_SECURE_KD_BLOCK_INDEX, error);
  361. instance->state = PicopassPollerStateFail;
  362. break;
  363. }
  364. instance->state = PicopassPollerStateSuccess;
  365. } while(false);
  366. return command;
  367. }
  368. NfcCommand picopass_poller_success_handler(PicopassPoller* instance) {
  369. NfcCommand command = NfcCommandContinue;
  370. instance->event.type = PicopassPollerEventTypeSuccess;
  371. command = instance->callback(instance->event, instance->context);
  372. furi_delay_ms(100);
  373. return command;
  374. }
  375. NfcCommand picopass_poller_fail_handler(PicopassPoller* instance) {
  376. NfcCommand command = NfcCommandReset;
  377. instance->event.type = PicopassPollerEventTypeFail;
  378. command = instance->callback(instance->event, instance->context);
  379. picopass_poller_reset(instance);
  380. instance->state = PicopassPollerStateDetect;
  381. return command;
  382. }
  383. static const PicopassPollerStateHandler picopass_poller_state_handler[PicopassPollerStateNum] = {
  384. [PicopassPollerStateRequestMode] = picopass_poller_request_mode_handler,
  385. [PicopassPollerStateDetect] = picopass_poller_detect_handler,
  386. [PicopassPollerStateSelect] = picopass_poller_select_handler,
  387. [PicopassPollerStatePreAuth] = picopass_poller_pre_auth_handler,
  388. [PicopassPollerStateCheckSecurity] = picopass_poller_check_security,
  389. [PicopassPollerStateAuth] = picopass_poller_auth_handler,
  390. [PicopassPollerStateReadBlock] = picopass_poller_read_block_handler,
  391. [PicopassPollerStateWriteBlock] = picopass_poller_write_block_handler,
  392. [PicopassPollerStateWriteKey] = picopass_poller_write_key_handler,
  393. [PicopassPollerStateParseCredential] = picopass_poller_parse_credential_handler,
  394. [PicopassPollerStateParseWiegand] = picopass_poller_parse_wiegand_handler,
  395. [PicopassPollerStateSuccess] = picopass_poller_success_handler,
  396. [PicopassPollerStateFail] = picopass_poller_fail_handler,
  397. };
  398. static NfcCommand picopass_poller_callback(NfcEvent event, void* context) {
  399. furi_assert(context);
  400. PicopassPoller* instance = context;
  401. NfcCommand command = NfcCommandContinue;
  402. if(event.type == NfcEventTypePollerReady) {
  403. command = picopass_poller_state_handler[instance->state](instance);
  404. }
  405. if(instance->session_state == PicopassPollerSessionStateStopRequest) {
  406. command = NfcCommandStop;
  407. }
  408. return command;
  409. }
  410. void picopass_poller_start(
  411. PicopassPoller* instance,
  412. PicopassPollerCallback callback,
  413. void* context) {
  414. furi_assert(instance);
  415. furi_assert(instance->session_state == PicopassPollerSessionStateIdle);
  416. instance->callback = callback;
  417. instance->context = context;
  418. instance->session_state = PicopassPollerSessionStateActive;
  419. nfc_start(instance->nfc, picopass_poller_callback, instance);
  420. }
  421. void picopass_poller_stop(PicopassPoller* instance) {
  422. furi_assert(instance);
  423. instance->session_state = PicopassPollerSessionStateStopRequest;
  424. nfc_stop(instance->nfc);
  425. instance->session_state = PicopassPollerSessionStateIdle;
  426. }
  427. PicopassPoller* picopass_poller_alloc(Nfc* nfc) {
  428. furi_assert(nfc);
  429. PicopassPoller* instance = malloc(sizeof(PicopassPoller));
  430. instance->nfc = nfc;
  431. nfc_config(instance->nfc, NfcModePoller, NfcTechIso15693);
  432. nfc_set_guard_time_us(instance->nfc, 10000);
  433. nfc_set_fdt_poll_fc(instance->nfc, 5000);
  434. nfc_set_fdt_poll_poll_us(instance->nfc, 1000);
  435. instance->event.data = &instance->event_data;
  436. instance->data = malloc(sizeof(PicopassDeviceData));
  437. instance->tx_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
  438. instance->rx_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
  439. instance->tmp_buffer = bit_buffer_alloc(PICOPASS_POLLER_BUFFER_SIZE);
  440. return instance;
  441. }
  442. void picopass_poller_free(PicopassPoller* instance) {
  443. furi_assert(instance);
  444. free(instance->data);
  445. bit_buffer_free(instance->tx_buffer);
  446. bit_buffer_free(instance->rx_buffer);
  447. bit_buffer_free(instance->tmp_buffer);
  448. free(instance);
  449. }
  450. const PicopassDeviceData* picopass_poller_get_data(PicopassPoller* instance) {
  451. furi_assert(instance);
  452. return instance->data;
  453. }