picopass_worker.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #include "picopass_worker_i.h"
  2. #define TAG "PicopassWorker"
  3. const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
  4. const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00};
  5. static void picopass_worker_enable_field() {
  6. furi_hal_nfc_ll_txrx_on();
  7. furi_hal_nfc_exit_sleep();
  8. furi_hal_nfc_ll_poll();
  9. }
  10. static ReturnCode picopass_worker_disable_field(ReturnCode rc) {
  11. furi_hal_nfc_ll_txrx_off();
  12. furi_hal_nfc_start_sleep();
  13. return rc;
  14. }
  15. /***************************** Picopass Worker API *******************************/
  16. PicopassWorker* picopass_worker_alloc() {
  17. PicopassWorker* picopass_worker = malloc(sizeof(PicopassWorker));
  18. // Worker thread attributes
  19. picopass_worker->thread = furi_thread_alloc();
  20. furi_thread_set_name(picopass_worker->thread, "PicopassWorker");
  21. furi_thread_set_stack_size(picopass_worker->thread, 8192);
  22. furi_thread_set_callback(picopass_worker->thread, picopass_worker_task);
  23. furi_thread_set_context(picopass_worker->thread, picopass_worker);
  24. picopass_worker->callback = NULL;
  25. picopass_worker->context = NULL;
  26. picopass_worker->storage = furi_record_open(RECORD_STORAGE);
  27. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  28. return picopass_worker;
  29. }
  30. void picopass_worker_free(PicopassWorker* picopass_worker) {
  31. furi_assert(picopass_worker);
  32. furi_thread_free(picopass_worker->thread);
  33. furi_record_close(RECORD_STORAGE);
  34. free(picopass_worker);
  35. }
  36. PicopassWorkerState picopass_worker_get_state(PicopassWorker* picopass_worker) {
  37. return picopass_worker->state;
  38. }
  39. void picopass_worker_start(
  40. PicopassWorker* picopass_worker,
  41. PicopassWorkerState state,
  42. PicopassDeviceData* dev_data,
  43. PicopassWorkerCallback callback,
  44. void* context) {
  45. furi_assert(picopass_worker);
  46. furi_assert(dev_data);
  47. picopass_worker->callback = callback;
  48. picopass_worker->context = context;
  49. picopass_worker->dev_data = dev_data;
  50. picopass_worker_change_state(picopass_worker, state);
  51. furi_thread_start(picopass_worker->thread);
  52. }
  53. void picopass_worker_stop(PicopassWorker* picopass_worker) {
  54. furi_assert(picopass_worker);
  55. if(picopass_worker->state == PicopassWorkerStateBroken ||
  56. picopass_worker->state == PicopassWorkerStateReady) {
  57. return;
  58. }
  59. picopass_worker_disable_field(ERR_NONE);
  60. picopass_worker_change_state(picopass_worker, PicopassWorkerStateStop);
  61. furi_thread_join(picopass_worker->thread);
  62. }
  63. void picopass_worker_change_state(PicopassWorker* picopass_worker, PicopassWorkerState state) {
  64. picopass_worker->state = state;
  65. }
  66. /***************************** Picopass Worker Thread *******************************/
  67. ReturnCode picopass_detect_card(int timeout) {
  68. UNUSED(timeout);
  69. ReturnCode err;
  70. err = rfalPicoPassPollerInitialize();
  71. if(err != ERR_NONE) {
  72. FURI_LOG_E(TAG, "rfalPicoPassPollerInitialize error %d", err);
  73. return err;
  74. }
  75. err = rfalFieldOnAndStartGT();
  76. if(err != ERR_NONE) {
  77. FURI_LOG_E(TAG, "rfalFieldOnAndStartGT error %d", err);
  78. return err;
  79. }
  80. err = rfalPicoPassPollerCheckPresence();
  81. if(err != ERR_RF_COLLISION) {
  82. FURI_LOG_E(TAG, "rfalPicoPassPollerCheckPresence error %d", err);
  83. return err;
  84. }
  85. return ERR_NONE;
  86. }
  87. ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
  88. rfalPicoPassIdentifyRes idRes;
  89. rfalPicoPassSelectRes selRes;
  90. ReturnCode err;
  91. err = rfalPicoPassPollerIdentify(&idRes);
  92. if(err != ERR_NONE) {
  93. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  94. return err;
  95. }
  96. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  97. if(err != ERR_NONE) {
  98. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  99. return err;
  100. }
  101. memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, selRes.CSN, sizeof(selRes.CSN));
  102. FURI_LOG_D(
  103. TAG,
  104. "csn %02x%02x%02x%02x%02x%02x%02x%02x",
  105. AA1[PICOPASS_CSN_BLOCK_INDEX].data[0],
  106. AA1[PICOPASS_CSN_BLOCK_INDEX].data[1],
  107. AA1[PICOPASS_CSN_BLOCK_INDEX].data[2],
  108. AA1[PICOPASS_CSN_BLOCK_INDEX].data[3],
  109. AA1[PICOPASS_CSN_BLOCK_INDEX].data[4],
  110. AA1[PICOPASS_CSN_BLOCK_INDEX].data[5],
  111. AA1[PICOPASS_CSN_BLOCK_INDEX].data[6],
  112. AA1[PICOPASS_CSN_BLOCK_INDEX].data[7]);
  113. rfalPicoPassReadBlockRes cfg = {0};
  114. err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
  115. memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
  116. FURI_LOG_D(
  117. TAG,
  118. "config %02x%02x%02x%02x%02x%02x%02x%02x",
  119. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0],
  120. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[1],
  121. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[2],
  122. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[3],
  123. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[4],
  124. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[5],
  125. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[6],
  126. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7]);
  127. rfalPicoPassReadBlockRes aia;
  128. err = rfalPicoPassPollerReadBlock(PICOPASS_AIA_BLOCK_INDEX, &aia);
  129. memcpy(AA1[PICOPASS_AIA_BLOCK_INDEX].data, aia.data, sizeof(aia.data));
  130. FURI_LOG_D(
  131. TAG,
  132. "aia %02x%02x%02x%02x%02x%02x%02x%02x",
  133. AA1[PICOPASS_AIA_BLOCK_INDEX].data[0],
  134. AA1[PICOPASS_AIA_BLOCK_INDEX].data[1],
  135. AA1[PICOPASS_AIA_BLOCK_INDEX].data[2],
  136. AA1[PICOPASS_AIA_BLOCK_INDEX].data[3],
  137. AA1[PICOPASS_AIA_BLOCK_INDEX].data[4],
  138. AA1[PICOPASS_AIA_BLOCK_INDEX].data[5],
  139. AA1[PICOPASS_AIA_BLOCK_INDEX].data[6],
  140. AA1[PICOPASS_AIA_BLOCK_INDEX].data[7]);
  141. return ERR_NONE;
  142. }
  143. ReturnCode picopass_read_card(PicopassBlock* AA1) {
  144. rfalPicoPassReadCheckRes rcRes;
  145. rfalPicoPassCheckRes chkRes;
  146. ReturnCode err;
  147. uint8_t div_key[8] = {0};
  148. uint8_t mac[4] = {0};
  149. uint8_t ccnr[12] = {0};
  150. err = rfalPicoPassPollerReadCheck(&rcRes);
  151. if(err != ERR_NONE) {
  152. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  153. return err;
  154. }
  155. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  156. loclass_diversifyKey(AA1[PICOPASS_CSN_BLOCK_INDEX].data, picopass_iclass_key, div_key);
  157. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  158. err = rfalPicoPassPollerCheck(mac, &chkRes);
  159. if(err != ERR_NONE) {
  160. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  161. return err;
  162. }
  163. size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
  164. AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
  165. PICOPASS_MAX_APP_LIMIT;
  166. for(size_t i = 2; i < app_limit; i++) {
  167. rfalPicoPassReadBlockRes block;
  168. err = rfalPicoPassPollerReadBlock(i, &block);
  169. if(err != ERR_NONE) {
  170. FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
  171. return err;
  172. }
  173. FURI_LOG_D(
  174. TAG,
  175. "rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
  176. i,
  177. block.data[0],
  178. block.data[1],
  179. block.data[2],
  180. block.data[3],
  181. block.data[4],
  182. block.data[5],
  183. block.data[6],
  184. block.data[7]);
  185. memcpy(AA1[i].data, block.data, sizeof(block.data));
  186. }
  187. return ERR_NONE;
  188. }
  189. ReturnCode picopass_write_card(PicopassBlock* AA1) {
  190. rfalPicoPassIdentifyRes idRes;
  191. rfalPicoPassSelectRes selRes;
  192. rfalPicoPassReadCheckRes rcRes;
  193. rfalPicoPassCheckRes chkRes;
  194. ReturnCode err;
  195. uint8_t div_key[8] = {0};
  196. uint8_t mac[4] = {0};
  197. uint8_t ccnr[12] = {0};
  198. err = rfalPicoPassPollerIdentify(&idRes);
  199. if(err != ERR_NONE) {
  200. FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err);
  201. return err;
  202. }
  203. err = rfalPicoPassPollerSelect(idRes.CSN, &selRes);
  204. if(err != ERR_NONE) {
  205. FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err);
  206. return err;
  207. }
  208. err = rfalPicoPassPollerReadCheck(&rcRes);
  209. if(err != ERR_NONE) {
  210. FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err);
  211. return err;
  212. }
  213. memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0
  214. loclass_diversifyKey(selRes.CSN, picopass_iclass_key, div_key);
  215. loclass_opt_doReaderMAC(ccnr, div_key, mac);
  216. err = rfalPicoPassPollerCheck(mac, &chkRes);
  217. if(err != ERR_NONE) {
  218. FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err);
  219. return err;
  220. }
  221. for(size_t i = 6; i < 10; i++) {
  222. FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", i);
  223. uint8_t data[9] = {0};
  224. data[0] = i;
  225. memcpy(data + 1, AA1[i].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
  226. loclass_doMAC_N(data, sizeof(data), div_key, mac);
  227. FURI_LOG_D(
  228. TAG,
  229. "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x",
  230. i,
  231. data[1],
  232. data[2],
  233. data[3],
  234. data[4],
  235. data[5],
  236. data[6],
  237. data[7],
  238. data[8],
  239. mac[0],
  240. mac[1],
  241. mac[2],
  242. mac[3]);
  243. err = rfalPicoPassPollerWriteBlock(i, AA1[i].data, mac);
  244. if(err != ERR_NONE) {
  245. FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err);
  246. return err;
  247. }
  248. }
  249. return ERR_NONE;
  250. }
  251. int32_t picopass_worker_task(void* context) {
  252. PicopassWorker* picopass_worker = context;
  253. picopass_worker_enable_field();
  254. if(picopass_worker->state == PicopassWorkerStateDetect) {
  255. picopass_worker_detect(picopass_worker);
  256. } else if(picopass_worker->state == PicopassWorkerStateWrite) {
  257. picopass_worker_write(picopass_worker);
  258. }
  259. picopass_worker_disable_field(ERR_NONE);
  260. picopass_worker_change_state(picopass_worker, PicopassWorkerStateReady);
  261. return 0;
  262. }
  263. void picopass_worker_detect(PicopassWorker* picopass_worker) {
  264. picopass_device_data_clear(picopass_worker->dev_data);
  265. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  266. PicopassBlock* AA1 = dev_data->AA1;
  267. PicopassPacs* pacs = &dev_data->pacs;
  268. ReturnCode err;
  269. // reset device data
  270. for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
  271. memset(AA1[i].data, 0, sizeof(AA1[i].data));
  272. }
  273. memset(pacs, 0, sizeof(PicopassPacs));
  274. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  275. while(picopass_worker->state == PicopassWorkerStateDetect) {
  276. if(picopass_detect_card(1000) == ERR_NONE) {
  277. // Process first found device
  278. err = picopass_read_preauth(AA1);
  279. if(err != ERR_NONE) {
  280. FURI_LOG_E(TAG, "picopass_read_preauth error %d", err);
  281. nextState = PicopassWorkerEventFail;
  282. }
  283. // Thank you proxmark!
  284. pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
  285. pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
  286. if(pacs->se_enabled) {
  287. FURI_LOG_D(TAG, "SE enabled");
  288. }
  289. err = picopass_read_card(AA1);
  290. if(err != ERR_NONE) {
  291. FURI_LOG_E(TAG, "picopass_read_card error %d", err);
  292. nextState = PicopassWorkerEventFail;
  293. }
  294. if(nextState == PicopassWorkerEventSuccess) {
  295. err = picopass_device_parse_credential(AA1, pacs);
  296. }
  297. if(err != ERR_NONE) {
  298. FURI_LOG_E(TAG, "picopass_device_parse_credential error %d", err);
  299. nextState = PicopassWorkerEventFail;
  300. }
  301. if(nextState == PicopassWorkerEventSuccess) {
  302. err = picopass_device_parse_wiegand(pacs->credential, &pacs->record);
  303. }
  304. if(err != ERR_NONE) {
  305. FURI_LOG_E(TAG, "picopass_device_parse_wiegand error %d", err);
  306. nextState = PicopassWorkerEventFail;
  307. }
  308. // Notify caller and exit
  309. if(picopass_worker->callback) {
  310. picopass_worker->callback(nextState, picopass_worker->context);
  311. }
  312. break;
  313. }
  314. furi_delay_ms(100);
  315. }
  316. }
  317. void picopass_worker_write(PicopassWorker* picopass_worker) {
  318. PicopassDeviceData* dev_data = picopass_worker->dev_data;
  319. PicopassBlock* AA1 = dev_data->AA1;
  320. ReturnCode err;
  321. PicopassWorkerEvent nextState = PicopassWorkerEventSuccess;
  322. while(picopass_worker->state == PicopassWorkerStateWrite) {
  323. if(picopass_detect_card(1000) == ERR_NONE) {
  324. err = picopass_write_card(AA1);
  325. if(err != ERR_NONE) {
  326. FURI_LOG_E(TAG, "picopass_write_card error %d", err);
  327. nextState = PicopassWorkerEventFail;
  328. }
  329. // Notify caller and exit
  330. if(picopass_worker->callback) {
  331. picopass_worker->callback(nextState, picopass_worker->context);
  332. }
  333. break;
  334. }
  335. furi_delay_ms(100);
  336. }
  337. }