picopass_worker.c 15 KB

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