picopass_worker.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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. ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
  142. rfalPicoPassReadCheckRes rcRes;
  143. rfalPicoPassCheckRes chkRes;
  144. ReturnCode err;
  145. uint8_t div_key[8] = {0};
  146. uint8_t mac[4] = {0};
  147. uint8_t ccnr[12] = {0};
  148. err = rfalPicoPassPollerReadCheck(&rcRes);
  149. if(err != ERR_NONE) {
  150. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  151. return err;
  152. }
  153. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  154. loclass_diversifyKey(AA1[PICOPASS_CSN_BLOCK_INDEX].data, picopass_iclass_key, div_key);
  155. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  156. err = rfalPicoPassPollerCheck(mac, &chkRes);
  157. if(err == ERR_NONE) {
  158. return ERR_NONE;
  159. }
  160. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  161. FURI_LOG_E(TAG, "Starting dictionary attack");
  162. size_t index = 0;
  163. uint8_t key[PICOPASS_BLOCK_LEN] = {0};
  164. if(!iclass_elite_dict_check_presence(IclassEliteDictTypeFlipper)) {
  165. FURI_LOG_E(TAG, "Dictionary not found");
  166. return ERR_PARAM;
  167. }
  168. IclassEliteDict* dict = iclass_elite_dict_alloc(IclassEliteDictTypeFlipper);
  169. if(!dict) {
  170. FURI_LOG_E(TAG, "Dictionary not allocated");
  171. return ERR_PARAM;
  172. }
  173. FURI_LOG_D(TAG, "Loaded %lu keys", iclass_elite_dict_get_total_keys(dict));
  174. while(iclass_elite_dict_get_next_key(dict, key)) {
  175. FURI_LOG_D(
  176. TAG,
  177. "Try to auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x",
  178. index++,
  179. key[0],
  180. key[1],
  181. key[2],
  182. key[3],
  183. key[4],
  184. key[5],
  185. key[6],
  186. key[7]);
  187. err = rfalPicoPassPollerReadCheck(&rcRes);
  188. if(err != ERR_NONE) {
  189. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  190. return err;
  191. }
  192. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  193. loclass_iclass_calc_div_key(AA1[PICOPASS_CSN_BLOCK_INDEX].data, key, div_key, true);
  194. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  195. err = rfalPicoPassPollerCheck(mac, &chkRes);
  196. if(err == ERR_NONE) {
  197. memcpy(pacs->key, key, PICOPASS_BLOCK_LEN);
  198. break;
  199. }
  200. }
  201. iclass_elite_dict_free(dict);
  202. return err;
  203. }
  204. ReturnCode picopass_read_card(PicopassBlock* AA1) {
  205. ReturnCode err;
  206. size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
  207. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
  208. PICOPASS_MAX_APP_LIMIT;
  209. for(size_t i = 2; i < app_limit; i++) {
  210. rfalPicoPassReadBlockRes block;
  211. err = rfalPicoPassPollerReadBlock(i, &block);
  212. if(err != ERR_NONE) {
  213. FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
  214. return err;
  215. }
  216. FURI_LOG_D(
  217. TAG,
  218. "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
  219. i,
  220. block.data[0],
  221. block.data[1],
  222. block.data[2],
  223. block.data[3],
  224. block.data[4],
  225. block.data[5],
  226. block.data[6],
  227. block.data[7]);
  228. memcpy(AA1[i].data, block.data, sizeof(block.data));
  229. }
  230. return ERR_NONE;
  231. }
  232. ReturnCode picopass_write_card(PicopassBlock* AA1) {
  233. rfalPicoPassIdentifyRes idRes;
  234. rfalPicoPassSelectRes selRes;
  235. rfalPicoPassReadCheckRes rcRes;
  236. rfalPicoPassCheckRes chkRes;
  237. ReturnCode err;
  238. uint8_t div_key[8] = {0};
  239. uint8_t mac[4] = {0};
  240. uint8_t ccnr[12] = {0};
  241. err = rfalPicoPassPollerIdentify(&idRes);
  242. if(err != ERR_NONE) {
  243. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  244. return err;
  245. }
  246. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  247. if(err != ERR_NONE) {
  248. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  249. return err;
  250. }
  251. err = rfalPicoPassPollerReadCheck(&rcRes);
  252. if(err != ERR_NONE) {
  253. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  254. return err;
  255. }
  256. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  257. loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key);
  258. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  259. err = rfalPicoPassPollerCheck(mac, &chkRes);
  260. if(err != ERR_NONE) {
  261. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  262. return err;
  263. }
  264. for(size_t i = 6; i < 10; i++) {
  265. FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i);
  266. uint8_t data[9] = {0};
  267. data[0] = i;
  268. memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
  269. loclass_doMAC_N(data, sizeof(data), div_key, mac);
  270. FURI_LOG_D(
  271. TAG,
  272. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  273. i,
  274. data[1],
  275. data[2],
  276. data[3],
  277. data[4],
  278. data[5],
  279. data[6],
  280. data[7],
  281. data[8],
  282. mac[0],
  283. mac[1],
  284. mac[2],
  285. mac[3]);
  286. err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac);
  287. if(err != ERR_NONE) {
  288. FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
  289. return err;
  290. }
  291. }
  292. return ERR_NONE;
  293. }
  294. int32_t picopass_worker_task(void* context) {
  295. PicopassWorker* picopass_worker = context;
  296. picopass_worker_enable_field();
  297. if(picopass_worker->state == PicopassWorkerStateDetect) {
  298. picopass_worker_detect(picopass_worker);
  299. } else if(picopass_worker->state == PicopassWorkerStateWrite) {
  300. picopass_worker_write(picopass_worker);
  301. }
  302. picopass_worker_disable_field(ERR_NONE);
  303. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  304. return 0;
  305. }
  306. void picopass_worker_detect(PicopassWorker* picopass_worker) {
  307. picopass_device_data_clear(picopass_worker->dev_data);
  308. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  309. PicopassBlock* AA1 = dev_data->AA1;
  310. PicopassPacs* pacs = &dev_data->pacs;
  311. ReturnCode err;
  312. // reset device data
  313. for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
  314. memset(AA1[i].data, 0, sizeof(AA1[i].data));
  315. }
  316. memset(pacs, 0, sizeof(PicopassPacs));
  317. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  318. while(picopass_worker->state == PicopassWorkerStateDetect) {
  319. if(picopass_detect_card(1000) == ERR_NONE) {
  320. // Process first found device
  321. err = picopass_read_preauth(AA1);
  322. if(err != ERR_NONE) {
  323. FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
  324. nextState = PicopassWorkerEventFail;
  325. }
  326. // Thank you proxmark!
  327. pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
  328. pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
  329. if(pacs->se_enabled) {
  330. FURI_LOG_D(TAG, "SE enabled");
  331. nextState = PicopassWorkerEventFail;
  332. }
  333. if(nextState == PicopassWorkerEventSuccess) {
  334. err = picopass_auth(AA1, pacs);
  335. if(err != ERR_NONE) {
  336. FURI_LOG_E(TAG, "picopass_try_auth error %d", err);
  337. nextState = PicopassWorkerEventFail;
  338. }
  339. }
  340. if(nextState == PicopassWorkerEventSuccess) {
  341. err = picopass_read_card(AA1);
  342. if(err != ERR_NONE) {
  343. FURI_LOG_E(TAG, "picopass_read_card error %d", err);
  344. nextState = PicopassWorkerEventFail;
  345. }
  346. }
  347. if(nextState == PicopassWorkerEventSuccess) {
  348. err = picopass_device_parse_credential(AA1, pacs);
  349. if(err != ERR_NONE) {
  350. FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
  351. nextState = PicopassWorkerEventFail;
  352. }
  353. }
  354. if(nextState == PicopassWorkerEventSuccess) {
  355. err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
  356. if(err != ERR_NONE) {
  357. FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
  358. nextState = PicopassWorkerEventFail;
  359. }
  360. }
  361. // Notify caller and exit
  362. if(picopass_worker->callback) {
  363. picopass_worker->callback(nextState, picopass_worker->context);
  364. }
  365. break;
  366. }
  367. furi_delay_ms(100);
  368. }
  369. }
  370. void picopass_worker_write(PicopassWorker* picopass_worker) {
  371. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  372. PicopassBlock* AA1 = dev_data->AA1;
  373. ReturnCode err;
  374. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  375. while(picopass_worker->state == PicopassWorkerStateWrite) {
  376. if(picopass_detect_card(1000) == ERR_NONE) {
  377. err = picopass_write_card(AA1);
  378. if(err != ERR_NONE) {
  379. FURI_LOG_E(TAG, "picopass_write_card error %d", err);
  380. nextState = PicopassWorkerEventFail;
  381. }
  382. // Notify caller and exit
  383. if(picopass_worker->callback) {
  384. picopass_worker->callback(nextState, picopass_worker->context);
  385. }
  386. break;
  387. }
  388. furi_delay_ms(100);
  389. }
  390. }