picopass_worker.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. #include "picopass_worker_i.h"
  2. #include <flipper_format/flipper_format.h>
  3. #define TAG "PicopassWorker"
  4. static void picopass_worker_enable_field() {
  5. furi_hal_nfc_ll_txrx_on();
  6. furi_hal_nfc_exit_sleep();
  7. furi_hal_nfc_ll_poll();
  8. }
  9. static ReturnCode picopass_worker_disable_field(ReturnCode rc) {
  10. furi_hal_nfc_ll_txrx_off();
  11. furi_hal_nfc_start_sleep();
  12. return rc;
  13. }
  14. /***************************** Picopass Worker API *******************************/
  15. PicopassWorker* picopass_worker_alloc() {
  16. PicopassWorker* picopass_worker = malloc(sizeof(PicopassWorker));
  17. // Worker thread attributes
  18. picopass_worker->thread =
  19. furi_thread_alloc_ex("PicopassWorker", 8 * 1024, picopass_worker_task, picopass_worker);
  20. picopass_worker->callback = NULL;
  21. picopass_worker->context = NULL;
  22. picopass_worker->storage = furi_record_open(RECORD_STORAGE);
  23. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  24. return picopass_worker;
  25. }
  26. void picopass_worker_free(PicopassWorker* picopass_worker) {
  27. furi_assert(picopass_worker);
  28. furi_thread_free(picopass_worker->thread);
  29. furi_record_close(RECORD_STORAGE);
  30. free(picopass_worker);
  31. }
  32. PicopassWorkerState picopass_worker_get_state(PicopassWorker* picopass_worker) {
  33. return picopass_worker->state;
  34. }
  35. void picopass_worker_start(
  36. PicopassWorker* picopass_worker,
  37. PicopassWorkerState state,
  38. PicopassDeviceData* dev_data,
  39. PicopassWorkerCallback callback,
  40. void* context) {
  41. furi_assert(picopass_worker);
  42. furi_assert(dev_data);
  43. picopass_worker->callback = callback;
  44. picopass_worker->context = context;
  45. picopass_worker->dev_data = dev_data;
  46. picopass_worker_change_state(picopass_worker, state);
  47. furi_thread_start(picopass_worker->thread);
  48. }
  49. void picopass_worker_stop(PicopassWorker* picopass_worker) {
  50. furi_assert(picopass_worker);
  51. furi_assert(picopass_worker->thread);
  52. if(furi_thread_get_state(picopass_worker->thread) != FuriThreadStateStopped) {
  53. picopass_worker_change_state(picopass_worker, PicopassWorkerStateStop);
  54. furi_thread_join(picopass_worker->thread);
  55. }
  56. }
  57. void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorkerState state) {
  58. picopass_worker->state = state;
  59. }
  60. /***************************** Picopass Worker Thread *******************************/
  61. ReturnCode picopass_detect_card(int timeout) {
  62. UNUSED(timeout);
  63. ReturnCode err;
  64. err = rfalPicoPassPollerInitialize();
  65. if(err != ERR_NONE) {
  66. FURI_LOG_E(TAG, "rfalPicoPassPollerInitialize error %d", err);
  67. return err;
  68. }
  69. err = rfalFieldOnAndStartGT();
  70. if(err != ERR_NONE) {
  71. FURI_LOG_E(TAG, "rfalFieldOnAndStartGT error %d", err);
  72. return err;
  73. }
  74. err = rfalPicoPassPollerCheckPresence();
  75. if(err != ERR_RF_COLLISION) {
  76. //FURI_LOG_E(TAG, "rfalPicoPassPollerCheckPresence error %d", err);
  77. return err;
  78. }
  79. return ERR_NONE;
  80. }
  81. ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
  82. rfalPicoPassIdentifyRes idRes;
  83. rfalPicoPassSelectRes selRes;
  84. ReturnCode err;
  85. err = rfalPicoPassPollerIdentify(&idRes);
  86. if(err != ERR_NONE) {
  87. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  88. return err;
  89. }
  90. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  91. if(err != ERR_NONE) {
  92. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  93. return err;
  94. }
  95. memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, selRes.CSN, sizeof(selRes.CSN));
  96. FURI_LOG_D(
  97. TAG,
  98. "csn %02x%02x%02x%02x%02x%02x%02x%02x",
  99. AA1[PICOPASS_CSN_BLOCK_INDEX].data[0],
  100. AA1[PICOPASS_CSN_BLOCK_INDEX].data[1],
  101. AA1[PICOPASS_CSN_BLOCK_INDEX].data[2],
  102. AA1[PICOPASS_CSN_BLOCK_INDEX].data[3],
  103. AA1[PICOPASS_CSN_BLOCK_INDEX].data[4],
  104. AA1[PICOPASS_CSN_BLOCK_INDEX].data[5],
  105. AA1[PICOPASS_CSN_BLOCK_INDEX].data[6],
  106. AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
  107. rfalPicoPassReadBlockRes cfg = {0};
  108. rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
  109. memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
  110. FURI_LOG_D(
  111. TAG,
  112. "config %02x%02x%02x%02x%02x%02x%02x%02x",
  113. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
  114. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
  115. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
  116. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
  117. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
  118. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
  119. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
  120. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
  121. rfalPicoPassReadBlockRes aia;
  122. rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia);
  123. memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data));
  124. FURI_LOG_D(
  125. TAG,
  126. "aia %02x%02x%02x%02x%02x%02x%02x%02x",
  127. AA1[PICOPASS_AIA_BLOCK_INDEX].data[0],
  128. AA1[PICOPASS_AIA_BLOCK_INDEX].data[1],
  129. AA1[PICOPASS_AIA_BLOCK_INDEX].data[2],
  130. AA1[PICOPASS_AIA_BLOCK_INDEX].data[3],
  131. AA1[PICOPASS_AIA_BLOCK_INDEX].data[4],
  132. AA1[PICOPASS_AIA_BLOCK_INDEX].data[5],
  133. AA1[PICOPASS_AIA_BLOCK_INDEX].data[6],
  134. AA1[PICOPASS_AIA_BLOCK_INDEX].data[7]);
  135. return ERR_NONE;
  136. }
  137. static ReturnCode
  138. picopass_auth_dict(PicopassWorker* picopass_worker, IclassEliteDictType dict_type) {
  139. rfalPicoPassReadCheckRes rcRes;
  140. rfalPicoPassCheckRes chkRes;
  141. bool elite = (dict_type != IclassStandardDictTypeFlipper);
  142. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  143. PicopassBlock* AA1 = dev_data->AA1;
  144. PicopassPacs* pacs = &dev_data->pacs;
  145. uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
  146. uint8_t* div_key = AA1[PICOPASS_KD_BLOCK_INDEX].data;
  147. ReturnCode err = ERR_PARAM;
  148. uint8_t mac[4] = {0};
  149. uint8_t ccnr[12] = {0};
  150. size_t index = 0;
  151. uint8_t key[PICOPASS_BLOCK_LEN] = {0};
  152. if(!iclass_elite_dict_check_presence(dict_type)) {
  153. FURI_LOG_E(TAG, "Dictionary not found");
  154. return ERR_PARAM;
  155. }
  156. IclassEliteDict* dict = iclass_elite_dict_alloc(dict_type);
  157. if(!dict) {
  158. FURI_LOG_E(TAG, "Dictionary not allocated");
  159. return ERR_PARAM;
  160. }
  161. FURI_LOG_D(TAG, "Loaded %lu keys", iclass_elite_dict_get_total_keys(dict));
  162. while(iclass_elite_dict_get_next_key(dict, key)) {
  163. FURI_LOG_D(
  164. TAG,
  165. "Try to %s auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x",
  166. elite ? "elite" : "standard",
  167. index++,
  168. key[0],
  169. key[1],
  170. key[2],
  171. key[3],
  172. key[4],
  173. key[5],
  174. key[6],
  175. key[7]);
  176. err = rfalPicoPassPollerReadCheck(&rcRes);
  177. if(err != ERR_NONE) {
  178. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  179. break;
  180. }
  181. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  182. loclass_iclass_calc_div_key(csn, key, div_key, elite);
  183. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  184. err = rfalPicoPassPollerCheck(mac, &chkRes);
  185. if(err == ERR_NONE) {
  186. memcpy(pacs->key, key, PICOPASS_BLOCK_LEN);
  187. break;
  188. }
  189. if(picopass_worker->state != PicopassWorkerStateDetect) break;
  190. }
  191. iclass_elite_dict_free(dict);
  192. return err;
  193. }
  194. ReturnCode picopass_auth(PicopassWorker* picopass_worker) {
  195. ReturnCode err;
  196. FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]");
  197. err = picopass_auth_dict(picopass_worker, IclassStandardDictTypeFlipper);
  198. if(err == ERR_NONE) {
  199. return ERR_NONE;
  200. }
  201. FURI_LOG_I(TAG, "Starting user dictionary attack [Elite KDF]");
  202. err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeUser);
  203. if(err == ERR_NONE) {
  204. return ERR_NONE;
  205. }
  206. FURI_LOG_I(TAG, "Starting system dictionary attack [Elite KDF]");
  207. err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeFlipper);
  208. if(err == ERR_NONE) {
  209. return ERR_NONE;
  210. }
  211. return err;
  212. }
  213. ReturnCode picopass_read_card(PicopassBlock* AA1) {
  214. ReturnCode err;
  215. size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
  216. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
  217. PICOPASS_MAX_APP_LIMIT;
  218. for(size_t i = 2; i < app_limit; i++) {
  219. if(i == PICOPASS_KD_BLOCK_INDEX) {
  220. // Skip over Kd block which is populated earlier (READ of Kd returns all FF's)
  221. continue;
  222. }
  223. rfalPicoPassReadBlockRes block;
  224. err = rfalPicoPassPollerReadBlock(i, &block);
  225. if(err != ERR_NONE) {
  226. FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
  227. return err;
  228. }
  229. FURI_LOG_D(
  230. TAG,
  231. "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
  232. i,
  233. block.data[0],
  234. block.data[1],
  235. block.data[2],
  236. block.data[3],
  237. block.data[4],
  238. block.data[5],
  239. block.data[6],
  240. block.data[7]);
  241. memcpy(AA1[i].data, block.data, sizeof(block.data));
  242. }
  243. return ERR_NONE;
  244. }
  245. ReturnCode picopass_write_card(PicopassBlock* AA1) {
  246. rfalPicoPassIdentifyRes idRes;
  247. rfalPicoPassSelectRes selRes;
  248. rfalPicoPassReadCheckRes rcRes;
  249. rfalPicoPassCheckRes chkRes;
  250. ReturnCode err;
  251. uint8_t div_key[8] = {0};
  252. uint8_t mac[4] = {0};
  253. uint8_t ccnr[12] = {0};
  254. err = rfalPicoPassPollerIdentify(&idRes);
  255. if(err != ERR_NONE) {
  256. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  257. return err;
  258. }
  259. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  260. if(err != ERR_NONE) {
  261. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  262. return err;
  263. }
  264. err = rfalPicoPassPollerReadCheck(&rcRes);
  265. if(err != ERR_NONE) {
  266. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  267. return err;
  268. }
  269. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  270. loclass_iclass_calc_div_key(selRes.CSN, (uint8_t*)picopass_iclass_key, div_key, false);
  271. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  272. err = rfalPicoPassPollerCheck(mac, &chkRes);
  273. if(err != ERR_NONE) {
  274. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  275. return err;
  276. }
  277. for(size_t i = 6; i < 10; i++) {
  278. FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i);
  279. uint8_t data[9] = {0};
  280. data[0] = i;
  281. memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
  282. loclass_doMAC_N(data, sizeof(data), div_key, mac);
  283. FURI_LOG_D(
  284. TAG,
  285. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  286. i,
  287. data[1],
  288. data[2],
  289. data[3],
  290. data[4],
  291. data[5],
  292. data[6],
  293. data[7],
  294. data[8],
  295. mac[0],
  296. mac[1],
  297. mac[2],
  298. mac[3]);
  299. err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac);
  300. if(err != ERR_NONE) {
  301. FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
  302. return err;
  303. }
  304. }
  305. return ERR_NONE;
  306. }
  307. ReturnCode picopass_write_block(PicopassBlock* AA1, uint8_t blockNo, uint8_t* newBlock) {
  308. rfalPicoPassIdentifyRes idRes;
  309. rfalPicoPassSelectRes selRes;
  310. rfalPicoPassReadCheckRes rcRes;
  311. rfalPicoPassCheckRes chkRes;
  312. ReturnCode err;
  313. uint8_t mac[4] = {0};
  314. uint8_t ccnr[12] = {0};
  315. err = rfalPicoPassPollerIdentify(&idRes);
  316. if(err != ERR_NONE) {
  317. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  318. return err;
  319. }
  320. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  321. if(err != ERR_NONE) {
  322. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  323. return err;
  324. }
  325. err = rfalPicoPassPollerReadCheck(&rcRes);
  326. if(err != ERR_NONE) {
  327. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  328. return err;
  329. }
  330. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  331. if(memcmp(selRes.CSN, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN) != 0) {
  332. FURI_LOG_E(TAG, "Wrong CSN for write");
  333. return ERR_REQUEST;
  334. }
  335. loclass_opt_doReaderMAC(ccnr, AA1[PICOPASS_KD_BLOCK_INDEX].data, mac);
  336. err = rfalPicoPassPollerCheck(mac, &chkRes);
  337. if(err != ERR_NONE) {
  338. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  339. return err;
  340. }
  341. FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", blockNo);
  342. uint8_t data[9] = {
  343. blockNo,
  344. newBlock[0],
  345. newBlock[1],
  346. newBlock[2],
  347. newBlock[3],
  348. newBlock[4],
  349. newBlock[5],
  350. newBlock[6],
  351. newBlock[7]};
  352. loclass_doMAC_N(data, sizeof(data), AA1[PICOPASS_KD_BLOCK_INDEX].data, mac);
  353. FURI_LOG_D(
  354. TAG,
  355. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  356. blockNo,
  357. data[1],
  358. data[2],
  359. data[3],
  360. data[4],
  361. data[5],
  362. data[6],
  363. data[7],
  364. data[8],
  365. mac[0],
  366. mac[1],
  367. mac[2],
  368. mac[3]);
  369. err = rfalPicoPassPollerWriteBlock(data[0], data + 1, mac);
  370. if(err != ERR_NONE) {
  371. FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
  372. return err;
  373. }
  374. return ERR_NONE;
  375. }
  376. void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) {
  377. furi_assert(picopass_worker);
  378. furi_assert(picopass_worker->callback);
  379. picopass_device_data_clear(picopass_worker->dev_data);
  380. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  381. PicopassBlock* AA1 = dev_data->AA1;
  382. PicopassPacs* pacs = &dev_data->pacs;
  383. for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
  384. memset(AA1[i].data, 0, sizeof(AA1[i].data));
  385. }
  386. memset(pacs, 0, sizeof(PicopassPacs));
  387. IclassEliteDictAttackData* dict_attack_data =
  388. &picopass_worker->dev_data->iclass_elite_dict_attack_data;
  389. bool elite = (dict_attack_data->type != IclassStandardDictTypeFlipper);
  390. rfalPicoPassReadCheckRes rcRes;
  391. rfalPicoPassCheckRes chkRes;
  392. ReturnCode err;
  393. uint8_t mac[4] = {0};
  394. uint8_t ccnr[12] = {0};
  395. size_t index = 0;
  396. uint8_t key[PICOPASS_BLOCK_LEN] = {0};
  397. // Load dictionary
  398. IclassEliteDict* dict = dict_attack_data->dict;
  399. if(!dict) {
  400. FURI_LOG_E(TAG, "Dictionary not found");
  401. picopass_worker->callback(PicopassWorkerEventNoDictFound, picopass_worker->context);
  402. return;
  403. }
  404. do {
  405. if(picopass_detect_card(1000) == ERR_NONE) {
  406. picopass_worker->callback(PicopassWorkerEventCardDetected, picopass_worker->context);
  407. // Process first found device
  408. err = picopass_read_preauth(AA1);
  409. if(err != ERR_NONE) {
  410. FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
  411. picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context);
  412. return;
  413. }
  414. // Thank you proxmark!
  415. pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8);
  416. pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
  417. if(pacs->se_enabled) {
  418. FURI_LOG_D(TAG, "SE enabled");
  419. picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context);
  420. return;
  421. }
  422. break;
  423. } else {
  424. picopass_worker->callback(PicopassWorkerEventNoCardDetected, picopass_worker->context);
  425. }
  426. if(picopass_worker->state != PicopassWorkerStateEliteDictAttack) break;
  427. furi_delay_ms(100);
  428. } while(true);
  429. FURI_LOG_D(
  430. TAG, "Start Dictionary attack, Key Count %lu", iclass_elite_dict_get_total_keys(dict));
  431. while(iclass_elite_dict_get_next_key(dict, key)) {
  432. FURI_LOG_T(TAG, "Key %zu", index);
  433. if(++index % PICOPASS_DICT_KEY_BATCH_SIZE == 0) {
  434. picopass_worker->callback(
  435. PicopassWorkerEventNewDictKeyBatch, picopass_worker->context);
  436. }
  437. err = rfalPicoPassPollerReadCheck(&rcRes);
  438. if(err != ERR_NONE) {
  439. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  440. break;
  441. }
  442. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  443. uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
  444. uint8_t* div_key = AA1[PICOPASS_KD_BLOCK_INDEX].data;
  445. loclass_iclass_calc_div_key(csn, key, div_key, elite);
  446. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  447. err = rfalPicoPassPollerCheck(mac, &chkRes);
  448. if(err == ERR_NONE) {
  449. FURI_LOG_I(TAG, "Found key");
  450. memcpy(pacs->key, key, PICOPASS_BLOCK_LEN);
  451. pacs->elite_kdf = elite;
  452. err = picopass_read_card(AA1);
  453. if(err != ERR_NONE) {
  454. FURI_LOG_E(TAG, "picopass_read_card error %d", err);
  455. picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context);
  456. break;
  457. }
  458. err = picopass_device_parse_credential(AA1, pacs);
  459. if(err != ERR_NONE) {
  460. FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
  461. picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context);
  462. break;
  463. }
  464. err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
  465. if(err != ERR_NONE) {
  466. FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
  467. picopass_worker->callback(PicopassWorkerEventFail, picopass_worker->context);
  468. break;
  469. }
  470. picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context);
  471. break;
  472. }
  473. if(picopass_worker->state != PicopassWorkerStateEliteDictAttack) break;
  474. }
  475. FURI_LOG_D(TAG, "Dictionary complete");
  476. if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) {
  477. picopass_worker->callback(PicopassWorkerEventSuccess, picopass_worker->context);
  478. } else {
  479. picopass_worker->callback(PicopassWorkerEventAborted, picopass_worker->context);
  480. }
  481. }
  482. int32_t picopass_worker_task(void* context) {
  483. PicopassWorker* picopass_worker = context;
  484. picopass_worker_enable_field();
  485. if(picopass_worker->state == PicopassWorkerStateDetect) {
  486. picopass_worker_detect(picopass_worker);
  487. } else if(picopass_worker->state == PicopassWorkerStateWrite) {
  488. picopass_worker_write(picopass_worker);
  489. } else if(picopass_worker->state == PicopassWorkerStateWriteKey) {
  490. picopass_worker_write_key(picopass_worker);
  491. } else if(picopass_worker->state == PicopassWorkerStateEliteDictAttack) {
  492. picopass_worker_elite_dict_attack(picopass_worker);
  493. } else if(picopass_worker->state == PicopassWorkerStateStop) {
  494. FURI_LOG_D(TAG, "Worker state stop");
  495. // no-op
  496. } else {
  497. FURI_LOG_W(TAG, "Unknown state %d", picopass_worker->state);
  498. }
  499. picopass_worker_disable_field(ERR_NONE);
  500. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  501. return 0;
  502. }
  503. void picopass_worker_detect(PicopassWorker* picopass_worker) {
  504. picopass_device_data_clear(picopass_worker->dev_data);
  505. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  506. PicopassBlock* AA1 = dev_data->AA1;
  507. PicopassPacs* pacs = &dev_data->pacs;
  508. ReturnCode err;
  509. // reset device data
  510. for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
  511. memset(AA1[i].data, 0, sizeof(AA1[i].data));
  512. }
  513. memset(pacs, 0, sizeof(PicopassPacs));
  514. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  515. while(picopass_worker->state == PicopassWorkerStateDetect) {
  516. if(picopass_detect_card(1000) == ERR_NONE) {
  517. // Process first found device
  518. err = picopass_read_preauth(AA1);
  519. if(err != ERR_NONE) {
  520. FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
  521. nextState = PicopassWorkerEventFail;
  522. }
  523. // Thank you proxmark!
  524. pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8);
  525. pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
  526. if(pacs->se_enabled) {
  527. FURI_LOG_D(TAG, "SE enabled");
  528. nextState = PicopassWorkerEventFail;
  529. }
  530. if(nextState == PicopassWorkerEventSuccess) {
  531. err = picopass_auth(picopass_worker);
  532. if(err != ERR_NONE) {
  533. FURI_LOG_E(TAG, "picopass_try_auth error %d", err);
  534. nextState = PicopassWorkerEventFail;
  535. }
  536. }
  537. if(nextState == PicopassWorkerEventSuccess) {
  538. err = picopass_read_card(AA1);
  539. if(err != ERR_NONE) {
  540. FURI_LOG_E(TAG, "picopass_read_card error %d", err);
  541. nextState = PicopassWorkerEventFail;
  542. }
  543. }
  544. if(nextState == PicopassWorkerEventSuccess) {
  545. err = picopass_device_parse_credential(AA1, pacs);
  546. if(err != ERR_NONE) {
  547. FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
  548. nextState = PicopassWorkerEventFail;
  549. }
  550. }
  551. if(nextState == PicopassWorkerEventSuccess) {
  552. err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
  553. if(err != ERR_NONE) {
  554. FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
  555. nextState = PicopassWorkerEventFail;
  556. }
  557. }
  558. // Notify caller and exit
  559. if(picopass_worker->callback) {
  560. picopass_worker->callback(nextState, picopass_worker->context);
  561. }
  562. break;
  563. }
  564. furi_delay_ms(100);
  565. }
  566. }
  567. void picopass_worker_write(PicopassWorker* picopass_worker) {
  568. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  569. PicopassBlock* AA1 = dev_data->AA1;
  570. ReturnCode err;
  571. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  572. while(picopass_worker->state == PicopassWorkerStateWrite) {
  573. if(picopass_detect_card(1000) == ERR_NONE) {
  574. err = picopass_write_card(AA1);
  575. if(err != ERR_NONE) {
  576. FURI_LOG_E(TAG, "picopass_write_card error %d", err);
  577. nextState = PicopassWorkerEventFail;
  578. }
  579. // Notify caller and exit
  580. if(picopass_worker->callback) {
  581. picopass_worker->callback(nextState, picopass_worker->context);
  582. }
  583. break;
  584. }
  585. furi_delay_ms(100);
  586. }
  587. }
  588. void picopass_worker_write_key(PicopassWorker* picopass_worker) {
  589. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  590. PicopassBlock* AA1 = dev_data->AA1;
  591. PicopassPacs* pacs = &dev_data->pacs;
  592. ReturnCode err;
  593. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  594. uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
  595. uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data;
  596. uint8_t fuses = configBlock[7];
  597. uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data;
  598. uint8_t newKey[PICOPASS_BLOCK_LEN] = {0};
  599. loclass_iclass_calc_div_key(csn, pacs->key, newKey, pacs->elite_kdf);
  600. if((fuses & 0x80) == 0x80) {
  601. FURI_LOG_D(TAG, "Plain write for personalized mode key change");
  602. } else {
  603. FURI_LOG_D(TAG, "XOR write for application mode key change");
  604. // XOR when in application mode
  605. for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
  606. newKey[i] ^= oldKey[i];
  607. }
  608. }
  609. while(picopass_worker->state == PicopassWorkerStateWriteKey) {
  610. if(picopass_detect_card(1000) == ERR_NONE) {
  611. err = picopass_write_block(AA1, PICOPASS_KD_BLOCK_INDEX, newKey);
  612. if(err != ERR_NONE) {
  613. FURI_LOG_E(TAG, "picopass_write_block error %d", err);
  614. nextState = PicopassWorkerEventFail;
  615. }
  616. // Notify caller and exit
  617. if(picopass_worker->callback) {
  618. picopass_worker->callback(nextState, picopass_worker->context);
  619. }
  620. break;
  621. }
  622. furi_delay_ms(100);
  623. }
  624. }