mfkey32.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  1. #pragma GCC optimize("O3")
  2. #pragma GCC optimize("-funroll-all-loops")
  3. // TODO: Add keys to top of the user dictionary, not the bottom
  4. // TODO: More efficient dictionary bruteforce by scanning through hardcoded very common keys and previously found dictionary keys first?
  5. // (a cache for napi_key_already_found_for_nonce)
  6. #include <furi.h>
  7. #include <furi_hal.h>
  8. #include "time.h"
  9. #include <gui/gui.h>
  10. #include <gui/elements.h>
  11. #include <input/input.h>
  12. #include <stdlib.h>
  13. #include "mfkey32_icons.h"
  14. #include <inttypes.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdint.h>
  18. #include <unistd.h>
  19. #include <storage/storage.h>
  20. #include <lib/nfc/helpers/mf_classic_dict.h>
  21. #include <lib/toolbox/args.h>
  22. #include <lib/flipper_format/flipper_format.h>
  23. #include <dolphin/dolphin.h>
  24. #include <notification/notification_messages.h>
  25. #define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
  26. #define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
  27. #define MF_CLASSIC_NONCE_PATH EXT_PATH("nfc/.mfkey32.log")
  28. #define TAG "Mfkey32"
  29. #define NFC_MF_CLASSIC_KEY_LEN (13)
  30. #define MIN_RAM 115632
  31. #define LF_POLY_ODD (0x29CE5C)
  32. #define LF_POLY_EVEN (0x870804)
  33. #define CONST_M1_1 (LF_POLY_EVEN << 1 | 1)
  34. #define CONST_M2_1 (LF_POLY_ODD << 1)
  35. #define CONST_M1_2 (LF_POLY_ODD)
  36. #define CONST_M2_2 (LF_POLY_EVEN << 1 | 1)
  37. #define BIT(x, n) ((x) >> (n)&1)
  38. #define BEBIT(x, n) BIT(x, (n) ^ 24)
  39. #define SWAPENDIAN(x) \
  40. ((x) = ((x) >> 8 & 0xff00ff) | ((x)&0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
  41. //#define SIZEOF(arr) sizeof(arr) / sizeof(*arr)
  42. static int eta_round_time = 56;
  43. static int eta_total_time = 900;
  44. // MSB_LIMIT: Chunk size (out of 256)
  45. static int MSB_LIMIT = 16;
  46. struct Crypto1State {
  47. uint32_t odd, even;
  48. };
  49. struct Crypto1Params {
  50. uint64_t key;
  51. uint32_t nr0_enc, uid_xor_nt0, uid_xor_nt1, nr1_enc, p64b, ar1_enc;
  52. };
  53. struct Msb {
  54. int tail;
  55. uint32_t states[768];
  56. };
  57. typedef enum {
  58. EventTypeTick,
  59. EventTypeKey,
  60. } EventType;
  61. typedef struct {
  62. EventType type;
  63. InputEvent input;
  64. } PluginEvent;
  65. typedef enum {
  66. MissingNonces,
  67. ZeroNonces,
  68. } MfkeyError;
  69. typedef enum {
  70. Ready,
  71. Initializing,
  72. DictionaryAttack,
  73. MfkeyAttack,
  74. Complete,
  75. Error,
  76. Help,
  77. } MfkeyState;
  78. // TODO: Can we eliminate any of the members of this struct?
  79. typedef struct {
  80. FuriMutex* mutex;
  81. MfkeyError err;
  82. MfkeyState mfkey_state;
  83. int cracked;
  84. int unique_cracked;
  85. int num_completed;
  86. int total;
  87. int dict_count;
  88. int search;
  89. int eta_timestamp;
  90. int eta_total;
  91. int eta_round;
  92. bool is_thread_running;
  93. bool close_thread_please;
  94. FuriThread* mfkeythread;
  95. } ProgramState;
  96. // TODO: Merge this with Crypto1Params?
  97. typedef struct {
  98. uint32_t uid; // serial number
  99. uint32_t nt0; // tag challenge first
  100. uint32_t nt1; // tag challenge second
  101. uint32_t nr0_enc; // first encrypted reader challenge
  102. uint32_t ar0_enc; // first encrypted reader response
  103. uint32_t nr1_enc; // second encrypted reader challenge
  104. uint32_t ar1_enc; // second encrypted reader response
  105. } MfClassicNonce;
  106. typedef struct {
  107. Stream* stream;
  108. uint32_t total_nonces;
  109. MfClassicNonce* remaining_nonce_array;
  110. size_t remaining_nonces;
  111. } MfClassicNonceArray;
  112. struct MfClassicDict {
  113. Stream* stream;
  114. uint32_t total_keys;
  115. };
  116. static const uint8_t table[256] = {
  117. 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,
  118. 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
  119. 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
  120. 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,
  121. 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2,
  122. 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5,
  123. 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4,
  124. 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6,
  125. 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
  126. static const uint8_t lookup1[256] = {
  127. 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
  128. 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16,
  129. 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8,
  130. 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
  131. 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
  132. 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
  133. 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
  134. 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
  135. 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0,
  136. 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
  137. 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24};
  138. static const uint8_t lookup2[256] = {
  139. 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4,
  140. 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6,
  141. 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2,
  142. 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4,
  143. 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2,
  144. 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4,
  145. 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2,
  146. 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2,
  147. 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6};
  148. uint32_t prng_successor(uint32_t x, uint32_t n) {
  149. SWAPENDIAN(x);
  150. while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
  151. return SWAPENDIAN(x);
  152. }
  153. static inline int filter(uint32_t const x) {
  154. uint32_t f;
  155. f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff];
  156. f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
  157. return BIT(0xEC57E80A, f);
  158. }
  159. static inline uint8_t evenparity32(uint32_t x) {
  160. if((table[x & 0xff] + table[(x >> 8) & 0xff] + table[(x >> 16) & 0xff] + table[x >> 24]) % 2 ==
  161. 0) {
  162. return 0;
  163. } else {
  164. return 1;
  165. }
  166. //return ((table[x & 0xff] + table[(x >> 8) & 0xff] + table[(x >> 16) & 0xff] + table[x >> 24]) % 2) & 0xFF;
  167. }
  168. static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) {
  169. int p = data[item] >> 25;
  170. p = p << 1 | evenparity32(data[item] & mask1);
  171. p = p << 1 | evenparity32(data[item] & mask2);
  172. data[item] = p << 24 | (data[item] & 0xffffff);
  173. }
  174. void crypto1_get_lfsr(struct Crypto1State* state, uint64_t* lfsr) {
  175. int i;
  176. for(*lfsr = 0, i = 23; i >= 0; --i) {
  177. *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
  178. *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
  179. }
  180. }
  181. static inline uint32_t crypt_word(struct Crypto1State* s) {
  182. // "in" and "x" are always 0 (last iteration)
  183. uint32_t res_ret = 0;
  184. uint32_t feedin, t;
  185. for(int i = 0; i <= 31; i++) {
  186. res_ret |= (filter(s->odd) << (24 ^ i)); //-V629
  187. feedin = LF_POLY_EVEN & s->even;
  188. feedin ^= LF_POLY_ODD & s->odd;
  189. s->even = s->even << 1 | (evenparity32(feedin));
  190. t = s->odd, s->odd = s->even, s->even = t;
  191. }
  192. return res_ret;
  193. }
  194. static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x) {
  195. uint8_t ret;
  196. uint32_t feedin, t, next_in;
  197. for(int i = 0; i <= 31; i++) {
  198. next_in = BEBIT(in, i);
  199. ret = filter(s->odd);
  200. feedin = ret & (!!x);
  201. feedin ^= LF_POLY_EVEN & s->even;
  202. feedin ^= LF_POLY_ODD & s->odd;
  203. feedin ^= !!next_in;
  204. s->even = s->even << 1 | (evenparity32(feedin));
  205. t = s->odd, s->odd = s->even, s->even = t;
  206. }
  207. return;
  208. }
  209. static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) {
  210. uint8_t ret;
  211. uint32_t feedin, t, next_in;
  212. for(int i = 31; i >= 0; i--) {
  213. next_in = BEBIT(in, i);
  214. s->odd &= 0xffffff;
  215. t = s->odd, s->odd = s->even, s->even = t;
  216. ret = filter(s->odd);
  217. feedin = ret & (!!x);
  218. feedin ^= s->even & 1;
  219. feedin ^= LF_POLY_EVEN & (s->even >>= 1);
  220. feedin ^= LF_POLY_ODD & s->odd;
  221. feedin ^= !!next_in;
  222. s->even |= (evenparity32(feedin)) << 23;
  223. }
  224. return;
  225. }
  226. int key_already_found_for_nonce(
  227. uint64_t* keyarray,
  228. int keyarray_size,
  229. uint32_t uid_xor_nt1,
  230. uint32_t nr1_enc,
  231. uint32_t p64b,
  232. uint32_t ar1_enc) {
  233. for(int k = 0; k < keyarray_size; k++) {
  234. struct Crypto1State temp = {0, 0};
  235. for(int i = 0; i < 24; i++) {
  236. (&temp)->odd |= (BIT(keyarray[k], 2 * i + 1) << (i ^ 3));
  237. (&temp)->even |= (BIT(keyarray[k], 2 * i) << (i ^ 3));
  238. }
  239. crypt_word_noret(&temp, uid_xor_nt1, 0);
  240. crypt_word_noret(&temp, nr1_enc, 1);
  241. if(ar1_enc == (crypt_word(&temp) ^ p64b)) {
  242. return 1;
  243. }
  244. }
  245. return 0;
  246. }
  247. int check_state(struct Crypto1State* t, struct Crypto1Params* p) {
  248. if(!(t->odd | t->even)) return 0;
  249. rollback_word_noret(t, 0, 0);
  250. rollback_word_noret(t, p->nr0_enc, 1);
  251. rollback_word_noret(t, p->uid_xor_nt0, 0);
  252. struct Crypto1State temp = {t->odd, t->even};
  253. crypt_word_noret(t, p->uid_xor_nt1, 0);
  254. crypt_word_noret(t, p->nr1_enc, 1);
  255. if(p->ar1_enc == (crypt_word(t) ^ p->p64b)) {
  256. crypto1_get_lfsr(&temp, &(p->key));
  257. return 1;
  258. }
  259. return 0;
  260. }
  261. static inline int state_loop(unsigned int* states_buffer, int xks, int m1, int m2) {
  262. int states_tail = 0;
  263. int round = 0, s = 0, xks_bit = 0;
  264. for(round = 1; round <= 12; round++) {
  265. xks_bit = BIT(xks, round);
  266. for(s = 0; s <= states_tail; s++) {
  267. states_buffer[s] <<= 1;
  268. if((filter(states_buffer[s]) ^ filter(states_buffer[s] | 1)) != 0) {
  269. states_buffer[s] |= filter(states_buffer[s]) ^ xks_bit;
  270. if(round > 4) {
  271. update_contribution(states_buffer, s, m1, m2);
  272. }
  273. } else if(filter(states_buffer[s]) == xks_bit) {
  274. // TODO: Refactor
  275. if(round > 4) {
  276. states_buffer[++states_tail] = states_buffer[s + 1];
  277. states_buffer[s + 1] = states_buffer[s] | 1;
  278. update_contribution(states_buffer, s, m1, m2);
  279. s++;
  280. update_contribution(states_buffer, s, m1, m2);
  281. } else {
  282. states_buffer[++states_tail] = states_buffer[++s];
  283. states_buffer[s] = states_buffer[s - 1] | 1;
  284. }
  285. } else {
  286. states_buffer[s--] = states_buffer[states_tail--];
  287. }
  288. }
  289. }
  290. return states_tail;
  291. }
  292. int binsearch(unsigned int data[], int start, int stop) {
  293. int mid, val = data[stop] & 0xff000000;
  294. while(start != stop) {
  295. mid = (stop - start) >> 1;
  296. if((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000))
  297. stop = start + mid;
  298. else
  299. start += mid + 1;
  300. }
  301. return start;
  302. }
  303. void quicksort(unsigned int array[], int low, int high) {
  304. //if (SIZEOF(array) == 0)
  305. // return;
  306. if(low >= high) return;
  307. int middle = low + (high - low) / 2;
  308. unsigned int pivot = array[middle];
  309. int i = low, j = high;
  310. while(i <= j) {
  311. while(array[i] < pivot) {
  312. i++;
  313. }
  314. while(array[j] > pivot) {
  315. j--;
  316. }
  317. if(i <= j) { // swap
  318. int temp = array[i];
  319. array[i] = array[j];
  320. array[j] = temp;
  321. i++;
  322. j--;
  323. }
  324. }
  325. if(low < j) {
  326. quicksort(array, low, j);
  327. }
  328. if(high > i) {
  329. quicksort(array, i, high);
  330. }
  331. }
  332. int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2) {
  333. for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) {
  334. if((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) {
  335. data[tbl] |= filter(data[tbl]) ^ bit;
  336. update_contribution(data, tbl, m1, m2);
  337. } else if(filter(data[tbl]) == bit) {
  338. data[++end] = data[tbl + 1];
  339. data[tbl + 1] = data[tbl] | 1;
  340. update_contribution(data, tbl, m1, m2);
  341. tbl++;
  342. update_contribution(data, tbl, m1, m2);
  343. } else {
  344. data[tbl--] = data[end--];
  345. }
  346. }
  347. return end;
  348. }
  349. int old_recover(
  350. unsigned int odd[],
  351. int o_head,
  352. int o_tail,
  353. int oks,
  354. unsigned int even[],
  355. int e_head,
  356. int e_tail,
  357. int eks,
  358. int rem,
  359. int s,
  360. struct Crypto1Params* p,
  361. int first_run) {
  362. int o, e, i;
  363. if(rem == -1) {
  364. for(e = e_head; e <= e_tail; ++e) {
  365. even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN);
  366. for(o = o_head; o <= o_tail; ++o, ++s) {
  367. struct Crypto1State temp = {0, 0};
  368. temp.even = odd[o];
  369. temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD);
  370. if(check_state(&temp, p)) {
  371. return -1;
  372. }
  373. }
  374. }
  375. return s;
  376. }
  377. if(first_run == 0) {
  378. for(i = 0; (i < 4) && (rem-- != 0); i++) {
  379. oks >>= 1;
  380. eks >>= 1;
  381. o_tail = extend_table(
  382. odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1);
  383. if(o_head > o_tail) return s;
  384. e_tail =
  385. extend_table(even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1);
  386. if(e_head > e_tail) return s;
  387. }
  388. }
  389. first_run = 0;
  390. quicksort(odd, o_head, o_tail);
  391. quicksort(even, e_head, e_tail);
  392. while(o_tail >= o_head && e_tail >= e_head) {
  393. if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) {
  394. o_tail = binsearch(odd, o_head, o = o_tail);
  395. e_tail = binsearch(even, e_head, e = e_tail);
  396. s = old_recover(odd, o_tail--, o, oks, even, e_tail--, e, eks, rem, s, p, first_run);
  397. if(s == -1) {
  398. break;
  399. }
  400. } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) {
  401. o_tail = binsearch(odd, o_head, o_tail) - 1;
  402. } else {
  403. e_tail = binsearch(even, e_head, e_tail) - 1;
  404. }
  405. }
  406. return s;
  407. }
  408. static inline int sync_state(ProgramState* program_state) {
  409. int ts = furi_hal_rtc_get_timestamp();
  410. program_state->eta_round = program_state->eta_round - (ts - program_state->eta_timestamp);
  411. program_state->eta_total = program_state->eta_total - (ts - program_state->eta_timestamp);
  412. program_state->eta_timestamp = ts;
  413. if(program_state->close_thread_please) {
  414. return 1;
  415. }
  416. return 0;
  417. }
  418. int calculate_msb_tables(
  419. int oks,
  420. int eks,
  421. int msb_round,
  422. struct Crypto1Params* p,
  423. unsigned int* states_buffer,
  424. struct Msb* odd_msbs,
  425. struct Msb* even_msbs,
  426. unsigned int* temp_states_odd,
  427. unsigned int* temp_states_even,
  428. ProgramState* program_state) {
  429. //FURI_LOG_I(TAG, "MSB GO %i", msb_iter); // DEBUG
  430. unsigned int msb_head = (MSB_LIMIT * msb_round); // msb_iter ranges from 0 to (256/MSB_LIMIT)-1
  431. unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1));
  432. int states_tail = 0, tail = 0;
  433. int i = 0, j = 0, semi_state = 0, found = 0;
  434. unsigned int msb = 0;
  435. // TODO: Why is this necessary?
  436. memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb));
  437. memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb));
  438. for(semi_state = 1 << 20; semi_state >= 0; semi_state--) {
  439. if(semi_state % 32768 == 0) {
  440. if(sync_state(program_state) == 1) {
  441. return 0;
  442. }
  443. }
  444. if(filter(semi_state) == (oks & 1)) { //-V547
  445. states_buffer[0] = semi_state;
  446. states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1);
  447. for(i = states_tail; i >= 0; i--) {
  448. msb = states_buffer[i] >> 24;
  449. if((msb >= msb_head) && (msb < msb_tail)) {
  450. found = 0;
  451. for(j = 0; j < odd_msbs[msb - msb_head].tail - 1; j++) {
  452. if(odd_msbs[msb - msb_head].states[j] == states_buffer[i]) {
  453. found = 1;
  454. break;
  455. }
  456. }
  457. if(!found) {
  458. tail = odd_msbs[msb - msb_head].tail++;
  459. odd_msbs[msb - msb_head].states[tail] = states_buffer[i];
  460. }
  461. }
  462. }
  463. }
  464. if(filter(semi_state) == (eks & 1)) { //-V547
  465. states_buffer[0] = semi_state;
  466. states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2);
  467. for(i = 0; i <= states_tail; i++) {
  468. msb = states_buffer[i] >> 24;
  469. if((msb >= msb_head) && (msb < msb_tail)) {
  470. found = 0;
  471. for(j = 0; j < even_msbs[msb - msb_head].tail; j++) {
  472. if(even_msbs[msb - msb_head].states[j] == states_buffer[i]) {
  473. found = 1;
  474. break;
  475. }
  476. }
  477. if(!found) {
  478. tail = even_msbs[msb - msb_head].tail++;
  479. even_msbs[msb - msb_head].states[tail] = states_buffer[i];
  480. }
  481. }
  482. }
  483. }
  484. }
  485. oks >>= 12;
  486. eks >>= 12;
  487. for(i = 0; i < MSB_LIMIT; i++) {
  488. if(sync_state(program_state) == 1) {
  489. return 0;
  490. }
  491. // TODO: Why is this necessary?
  492. memset(temp_states_even, 0, sizeof(unsigned int) * (1280));
  493. memset(temp_states_odd, 0, sizeof(unsigned int) * (1280));
  494. memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int));
  495. memcpy(temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int));
  496. int res = old_recover(
  497. temp_states_odd,
  498. 0,
  499. odd_msbs[i].tail,
  500. oks,
  501. temp_states_even,
  502. 0,
  503. even_msbs[i].tail,
  504. eks,
  505. 3,
  506. 0,
  507. p,
  508. 1);
  509. if(res == -1) {
  510. return 1;
  511. }
  512. //odd_msbs[i].tail = 0;
  513. //even_msbs[i].tail = 0;
  514. }
  515. return 0;
  516. }
  517. bool recover(struct Crypto1Params* p, int ks2, ProgramState* program_state) {
  518. bool found = false;
  519. unsigned int* states_buffer = malloc(sizeof(unsigned int) * (2 << 9));
  520. struct Msb* odd_msbs = (struct Msb*)malloc(MSB_LIMIT * sizeof(struct Msb));
  521. struct Msb* even_msbs = (struct Msb*)malloc(MSB_LIMIT * sizeof(struct Msb));
  522. unsigned int* temp_states_odd = malloc(sizeof(unsigned int) * (1280));
  523. unsigned int* temp_states_even = malloc(sizeof(unsigned int) * (1280));
  524. int oks = 0, eks = 0;
  525. int i = 0, msb = 0;
  526. for(i = 31; i >= 0; i -= 2) {
  527. oks = oks << 1 | BEBIT(ks2, i);
  528. }
  529. for(i = 30; i >= 0; i -= 2) {
  530. eks = eks << 1 | BEBIT(ks2, i);
  531. }
  532. int bench_start = furi_hal_rtc_get_timestamp();
  533. program_state->eta_total = eta_total_time;
  534. program_state->eta_timestamp = bench_start;
  535. for(msb = 0; msb <= ((256 / MSB_LIMIT) - 1); msb++) {
  536. program_state->search = msb;
  537. program_state->eta_round = eta_round_time;
  538. program_state->eta_total = eta_total_time - (eta_round_time * msb);
  539. if(calculate_msb_tables(
  540. oks,
  541. eks,
  542. msb,
  543. p,
  544. states_buffer,
  545. odd_msbs,
  546. even_msbs,
  547. temp_states_odd,
  548. temp_states_even,
  549. program_state)) {
  550. int bench_stop = furi_hal_rtc_get_timestamp();
  551. FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start);
  552. found = true;
  553. break;
  554. }
  555. if(program_state->close_thread_please) {
  556. break;
  557. }
  558. }
  559. free(states_buffer);
  560. free(odd_msbs);
  561. free(even_msbs);
  562. free(temp_states_odd);
  563. free(temp_states_even);
  564. return found;
  565. }
  566. bool napi_mf_classic_dict_check_presence(MfClassicDictType dict_type) {
  567. Storage* storage = furi_record_open(RECORD_STORAGE);
  568. bool dict_present = false;
  569. if(dict_type == MfClassicDictTypeSystem) {
  570. dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK;
  571. } else if(dict_type == MfClassicDictTypeUser) {
  572. dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK;
  573. }
  574. furi_record_close(RECORD_STORAGE);
  575. return dict_present;
  576. }
  577. MfClassicDict* napi_mf_classic_dict_alloc(MfClassicDictType dict_type) {
  578. MfClassicDict* dict = malloc(sizeof(MfClassicDict));
  579. Storage* storage = furi_record_open(RECORD_STORAGE);
  580. dict->stream = buffered_file_stream_alloc(storage);
  581. furi_record_close(RECORD_STORAGE);
  582. bool dict_loaded = false;
  583. do {
  584. if(dict_type == MfClassicDictTypeSystem) {
  585. if(!buffered_file_stream_open(
  586. dict->stream,
  587. MF_CLASSIC_DICT_FLIPPER_PATH,
  588. FSAM_READ_WRITE,
  589. FSOM_OPEN_EXISTING)) {
  590. buffered_file_stream_close(dict->stream);
  591. break;
  592. }
  593. } else if(dict_type == MfClassicDictTypeUser) {
  594. if(!buffered_file_stream_open(
  595. dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
  596. buffered_file_stream_close(dict->stream);
  597. break;
  598. }
  599. }
  600. // Check for newline ending
  601. if(!stream_eof(dict->stream)) {
  602. if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break;
  603. uint8_t last_char = 0;
  604. if(stream_read(dict->stream, &last_char, 1) != 1) break;
  605. if(last_char != '\n') {
  606. FURI_LOG_D(TAG, "Adding new line ending");
  607. if(stream_write_char(dict->stream, '\n') != 1) break;
  608. }
  609. if(!stream_rewind(dict->stream)) break;
  610. }
  611. // Read total amount of keys
  612. FuriString* next_line;
  613. next_line = furi_string_alloc();
  614. while(true) {
  615. if(!stream_read_line(dict->stream, next_line)) {
  616. FURI_LOG_T(TAG, "No keys left in dict");
  617. break;
  618. }
  619. FURI_LOG_T(
  620. TAG,
  621. "Read line: %s, len: %zu",
  622. furi_string_get_cstr(next_line),
  623. furi_string_size(next_line));
  624. if(furi_string_get_char(next_line, 0) == '#') continue;
  625. if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
  626. dict->total_keys++;
  627. }
  628. furi_string_free(next_line);
  629. stream_rewind(dict->stream);
  630. dict_loaded = true;
  631. FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys);
  632. } while(false);
  633. if(!dict_loaded) {
  634. buffered_file_stream_close(dict->stream);
  635. free(dict);
  636. dict = NULL;
  637. }
  638. return dict;
  639. }
  640. bool napi_mf_classic_dict_add_key_str(MfClassicDict* dict, FuriString* key) {
  641. furi_assert(dict);
  642. furi_assert(dict->stream);
  643. FURI_LOG_I(TAG, "Saving key: %s", furi_string_get_cstr(key));
  644. furi_string_cat_printf(key, "\n");
  645. bool key_added = false;
  646. do {
  647. if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break;
  648. if(!stream_insert_string(dict->stream, key)) break;
  649. dict->total_keys++;
  650. key_added = true;
  651. } while(false);
  652. furi_string_left(key, 12);
  653. return key_added;
  654. }
  655. void napi_mf_classic_dict_free(MfClassicDict* dict) {
  656. furi_assert(dict);
  657. furi_assert(dict->stream);
  658. buffered_file_stream_close(dict->stream);
  659. stream_free(dict->stream);
  660. free(dict);
  661. }
  662. static void napi_mf_classic_dict_int_to_str(uint8_t* key_int, FuriString* key_str) {
  663. furi_string_reset(key_str);
  664. for(size_t i = 0; i < 6; i++) {
  665. furi_string_cat_printf(key_str, "%02X", key_int[i]);
  666. }
  667. }
  668. static void napi_mf_classic_dict_str_to_int(FuriString* key_str, uint64_t* key_int) {
  669. uint8_t key_byte_tmp;
  670. *key_int = 0ULL;
  671. for(uint8_t i = 0; i < 12; i += 2) {
  672. args_char_to_hex(
  673. furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
  674. *key_int |= (uint64_t)key_byte_tmp << (8 * (5 - i / 2));
  675. }
  676. }
  677. uint32_t napi_mf_classic_dict_get_total_keys(MfClassicDict* dict) {
  678. furi_assert(dict);
  679. return dict->total_keys;
  680. }
  681. bool napi_mf_classic_dict_rewind(MfClassicDict* dict) {
  682. furi_assert(dict);
  683. furi_assert(dict->stream);
  684. return stream_rewind(dict->stream);
  685. }
  686. bool napi_mf_classic_dict_get_next_key_str(MfClassicDict* dict, FuriString* key) {
  687. furi_assert(dict);
  688. furi_assert(dict->stream);
  689. bool key_read = false;
  690. furi_string_reset(key);
  691. while(!key_read) {
  692. if(!stream_read_line(dict->stream, key)) break;
  693. if(furi_string_get_char(key, 0) == '#') continue;
  694. if(furi_string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue;
  695. furi_string_left(key, 12);
  696. key_read = true;
  697. }
  698. return key_read;
  699. }
  700. bool napi_mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) {
  701. furi_assert(dict);
  702. furi_assert(dict->stream);
  703. FuriString* temp_key;
  704. temp_key = furi_string_alloc();
  705. bool key_read = napi_mf_classic_dict_get_next_key_str(dict, temp_key);
  706. if(key_read) {
  707. napi_mf_classic_dict_str_to_int(temp_key, key);
  708. }
  709. furi_string_free(temp_key);
  710. return key_read;
  711. }
  712. bool napi_mf_classic_dict_is_key_present_str(MfClassicDict* dict, FuriString* key) {
  713. furi_assert(dict);
  714. furi_assert(dict->stream);
  715. FuriString* next_line;
  716. next_line = furi_string_alloc();
  717. bool key_found = false;
  718. stream_rewind(dict->stream);
  719. while(!key_found) { //-V654
  720. if(!stream_read_line(dict->stream, next_line)) break;
  721. if(furi_string_get_char(next_line, 0) == '#') continue;
  722. if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
  723. furi_string_left(next_line, 12);
  724. if(!furi_string_equal(key, next_line)) continue;
  725. key_found = true;
  726. }
  727. furi_string_free(next_line);
  728. return key_found;
  729. }
  730. bool napi_mf_classic_dict_is_key_present(MfClassicDict* dict, uint8_t* key) {
  731. FuriString* temp_key;
  732. temp_key = furi_string_alloc();
  733. napi_mf_classic_dict_int_to_str(key, temp_key);
  734. bool key_found = napi_mf_classic_dict_is_key_present_str(dict, temp_key);
  735. furi_string_free(temp_key);
  736. return key_found;
  737. }
  738. bool napi_key_already_found_for_nonce(
  739. MfClassicDict* dict,
  740. uint32_t uid_xor_nt1,
  741. uint32_t nr1_enc,
  742. uint32_t p64b,
  743. uint32_t ar1_enc) {
  744. bool found = false;
  745. uint64_t k = 0;
  746. napi_mf_classic_dict_rewind(dict);
  747. while(napi_mf_classic_dict_get_next_key(dict, &k)) {
  748. struct Crypto1State temp = {0, 0};
  749. int i;
  750. for(i = 0; i < 24; i++) {
  751. (&temp)->odd |= (BIT(k, 2 * i + 1) << (i ^ 3));
  752. (&temp)->even |= (BIT(k, 2 * i) << (i ^ 3));
  753. }
  754. crypt_word_noret(&temp, uid_xor_nt1, 0);
  755. crypt_word_noret(&temp, nr1_enc, 1);
  756. if(ar1_enc == (crypt_word(&temp) ^ p64b)) {
  757. found = true;
  758. break;
  759. }
  760. }
  761. return found;
  762. }
  763. bool napi_mf_classic_nonces_check_presence() {
  764. Storage* storage = furi_record_open(RECORD_STORAGE);
  765. bool nonces_present = storage_common_stat(storage, MF_CLASSIC_NONCE_PATH, NULL) == FSE_OK;
  766. furi_record_close(RECORD_STORAGE);
  767. return nonces_present;
  768. }
  769. MfClassicNonceArray* napi_mf_classic_nonce_array_alloc(
  770. MfClassicDict* system_dict,
  771. bool system_dict_exists,
  772. MfClassicDict* user_dict,
  773. ProgramState* program_state) {
  774. MfClassicNonceArray* nonce_array = malloc(sizeof(MfClassicNonceArray));
  775. MfClassicNonce* remaining_nonce_array_init = malloc(sizeof(MfClassicNonce) * 1);
  776. nonce_array->remaining_nonce_array = remaining_nonce_array_init;
  777. Storage* storage = furi_record_open(RECORD_STORAGE);
  778. nonce_array->stream = buffered_file_stream_alloc(storage);
  779. furi_record_close(RECORD_STORAGE);
  780. bool array_loaded = false;
  781. do {
  782. // https://github.com/flipperdevices/flipperzero-firmware/blob/5134f44c09d39344a8747655c0d59864bb574b96/applications/services/storage/filesystem_api_defines.h#L8-L22
  783. if(!buffered_file_stream_open(
  784. nonce_array->stream, MF_CLASSIC_NONCE_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
  785. buffered_file_stream_close(nonce_array->stream);
  786. break;
  787. }
  788. // Check for newline ending
  789. if(!stream_eof(nonce_array->stream)) {
  790. if(!stream_seek(nonce_array->stream, -1, StreamOffsetFromEnd)) break;
  791. uint8_t last_char = 0;
  792. if(stream_read(nonce_array->stream, &last_char, 1) != 1) break;
  793. if(last_char != '\n') {
  794. FURI_LOG_D(TAG, "Adding new line ending");
  795. if(stream_write_char(nonce_array->stream, '\n') != 1) break;
  796. }
  797. if(!stream_rewind(nonce_array->stream)) break;
  798. }
  799. // Read total amount of nonces
  800. FuriString* next_line;
  801. next_line = furi_string_alloc();
  802. while(!(program_state->close_thread_please)) {
  803. if(!stream_read_line(nonce_array->stream, next_line)) {
  804. FURI_LOG_T(TAG, "No nonces left");
  805. break;
  806. }
  807. FURI_LOG_T(
  808. TAG,
  809. "Read line: %s, len: %zu",
  810. furi_string_get_cstr(next_line),
  811. furi_string_size(next_line));
  812. if(!furi_string_start_with_str(next_line, "Sec")) continue;
  813. const char* next_line_cstr = furi_string_get_cstr(next_line);
  814. MfClassicNonce res = {0};
  815. int i = 0;
  816. char* endptr;
  817. for(i = 0; i <= 17; i++) {
  818. if(i != 0) {
  819. next_line_cstr = strchr(next_line_cstr, ' ');
  820. if(next_line_cstr) {
  821. next_line_cstr++;
  822. } else {
  823. break;
  824. }
  825. }
  826. unsigned long value = strtoul(next_line_cstr, &endptr, 16);
  827. switch(i) {
  828. case 5:
  829. res.uid = value;
  830. break;
  831. case 7:
  832. res.nt0 = value;
  833. break;
  834. case 9:
  835. res.nr0_enc = value;
  836. break;
  837. case 11:
  838. res.ar0_enc = value;
  839. break;
  840. case 13:
  841. res.nt1 = value;
  842. break;
  843. case 15:
  844. res.nr1_enc = value;
  845. break;
  846. case 17:
  847. res.ar1_enc = value;
  848. break;
  849. default:
  850. break; // Do nothing
  851. }
  852. next_line_cstr = endptr;
  853. }
  854. (program_state->total)++;
  855. uint32_t p64b = prng_successor(res.nt1, 64);
  856. if((system_dict_exists &&
  857. napi_key_already_found_for_nonce(
  858. system_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc)) ||
  859. (napi_key_already_found_for_nonce(
  860. user_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc))) {
  861. (program_state->cracked)++;
  862. (program_state->num_completed)++;
  863. continue;
  864. }
  865. FURI_LOG_I(TAG, "No key found for %8lx %8lx", res.uid, res.ar1_enc);
  866. // TODO: Refactor
  867. nonce_array->remaining_nonce_array = realloc( //-V701
  868. nonce_array->remaining_nonce_array,
  869. sizeof(MfClassicNonce) * ((nonce_array->remaining_nonces) + 1));
  870. nonce_array->remaining_nonces++;
  871. nonce_array->remaining_nonce_array[(nonce_array->remaining_nonces) - 1] = res;
  872. nonce_array->total_nonces++;
  873. }
  874. furi_string_free(next_line);
  875. buffered_file_stream_close(nonce_array->stream);
  876. array_loaded = true;
  877. FURI_LOG_I(TAG, "Loaded %lu nonces", nonce_array->total_nonces);
  878. } while(false);
  879. if(!array_loaded) {
  880. free(nonce_array);
  881. nonce_array = NULL;
  882. }
  883. return nonce_array;
  884. }
  885. void napi_mf_classic_nonce_array_free(MfClassicNonceArray* nonce_array) {
  886. furi_assert(nonce_array);
  887. furi_assert(nonce_array->stream);
  888. buffered_file_stream_close(nonce_array->stream);
  889. stream_free(nonce_array->stream);
  890. free(nonce_array);
  891. }
  892. static void finished_beep() {
  893. // Beep to indicate completion
  894. NotificationApp* notification = furi_record_open("notification");
  895. notification_message(notification, &sequence_audiovisual_alert);
  896. notification_message(notification, &sequence_display_backlight_on);
  897. furi_record_close("notification");
  898. }
  899. void mfkey32(ProgramState* program_state) {
  900. uint64_t found_key; // recovered key
  901. size_t keyarray_size = 0;
  902. uint64_t* keyarray = malloc(sizeof(uint64_t) * 1);
  903. uint32_t i = 0, j = 0;
  904. // Check for nonces
  905. if(!napi_mf_classic_nonces_check_presence()) {
  906. program_state->err = MissingNonces;
  907. program_state->mfkey_state = Error;
  908. free(keyarray);
  909. return;
  910. }
  911. // Read dictionaries (optional)
  912. MfClassicDict* system_dict = {0};
  913. bool system_dict_exists = napi_mf_classic_dict_check_presence(MfClassicDictTypeSystem);
  914. MfClassicDict* user_dict = {0};
  915. bool user_dict_exists = napi_mf_classic_dict_check_presence(MfClassicDictTypeUser);
  916. uint32_t total_dict_keys = 0;
  917. if(system_dict_exists) {
  918. system_dict = napi_mf_classic_dict_alloc(MfClassicDictTypeSystem);
  919. total_dict_keys += napi_mf_classic_dict_get_total_keys(system_dict);
  920. }
  921. user_dict = napi_mf_classic_dict_alloc(MfClassicDictTypeUser);
  922. if(user_dict_exists) {
  923. total_dict_keys += napi_mf_classic_dict_get_total_keys(user_dict);
  924. }
  925. user_dict_exists = true;
  926. program_state->dict_count = total_dict_keys;
  927. program_state->mfkey_state = DictionaryAttack;
  928. // Read nonces
  929. MfClassicNonceArray* nonce_arr;
  930. nonce_arr = napi_mf_classic_nonce_array_alloc(
  931. system_dict, system_dict_exists, user_dict, program_state);
  932. if(system_dict_exists) {
  933. napi_mf_classic_dict_free(system_dict);
  934. }
  935. if(nonce_arr->total_nonces == 0) {
  936. // Nothing to crack
  937. program_state->err = ZeroNonces;
  938. program_state->mfkey_state = Error;
  939. napi_mf_classic_nonce_array_free(nonce_arr);
  940. napi_mf_classic_dict_free(user_dict);
  941. free(keyarray);
  942. return;
  943. }
  944. if(memmgr_get_free_heap() < MIN_RAM) {
  945. // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed
  946. eta_round_time *= 2;
  947. eta_total_time *= 2;
  948. MSB_LIMIT /= 2;
  949. }
  950. program_state->mfkey_state = MfkeyAttack;
  951. // TODO: Work backwards on this array and free memory
  952. for(i = 0; i < nonce_arr->total_nonces; i++) {
  953. MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i];
  954. uint32_t p64 = prng_successor(next_nonce.nt0, 64);
  955. uint32_t p64b = prng_successor(next_nonce.nt1, 64);
  956. if(key_already_found_for_nonce(
  957. keyarray,
  958. keyarray_size,
  959. next_nonce.uid ^ next_nonce.nt1,
  960. next_nonce.nr1_enc,
  961. p64b,
  962. next_nonce.ar1_enc)) {
  963. nonce_arr->remaining_nonces--;
  964. (program_state->cracked)++;
  965. (program_state->num_completed)++;
  966. continue;
  967. }
  968. FURI_LOG_I(TAG, "Cracking %8lx %8lx", next_nonce.uid, next_nonce.ar1_enc);
  969. struct Crypto1Params p = {
  970. 0,
  971. next_nonce.nr0_enc,
  972. next_nonce.uid ^ next_nonce.nt0,
  973. next_nonce.uid ^ next_nonce.nt1,
  974. next_nonce.nr1_enc,
  975. p64b,
  976. next_nonce.ar1_enc};
  977. if(!recover(&p, next_nonce.ar0_enc ^ p64, program_state)) {
  978. if(program_state->close_thread_please) {
  979. break;
  980. }
  981. // No key found in recover()
  982. (program_state->num_completed)++;
  983. continue;
  984. }
  985. (program_state->cracked)++;
  986. (program_state->num_completed)++;
  987. found_key = p.key;
  988. bool already_found = false;
  989. for(j = 0; j < keyarray_size; j++) {
  990. if(keyarray[j] == found_key) {
  991. already_found = true;
  992. break;
  993. }
  994. }
  995. if(already_found == false) {
  996. // New key
  997. keyarray = realloc(keyarray, sizeof(uint64_t) * (keyarray_size + 1)); //-V701
  998. keyarray_size += 1;
  999. keyarray[keyarray_size - 1] = found_key;
  1000. (program_state->unique_cracked)++;
  1001. }
  1002. }
  1003. // TODO: Update display to show all keys were found
  1004. // TODO: Prepend found key(s) to user dictionary file
  1005. //FURI_LOG_I(TAG, "Unique keys found:");
  1006. for(i = 0; i < keyarray_size; i++) {
  1007. //FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]);
  1008. FuriString* temp_key = furi_string_alloc();
  1009. furi_string_cat_printf(temp_key, "%012" PRIX64, keyarray[i]);
  1010. napi_mf_classic_dict_add_key_str(user_dict, temp_key);
  1011. furi_string_free(temp_key);
  1012. }
  1013. if(keyarray_size > 0) {
  1014. // TODO: Should we use DolphinDeedNfcMfcAdd?
  1015. dolphin_deed(DolphinDeedNfcMfcAdd);
  1016. }
  1017. napi_mf_classic_nonce_array_free(nonce_arr);
  1018. napi_mf_classic_dict_free(user_dict);
  1019. free(keyarray);
  1020. //FURI_LOG_I(TAG, "mfkey32 function completed normally"); // DEBUG
  1021. program_state->mfkey_state = Complete;
  1022. // No need to alert the user if they asked it to stop
  1023. if(!(program_state->close_thread_please)) {
  1024. finished_beep();
  1025. }
  1026. return;
  1027. }
  1028. // Screen is 128x64 px
  1029. static void render_callback(Canvas* const canvas, void* ctx) {
  1030. furi_assert(ctx);
  1031. ProgramState* program_state = ctx;
  1032. furi_mutex_acquire(program_state->mutex, FuriWaitForever);
  1033. char draw_str[44] = {};
  1034. canvas_clear(canvas);
  1035. canvas_draw_frame(canvas, 0, 0, 128, 64);
  1036. canvas_draw_frame(canvas, 0, 15, 128, 64);
  1037. canvas_set_font(canvas, FontPrimary);
  1038. canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "Mfkey32");
  1039. canvas_draw_icon(canvas, 114, 4, &I_mfkey);
  1040. if(program_state->is_thread_running && program_state->mfkey_state == MfkeyAttack) {
  1041. float eta_round = (float)1 - ((float)program_state->eta_round / (float)eta_round_time);
  1042. float eta_total = (float)1 - ((float)program_state->eta_total / (float)eta_total_time);
  1043. float progress = (float)program_state->num_completed / (float)program_state->total;
  1044. if(eta_round < 0) {
  1045. // Round ETA miscalculated
  1046. eta_round = 1;
  1047. program_state->eta_round = 0;
  1048. }
  1049. if(eta_total < 0) {
  1050. // Total ETA miscalculated
  1051. eta_total = 1;
  1052. program_state->eta_total = 0;
  1053. }
  1054. canvas_set_font(canvas, FontSecondary);
  1055. snprintf(
  1056. draw_str,
  1057. sizeof(draw_str),
  1058. "Cracking: %d/%d - in prog.",
  1059. program_state->num_completed,
  1060. program_state->total);
  1061. elements_progress_bar_with_text(canvas, 5, 18, 118, progress, draw_str);
  1062. snprintf(
  1063. draw_str,
  1064. sizeof(draw_str),
  1065. "Round: %d/%d - ETA %02d Sec",
  1066. (program_state->search) + 1, // Zero indexed
  1067. 256 / MSB_LIMIT,
  1068. program_state->eta_round);
  1069. elements_progress_bar_with_text(canvas, 5, 31, 118, eta_round, draw_str);
  1070. snprintf(draw_str, sizeof(draw_str), "Total ETA %03d Sec", program_state->eta_total);
  1071. elements_progress_bar_with_text(canvas, 5, 44, 118, eta_total, draw_str);
  1072. } else if(program_state->is_thread_running && program_state->mfkey_state == DictionaryAttack) {
  1073. canvas_set_font(canvas, FontSecondary);
  1074. snprintf(
  1075. draw_str, sizeof(draw_str), "Dict solves: %d (in progress)", program_state->cracked);
  1076. canvas_draw_str_aligned(canvas, 10, 18, AlignLeft, AlignTop, draw_str);
  1077. snprintf(draw_str, sizeof(draw_str), "Keys in dict: %d", program_state->dict_count);
  1078. canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str);
  1079. } else if(program_state->mfkey_state == Complete) {
  1080. // TODO: Scrollable list view to see cracked keys if user presses down
  1081. elements_progress_bar_with_text(canvas, 5, 18, 118, 1, draw_str);
  1082. canvas_set_font(canvas, FontSecondary);
  1083. snprintf(draw_str, sizeof(draw_str), "Complete");
  1084. canvas_draw_str_aligned(canvas, 40, 31, AlignLeft, AlignTop, draw_str);
  1085. snprintf(
  1086. draw_str,
  1087. sizeof(draw_str),
  1088. "Keys added to user dict: %d",
  1089. program_state->unique_cracked);
  1090. canvas_draw_str_aligned(canvas, 10, 41, AlignLeft, AlignTop, draw_str);
  1091. } else if(program_state->mfkey_state == Ready) {
  1092. canvas_set_font(canvas, FontSecondary);
  1093. canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready");
  1094. elements_button_center(canvas, "Start");
  1095. elements_button_right(canvas, "Help");
  1096. } else if(program_state->mfkey_state == Help) {
  1097. canvas_set_font(canvas, FontSecondary);
  1098. canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces using");
  1099. canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "Detect Reader.");
  1100. canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "Developers: noproto, AG");
  1101. canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "Thanks: bettse");
  1102. } else if(program_state->mfkey_state == Error) {
  1103. canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Error");
  1104. canvas_set_font(canvas, FontSecondary);
  1105. if(program_state->err == MissingNonces) {
  1106. canvas_draw_str_aligned(canvas, 25, 36, AlignLeft, AlignTop, "No nonces found");
  1107. } else if(program_state->err == ZeroNonces) {
  1108. canvas_draw_str_aligned(canvas, 15, 36, AlignLeft, AlignTop, "Nonces already cracked");
  1109. } else {
  1110. // Unhandled error
  1111. }
  1112. } else {
  1113. // Unhandled program state
  1114. }
  1115. furi_mutex_release(program_state->mutex);
  1116. }
  1117. static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
  1118. furi_assert(event_queue);
  1119. PluginEvent event = {.type = EventTypeKey, .input = *input_event};
  1120. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  1121. }
  1122. static void mfkey32_state_init(ProgramState* program_state) {
  1123. program_state->is_thread_running = false;
  1124. program_state->mfkey_state = Ready;
  1125. program_state->cracked = 0;
  1126. program_state->unique_cracked = 0;
  1127. program_state->num_completed = 0;
  1128. program_state->total = 0;
  1129. program_state->dict_count = 0;
  1130. }
  1131. // Entrypoint for worker thread
  1132. static int32_t mfkey32_worker_thread(void* ctx) {
  1133. ProgramState* program_state = ctx;
  1134. program_state->is_thread_running = true;
  1135. program_state->mfkey_state = Initializing;
  1136. //FURI_LOG_I(TAG, "Hello from the mfkey32 worker thread"); // DEBUG
  1137. mfkey32(program_state);
  1138. program_state->is_thread_running = false;
  1139. return 0;
  1140. }
  1141. void start_mfkey32_thread(ProgramState* program_state) {
  1142. if(!program_state->is_thread_running) {
  1143. furi_thread_start(program_state->mfkeythread);
  1144. }
  1145. }
  1146. int32_t mfkey32_main() {
  1147. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
  1148. ProgramState* program_state = malloc(sizeof(ProgramState));
  1149. mfkey32_state_init(program_state);
  1150. program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  1151. if(!program_state->mutex) {
  1152. FURI_LOG_E(TAG, "cannot create mutex\r\n");
  1153. free(program_state);
  1154. return 255;
  1155. }
  1156. // Set system callbacks
  1157. ViewPort* view_port = view_port_alloc();
  1158. view_port_draw_callback_set(view_port, render_callback, program_state);
  1159. view_port_input_callback_set(view_port, input_callback, event_queue);
  1160. // Open GUI and register view_port
  1161. Gui* gui = furi_record_open(RECORD_GUI);
  1162. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  1163. program_state->mfkeythread = furi_thread_alloc();
  1164. furi_thread_set_name(program_state->mfkeythread, "Mfkey32 Worker");
  1165. furi_thread_set_stack_size(program_state->mfkeythread, 2048);
  1166. furi_thread_set_context(program_state->mfkeythread, program_state);
  1167. furi_thread_set_callback(program_state->mfkeythread, mfkey32_worker_thread);
  1168. PluginEvent event;
  1169. for(bool main_loop = true; main_loop;) {
  1170. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
  1171. furi_mutex_acquire(program_state->mutex, FuriWaitForever);
  1172. if(event_status == FuriStatusOk) {
  1173. // press events
  1174. if(event.type == EventTypeKey) {
  1175. if(event.input.type == InputTypePress) {
  1176. switch(event.input.key) {
  1177. case InputKeyUp:
  1178. break;
  1179. case InputKeyDown:
  1180. break;
  1181. case InputKeyRight:
  1182. if(!program_state->is_thread_running &&
  1183. program_state->mfkey_state == Ready) {
  1184. program_state->mfkey_state = Help;
  1185. view_port_update(view_port);
  1186. }
  1187. break;
  1188. case InputKeyLeft:
  1189. break;
  1190. case InputKeyOk:
  1191. if(!program_state->is_thread_running &&
  1192. program_state->mfkey_state == Ready) {
  1193. start_mfkey32_thread(program_state);
  1194. view_port_update(view_port);
  1195. }
  1196. break;
  1197. case InputKeyBack:
  1198. if(!program_state->is_thread_running &&
  1199. program_state->mfkey_state == Help) {
  1200. program_state->mfkey_state = Ready;
  1201. view_port_update(view_port);
  1202. } else {
  1203. program_state->close_thread_please = true;
  1204. if(program_state->is_thread_running && program_state->mfkeythread) {
  1205. // Wait until thread is finished
  1206. furi_thread_join(program_state->mfkeythread);
  1207. }
  1208. program_state->close_thread_please = false;
  1209. main_loop = false;
  1210. }
  1211. break;
  1212. default:
  1213. break;
  1214. }
  1215. }
  1216. }
  1217. }
  1218. furi_mutex_release(program_state->mutex);
  1219. view_port_update(view_port);
  1220. }
  1221. furi_thread_free(program_state->mfkeythread);
  1222. view_port_enabled_set(view_port, false);
  1223. gui_remove_view_port(gui, view_port);
  1224. furi_record_close("gui");
  1225. view_port_free(view_port);
  1226. furi_message_queue_free(event_queue);
  1227. furi_mutex_free(program_state->mutex);
  1228. free(program_state);
  1229. return 0;
  1230. }