picopass_worker.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. #include "picopass_worker_i.h"
  2. #include <flipper_format/flipper_format.h>
  3. #define TAG "PicopassWorker"
  4. const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
  5. const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00};
  6. static void picopass_worker_enable_field() {
  7. furi_hal_nfc_ll_txrx_on();
  8. furi_hal_nfc_exit_sleep();
  9. furi_hal_nfc_ll_poll();
  10. }
  11. static ReturnCode picopass_worker_disable_field(ReturnCode rc) {
  12. furi_hal_nfc_ll_txrx_off();
  13. furi_hal_nfc_start_sleep();
  14. return rc;
  15. }
  16. /***************************** Picopass Worker API *******************************/
  17. PicopassWorker* picopass_worker_alloc() {
  18. PicopassWorker* picopass_worker = malloc(sizeof(PicopassWorker));
  19. // Worker thread attributes
  20. picopass_worker->thread =
  21. furi_thread_alloc_ex("PicopassWorker", 8192, picopass_worker_task, picopass_worker);
  22. picopass_worker->callback = NULL;
  23. picopass_worker->context = NULL;
  24. picopass_worker->storage = furi_record_open(RECORD_STORAGE);
  25. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  26. return picopass_worker;
  27. }
  28. void picopass_worker_free(PicopassWorker* picopass_worker) {
  29. furi_assert(picopass_worker);
  30. furi_thread_free(picopass_worker->thread);
  31. furi_record_close(RECORD_STORAGE);
  32. free(picopass_worker);
  33. }
  34. PicopassWorkerState picopass_worker_get_state(PicopassWorker* picopass_worker) {
  35. return picopass_worker->state;
  36. }
  37. void picopass_worker_start(
  38. PicopassWorker* picopass_worker,
  39. PicopassWorkerState state,
  40. PicopassDeviceData* dev_data,
  41. PicopassWorkerCallback callback,
  42. void* context) {
  43. furi_assert(picopass_worker);
  44. furi_assert(dev_data);
  45. picopass_worker->callback = callback;
  46. picopass_worker->context = context;
  47. picopass_worker->dev_data = dev_data;
  48. picopass_worker_change_state(picopass_worker, state);
  49. furi_thread_start(picopass_worker->thread);
  50. }
  51. void picopass_worker_stop(PicopassWorker* picopass_worker) {
  52. furi_assert(picopass_worker);
  53. if(picopass_worker->state == PicopassWorkerStateBroken ||
  54. picopass_worker->state == PicopassWorkerStateReady) {
  55. return;
  56. }
  57. picopass_worker_disable_field(ERR_NONE);
  58. picopass_worker_change_state(picopass_worker, PicopassWorkerStateStop);
  59. furi_thread_join(picopass_worker->thread);
  60. }
  61. void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorkerState state) {
  62. picopass_worker->state = state;
  63. }
  64. /***************************** Picopass Worker Thread *******************************/
  65. ReturnCode picopass_detect_card(int timeout) {
  66. UNUSED(timeout);
  67. ReturnCode err;
  68. err = rfalPicoPassPollerInitialize();
  69. if(err != ERR_NONE) {
  70. FURI_LOG_E(TAG, "rfalPicoPassPollerInitialize error %d", err);
  71. return err;
  72. }
  73. err = rfalFieldOnAndStartGT();
  74. if(err != ERR_NONE) {
  75. FURI_LOG_E(TAG, "rfalFieldOnAndStartGT error %d", err);
  76. return err;
  77. }
  78. err = rfalPicoPassPollerCheckPresence();
  79. if(err != ERR_RF_COLLISION) {
  80. FURI_LOG_E(TAG, "rfalPicoPassPollerCheckPresence error %d", err);
  81. return err;
  82. }
  83. return ERR_NONE;
  84. }
  85. ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
  86. rfalPicoPassIdentifyRes idRes;
  87. rfalPicoPassSelectRes selRes;
  88. ReturnCode err;
  89. err = rfalPicoPassPollerIdentify(&idRes);
  90. if(err != ERR_NONE) {
  91. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  92. return err;
  93. }
  94. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  95. if(err != ERR_NONE) {
  96. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  97. return err;
  98. }
  99. memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, selRes.CSN, sizeof(selRes.CSN));
  100. FURI_LOG_D(
  101. TAG,
  102. "csn %02x%02x%02x%02x%02x%02x%02x%02x",
  103. AA1[PICOPASS_CSN_BLOCK_INDEX].data[0],
  104. AA1[PICOPASS_CSN_BLOCK_INDEX].data[1],
  105. AA1[PICOPASS_CSN_BLOCK_INDEX].data[2],
  106. AA1[PICOPASS_CSN_BLOCK_INDEX].data[3],
  107. AA1[PICOPASS_CSN_BLOCK_INDEX].data[4],
  108. AA1[PICOPASS_CSN_BLOCK_INDEX].data[5],
  109. AA1[PICOPASS_CSN_BLOCK_INDEX].data[6],
  110. AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
  111. rfalPicoPassReadBlockRes cfg = {0};
  112. rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
  113. memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
  114. FURI_LOG_D(
  115. TAG,
  116. "config %02x%02x%02x%02x%02x%02x%02x%02x",
  117. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
  118. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
  119. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
  120. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
  121. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
  122. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
  123. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
  124. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
  125. rfalPicoPassReadBlockRes aia;
  126. rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia);
  127. memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data));
  128. FURI_LOG_D(
  129. TAG,
  130. "aia %02x%02x%02x%02x%02x%02x%02x%02x",
  131. AA1[PICOPASS_AIA_BLOCK_INDEX].data[0],
  132. AA1[PICOPASS_AIA_BLOCK_INDEX].data[1],
  133. AA1[PICOPASS_AIA_BLOCK_INDEX].data[2],
  134. AA1[PICOPASS_AIA_BLOCK_INDEX].data[3],
  135. AA1[PICOPASS_AIA_BLOCK_INDEX].data[4],
  136. AA1[PICOPASS_AIA_BLOCK_INDEX].data[5],
  137. AA1[PICOPASS_AIA_BLOCK_INDEX].data[6],
  138. AA1[PICOPASS_AIA_BLOCK_INDEX].data[7]);
  139. return ERR_NONE;
  140. }
  141. static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) {
  142. rfalPicoPassReadCheckRes rcRes;
  143. rfalPicoPassCheckRes chkRes;
  144. ReturnCode err;
  145. uint8_t mac[4] = {0};
  146. uint8_t ccnr[12] = {0};
  147. err = rfalPicoPassPollerReadCheck(&rcRes);
  148. if(err != ERR_NONE) {
  149. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  150. return err;
  151. }
  152. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  153. loclass_diversifyKey(csn, picopass_iclass_key, div_key);
  154. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  155. return rfalPicoPassPollerCheck(mac, &chkRes);
  156. }
  157. static ReturnCode picopass_auth_dict(
  158. uint8_t* csn,
  159. PicopassPacs* pacs,
  160. uint8_t* div_key,
  161. IclassEliteDictType dict_type) {
  162. rfalPicoPassReadCheckRes rcRes;
  163. rfalPicoPassCheckRes chkRes;
  164. ReturnCode err = ERR_PARAM;
  165. uint8_t mac[4] = {0};
  166. uint8_t ccnr[12] = {0};
  167. size_t index = 0;
  168. uint8_t key[PICOPASS_BLOCK_LEN] = {0};
  169. if(!iclass_elite_dict_check_presence(dict_type)) {
  170. FURI_LOG_E(TAG, "Dictionary not found");
  171. return ERR_PARAM;
  172. }
  173. IclassEliteDict* dict = iclass_elite_dict_alloc(dict_type);
  174. if(!dict) {
  175. FURI_LOG_E(TAG, "Dictionary not allocated");
  176. return ERR_PARAM;
  177. }
  178. FURI_LOG_D(TAG, "Loaded %lu keys", iclass_elite_dict_get_total_keys(dict));
  179. while(iclass_elite_dict_get_next_key(dict, key)) {
  180. FURI_LOG_D(
  181. TAG,
  182. "Try to auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x",
  183. index++,
  184. key[0],
  185. key[1],
  186. key[2],
  187. key[3],
  188. key[4],
  189. key[5],
  190. key[6],
  191. key[7]);
  192. err = rfalPicoPassPollerReadCheck(&rcRes);
  193. if(err != ERR_NONE) {
  194. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  195. break;
  196. }
  197. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  198. loclass_iclass_calc_div_key(csn, key, div_key, true);
  199. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  200. err = rfalPicoPassPollerCheck(mac, &chkRes);
  201. if(err == ERR_NONE) {
  202. memcpy(pacs->key, key, PICOPASS_BLOCK_LEN);
  203. break;
  204. }
  205. }
  206. iclass_elite_dict_free(dict);
  207. return err;
  208. }
  209. ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
  210. ReturnCode err;
  211. FURI_LOG_E(TAG, "Trying standard legacy key");
  212. err = picopass_auth_standard(
  213. AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data);
  214. if(err == ERR_NONE) {
  215. return ERR_NONE;
  216. }
  217. FURI_LOG_E(TAG, "Starting user dictionary attack");
  218. err = picopass_auth_dict(
  219. AA1[PICOPASS_CSN_BLOCK_INDEX].data,
  220. pacs,
  221. AA1[PICOPASS_KD_BLOCK_INDEX].data,
  222. IclassEliteDictTypeUser);
  223. if(err == ERR_NONE) {
  224. return ERR_NONE;
  225. }
  226. FURI_LOG_E(TAG, "Starting in-built dictionary attack");
  227. err = picopass_auth_dict(
  228. AA1[PICOPASS_CSN_BLOCK_INDEX].data,
  229. pacs,
  230. AA1[PICOPASS_KD_BLOCK_INDEX].data,
  231. IclassEliteDictTypeFlipper);
  232. if(err == ERR_NONE) {
  233. return ERR_NONE;
  234. }
  235. return err;
  236. }
  237. ReturnCode picopass_read_card(PicopassBlock* AA1) {
  238. ReturnCode err;
  239. size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
  240. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
  241. PICOPASS_MAX_APP_LIMIT;
  242. for(size_t i = 2; i < app_limit; i++) {
  243. if(i == PICOPASS_KD_BLOCK_INDEX) {
  244. // Skip over Kd block which is populated earlier (READ of Kd returns all FF's)
  245. continue;
  246. }
  247. rfalPicoPassReadBlockRes block;
  248. err = rfalPicoPassPollerReadBlock(i, &block);
  249. if(err != ERR_NONE) {
  250. FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
  251. return err;
  252. }
  253. FURI_LOG_D(
  254. TAG,
  255. "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
  256. i,
  257. block.data[0],
  258. block.data[1],
  259. block.data[2],
  260. block.data[3],
  261. block.data[4],
  262. block.data[5],
  263. block.data[6],
  264. block.data[7]);
  265. memcpy(AA1[i].data, block.data, sizeof(block.data));
  266. }
  267. return ERR_NONE;
  268. }
  269. ReturnCode picopass_write_card(PicopassBlock* AA1) {
  270. rfalPicoPassIdentifyRes idRes;
  271. rfalPicoPassSelectRes selRes;
  272. rfalPicoPassReadCheckRes rcRes;
  273. rfalPicoPassCheckRes chkRes;
  274. ReturnCode err;
  275. uint8_t div_key[8] = {0};
  276. uint8_t mac[4] = {0};
  277. uint8_t ccnr[12] = {0};
  278. err = rfalPicoPassPollerIdentify(&idRes);
  279. if(err != ERR_NONE) {
  280. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  281. return err;
  282. }
  283. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  284. if(err != ERR_NONE) {
  285. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  286. return err;
  287. }
  288. err = rfalPicoPassPollerReadCheck(&rcRes);
  289. if(err != ERR_NONE) {
  290. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  291. return err;
  292. }
  293. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  294. loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key);
  295. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  296. err = rfalPicoPassPollerCheck(mac, &chkRes);
  297. if(err != ERR_NONE) {
  298. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  299. return err;
  300. }
  301. for(size_t i = 6; i < 10; i++) {
  302. FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i);
  303. uint8_t data[9] = {0};
  304. data[0] = i;
  305. memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
  306. loclass_doMAC_N(data, sizeof(data), div_key, mac);
  307. FURI_LOG_D(
  308. TAG,
  309. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  310. i,
  311. data[1],
  312. data[2],
  313. data[3],
  314. data[4],
  315. data[5],
  316. data[6],
  317. data[7],
  318. data[8],
  319. mac[0],
  320. mac[1],
  321. mac[2],
  322. mac[3]);
  323. err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac);
  324. if(err != ERR_NONE) {
  325. FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
  326. return err;
  327. }
  328. }
  329. return ERR_NONE;
  330. }
  331. int32_t picopass_worker_task(void* context) {
  332. PicopassWorker* picopass_worker = context;
  333. picopass_worker_enable_field();
  334. if(picopass_worker->state == PicopassWorkerStateDetect) {
  335. picopass_worker_detect(picopass_worker);
  336. } else if(picopass_worker->state == PicopassWorkerStateWrite) {
  337. picopass_worker_write(picopass_worker);
  338. }
  339. picopass_worker_disable_field(ERR_NONE);
  340. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  341. return 0;
  342. }
  343. void picopass_worker_detect(PicopassWorker* picopass_worker) {
  344. picopass_device_data_clear(picopass_worker->dev_data);
  345. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  346. PicopassBlock* AA1 = dev_data->AA1;
  347. PicopassPacs* pacs = &dev_data->pacs;
  348. ReturnCode err;
  349. // reset device data
  350. for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
  351. memset(AA1[i].data, 0, sizeof(AA1[i].data));
  352. }
  353. memset(pacs, 0, sizeof(PicopassPacs));
  354. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  355. while(picopass_worker->state == PicopassWorkerStateDetect) {
  356. if(picopass_detect_card(1000) == ERR_NONE) {
  357. // Process first found device
  358. err = picopass_read_preauth(AA1);
  359. if(err != ERR_NONE) {
  360. FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
  361. nextState = PicopassWorkerEventFail;
  362. }
  363. // Thank you proxmark!
  364. pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
  365. pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
  366. if(pacs->se_enabled) {
  367. FURI_LOG_D(TAG, "SE enabled");
  368. nextState = PicopassWorkerEventFail;
  369. }
  370. if(nextState == PicopassWorkerEventSuccess) {
  371. err = picopass_auth(AA1, pacs);
  372. if(err != ERR_NONE) {
  373. FURI_LOG_E(TAG, "picopass_try_auth error %d", err);
  374. nextState = PicopassWorkerEventFail;
  375. }
  376. }
  377. if(nextState == PicopassWorkerEventSuccess) {
  378. err = picopass_read_card(AA1);
  379. if(err != ERR_NONE) {
  380. FURI_LOG_E(TAG, "picopass_read_card error %d", err);
  381. nextState = PicopassWorkerEventFail;
  382. }
  383. }
  384. if(nextState == PicopassWorkerEventSuccess) {
  385. err = picopass_device_parse_credential(AA1, pacs);
  386. if(err != ERR_NONE) {
  387. FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
  388. nextState = PicopassWorkerEventFail;
  389. }
  390. }
  391. if(nextState == PicopassWorkerEventSuccess) {
  392. err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
  393. if(err != ERR_NONE) {
  394. FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
  395. nextState = PicopassWorkerEventFail;
  396. }
  397. }
  398. // Notify caller and exit
  399. if(picopass_worker->callback) {
  400. picopass_worker->callback(nextState, picopass_worker->context);
  401. }
  402. break;
  403. }
  404. furi_delay_ms(100);
  405. }
  406. }
  407. void picopass_worker_write(PicopassWorker* picopass_worker) {
  408. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  409. PicopassBlock* AA1 = dev_data->AA1;
  410. ReturnCode err;
  411. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  412. while(picopass_worker->state == PicopassWorkerStateWrite) {
  413. if(picopass_detect_card(1000) == ERR_NONE) {
  414. err = picopass_write_card(AA1);
  415. if(err != ERR_NONE) {
  416. FURI_LOG_E(TAG, "picopass_write_card error %d", err);
  417. nextState = PicopassWorkerEventFail;
  418. }
  419. // Notify caller and exit
  420. if(picopass_worker->callback) {
  421. picopass_worker->callback(nextState, picopass_worker->context);
  422. }
  423. break;
  424. }
  425. furi_delay_ms(100);
  426. }
  427. }