subghz_protocol_keeloq.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. #include "subghz_protocol_keeloq.h"
  2. #include "subghz_protocol_keeloq_common.h"
  3. #include "../subghz_keystore.h"
  4. #include <furi.h>
  5. #include <m-string.h>
  6. struct SubGhzProtocolKeeloq {
  7. SubGhzProtocolCommon common;
  8. SubGhzKeystore* keystore;
  9. const char* manufacture_name;
  10. };
  11. SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) {
  12. SubGhzProtocolKeeloq* instance = furi_alloc(sizeof(SubGhzProtocolKeeloq));
  13. instance->keystore = keystore;
  14. instance->common.name = "KeeLoq";
  15. instance->common.code_min_count_bit_for_found = 64;
  16. instance->common.te_short = 400;
  17. instance->common.te_long = 800;
  18. instance->common.te_delta = 140;
  19. instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC;
  20. instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str;
  21. instance->common.to_save_string =
  22. (SubGhzProtocolCommonGetStrSave)subghz_protocol_keeloq_to_save_str;
  23. instance->common.to_load_protocol_from_file =
  24. (SubGhzProtocolCommonLoadFromFile)subghz_protocol_keeloq_to_load_protocol_from_file;
  25. instance->common.to_load_protocol =
  26. (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_keeloq_to_load_protocol;
  27. instance->common.get_upload_protocol =
  28. (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_keeloq_send_key;
  29. return instance;
  30. }
  31. void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance) {
  32. furi_assert(instance);
  33. free(instance);
  34. }
  35. /** Checking the accepted code against the database manafacture key
  36. *
  37. * @param instance SubGhzProtocolKeeloq instance
  38. * @param fix fix part of the parcel
  39. * @param hop hop encrypted part of the parcel
  40. * @return true on successful search
  41. */
  42. uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
  43. SubGhzProtocolKeeloq* instance,
  44. uint32_t fix,
  45. uint32_t hop) {
  46. uint16_t end_serial = (uint16_t)(fix & 0x3FF);
  47. uint8_t btn = (uint8_t)(fix >> 28);
  48. uint32_t decrypt = 0;
  49. uint64_t man_normal_learning;
  50. for
  51. M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
  52. switch(manufacture_code->type) {
  53. case KEELOQ_LEARNING_SIMPLE:
  54. //Simple Learning
  55. decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
  56. if((decrypt >> 28 == btn) &&
  57. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  58. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  59. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  60. instance->common.cnt = decrypt & 0x0000FFFF;
  61. return 1;
  62. }
  63. break;
  64. case KEELOQ_LEARNING_NORMAL:
  65. // Normal_Learning
  66. // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
  67. man_normal_learning =
  68. subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
  69. decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
  70. if((decrypt >> 28 == btn) &&
  71. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  72. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  73. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  74. instance->common.cnt = decrypt & 0x0000FFFF;
  75. return 1;
  76. }
  77. break;
  78. case KEELOQ_LEARNING_UNKNOWN:
  79. // Simple Learning
  80. decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
  81. if((decrypt >> 28 == btn) &&
  82. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  83. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  84. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  85. instance->common.cnt = decrypt & 0x0000FFFF;
  86. return 1;
  87. }
  88. // Check for mirrored man
  89. uint64_t man_rev = 0;
  90. uint64_t man_rev_byte = 0;
  91. for(uint8_t i = 0; i < 64; i += 8) {
  92. man_rev_byte = (uint8_t)(manufacture_code->key >> i);
  93. man_rev = man_rev | man_rev_byte << (56 - i);
  94. }
  95. decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
  96. if((decrypt >> 28 == btn) &&
  97. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  98. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  99. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  100. instance->common.cnt = decrypt & 0x0000FFFF;
  101. return 1;
  102. }
  103. //###########################
  104. // Normal_Learning
  105. // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
  106. man_normal_learning =
  107. subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
  108. decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
  109. if((decrypt >> 28 == btn) &&
  110. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  111. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  112. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  113. instance->common.cnt = decrypt & 0x0000FFFF;
  114. return 1;
  115. }
  116. // Check for mirrored man
  117. man_rev = 0;
  118. man_rev_byte = 0;
  119. for(uint8_t i = 0; i < 64; i += 8) {
  120. man_rev_byte = (uint8_t)(manufacture_code->key >> i);
  121. man_rev = man_rev | man_rev_byte << (56 - i);
  122. }
  123. man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
  124. decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
  125. if((decrypt >> 28 == btn) &&
  126. (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) ||
  127. ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) {
  128. instance->manufacture_name = string_get_cstr(manufacture_code->name);
  129. instance->common.cnt = decrypt & 0x0000FFFF;
  130. return 1;
  131. }
  132. break;
  133. }
  134. }
  135. instance->manufacture_name = "Unknown";
  136. instance->common.cnt = 0;
  137. return 0;
  138. }
  139. /** Analysis of received data
  140. *
  141. * @param instance SubGhzProtocolKeeloq instance
  142. */
  143. void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instance) {
  144. uint64_t key = subghz_protocol_common_reverse_key(
  145. instance->common.code_last_found, instance->common.code_last_count_bit);
  146. uint32_t key_fix = key >> 32;
  147. uint32_t key_hop = key & 0x00000000ffffffff;
  148. // Check key AN-Motors
  149. if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
  150. (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
  151. instance->manufacture_name = "AN-Motors";
  152. instance->common.cnt = key_hop >> 16;
  153. } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) {
  154. instance->manufacture_name = "HCS101";
  155. instance->common.cnt = key_hop >> 16;
  156. } else {
  157. subghz_protocol_keeloq_check_remote_controller_selector(instance, key_fix, key_hop);
  158. }
  159. instance->common.serial = key_fix & 0x0FFFFFFF;
  160. instance->common.btn = key_fix >> 28;
  161. }
  162. const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context) {
  163. SubGhzProtocolKeeloq* instance = context;
  164. subghz_protocol_keeloq_check_remote_controller(instance);
  165. return instance->manufacture_name;
  166. }
  167. const char* subghz_protocol_keeloq_get_manufacture_name(void* context) {
  168. SubGhzProtocolKeeloq* instance = context;
  169. return instance->manufacture_name;
  170. }
  171. bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) {
  172. SubGhzProtocolKeeloq* instance = context;
  173. instance->manufacture_name = manufacture_name;
  174. int res = 0;
  175. for
  176. M_EACH(
  177. manufacture_code,
  178. *subghz_keystore_get_data(instance->keystore),
  179. SubGhzKeyArray_t) {
  180. res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
  181. if(res == 0) return true;
  182. }
  183. instance->manufacture_name = "Unknown";
  184. return false;
  185. }
  186. uint64_t subghz_protocol_keeloq_gen_key(void* context) {
  187. SubGhzProtocolKeeloq* instance = context;
  188. uint32_t fix = instance->common.btn << 28 | instance->common.serial;
  189. uint32_t decrypt = instance->common.btn << 28 | (instance->common.serial & 0x3FF) << 16 |
  190. instance->common.cnt;
  191. uint32_t hop = 0;
  192. uint64_t man_normal_learning = 0;
  193. int res = 0;
  194. for
  195. M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
  196. res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
  197. if(res == 0) {
  198. switch(manufacture_code->type) {
  199. case KEELOQ_LEARNING_SIMPLE:
  200. //Simple Learning
  201. hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
  202. break;
  203. case KEELOQ_LEARNING_NORMAL:
  204. //Simple Learning
  205. man_normal_learning =
  206. subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
  207. hop = subghz_protocol_keeloq_common_encrypt(decrypt, man_normal_learning);
  208. break;
  209. case KEELOQ_LEARNING_UNKNOWN:
  210. hop = 0; //todo
  211. break;
  212. }
  213. break;
  214. }
  215. }
  216. uint64_t yek = (uint64_t)fix << 32 | hop;
  217. return subghz_protocol_common_reverse_key(yek, instance->common.code_last_count_bit);
  218. }
  219. bool subghz_protocol_keeloq_send_key(
  220. SubGhzProtocolKeeloq* instance,
  221. SubGhzProtocolCommonEncoder* encoder) {
  222. furi_assert(instance);
  223. furi_assert(encoder);
  224. //gen new key
  225. instance->common.cnt++;
  226. instance->common.code_last_found = subghz_protocol_keeloq_gen_key(instance);
  227. if(instance->common.callback)
  228. instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
  229. if(!strcmp(instance->manufacture_name, "Unknown")) {
  230. return false;
  231. }
  232. size_t index = 0;
  233. encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4;
  234. if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
  235. //Send header
  236. for(uint8_t i = 11; i > 0; i--) {
  237. encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
  238. encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
  239. }
  240. encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
  241. encoder->upload[index++] =
  242. level_duration_make(false, (uint32_t)instance->common.te_short * 10);
  243. //Send key data
  244. for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
  245. if(bit_read(instance->common.code_last_found, i - 1)) {
  246. //send bit 1
  247. encoder->upload[index++] =
  248. level_duration_make(true, (uint32_t)instance->common.te_short);
  249. encoder->upload[index++] =
  250. level_duration_make(false, (uint32_t)instance->common.te_long);
  251. } else {
  252. //send bit 0
  253. encoder->upload[index++] =
  254. level_duration_make(true, (uint32_t)instance->common.te_long);
  255. encoder->upload[index++] =
  256. level_duration_make(false, (uint32_t)instance->common.te_short);
  257. }
  258. }
  259. // +send 2 status bit
  260. encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
  261. encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long);
  262. //encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long);
  263. //encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
  264. // send end
  265. encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
  266. encoder->upload[index++] =
  267. level_duration_make(false, (uint32_t)instance->common.te_short * 40);
  268. return true;
  269. }
  270. void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) {
  271. instance->common.parser_step = 0;
  272. }
  273. void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration) {
  274. switch(instance->common.parser_step) {
  275. case 0:
  276. if((level) &&
  277. DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  278. instance->common.parser_step = 1;
  279. instance->common.header_count++;
  280. } else {
  281. instance->common.parser_step = 0;
  282. }
  283. break;
  284. case 1:
  285. if((!level) &&
  286. (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
  287. instance->common.parser_step = 0;
  288. break;
  289. }
  290. if((instance->common.header_count > 2) &&
  291. (DURATION_DIFF(duration, instance->common.te_short * 10) <
  292. instance->common.te_delta * 10)) {
  293. // Found header
  294. instance->common.parser_step = 2;
  295. instance->common.code_found = 0;
  296. instance->common.code_count_bit = 0;
  297. } else {
  298. instance->common.parser_step = 0;
  299. instance->common.header_count = 0;
  300. }
  301. break;
  302. case 2:
  303. if(level) {
  304. instance->common.te_last = duration;
  305. instance->common.parser_step = 3;
  306. }
  307. break;
  308. case 3:
  309. if(!level) {
  310. if(duration >= (instance->common.te_short * 2 + instance->common.te_delta)) {
  311. // Found end TX
  312. instance->common.parser_step = 0;
  313. if(instance->common.code_count_bit >=
  314. instance->common.code_min_count_bit_for_found) {
  315. if(instance->common.code_last_found != instance->common.code_found) {
  316. instance->common.code_last_found = instance->common.code_found;
  317. instance->common.code_last_count_bit = instance->common.code_count_bit;
  318. if(instance->common.callback)
  319. instance->common.callback(
  320. (SubGhzProtocolCommon*)instance, instance->common.context);
  321. }
  322. instance->common.code_found = 0;
  323. instance->common.code_count_bit = 0;
  324. instance->common.header_count = 0;
  325. }
  326. break;
  327. } else if(
  328. (DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
  329. instance->common.te_delta) &&
  330. (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) {
  331. if(instance->common.code_count_bit <
  332. instance->common.code_min_count_bit_for_found) {
  333. subghz_protocol_common_add_bit(&instance->common, 1);
  334. }
  335. instance->common.parser_step = 2;
  336. } else if(
  337. (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
  338. instance->common.te_delta) &&
  339. (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
  340. if(instance->common.code_count_bit <
  341. instance->common.code_min_count_bit_for_found) {
  342. subghz_protocol_common_add_bit(&instance->common, 0);
  343. }
  344. instance->common.parser_step = 2;
  345. } else {
  346. instance->common.parser_step = 0;
  347. instance->common.header_count = 0;
  348. }
  349. } else {
  350. instance->common.parser_step = 0;
  351. instance->common.header_count = 0;
  352. }
  353. break;
  354. }
  355. }
  356. void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output) {
  357. subghz_protocol_keeloq_check_remote_controller(instance);
  358. uint32_t code_found_hi = instance->common.code_last_found >> 32;
  359. uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
  360. uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
  361. instance->common.code_last_found, instance->common.code_last_count_bit);
  362. uint32_t code_found_reverse_hi = code_found_reverse >> 32;
  363. uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
  364. string_cat_printf(
  365. output,
  366. "%s %dbit\r\n"
  367. "Key:%08lX%08lX\r\n"
  368. "Fix:0x%08lX Cnt:%04X\r\n"
  369. "Hop:0x%08lX Btn:%02lX\r\n"
  370. "MF:%s\r\n"
  371. "Sn:0x%07lX \r\n",
  372. instance->common.name,
  373. instance->common.code_last_count_bit,
  374. code_found_hi,
  375. code_found_lo,
  376. code_found_reverse_hi,
  377. instance->common.cnt,
  378. code_found_reverse_lo,
  379. instance->common.btn,
  380. instance->manufacture_name,
  381. instance->common.serial);
  382. }
  383. void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) {
  384. string_printf(
  385. output,
  386. "Protocol: %s\n"
  387. "Bit: %d\n"
  388. "Key: %08lX%08lX\n",
  389. instance->common.name,
  390. instance->common.code_last_count_bit,
  391. (uint32_t)(instance->common.code_last_found >> 32),
  392. (uint32_t)(instance->common.code_last_found & 0xFFFFFFFF));
  393. }
  394. bool subghz_protocol_keeloq_to_load_protocol_from_file(
  395. FileWorker* file_worker,
  396. SubGhzProtocolKeeloq* instance) {
  397. bool loaded = false;
  398. string_t temp_str;
  399. string_init(temp_str);
  400. int res = 0;
  401. int data = 0;
  402. do {
  403. // Read and parse bit data from 2nd line
  404. if(!file_worker_read_until(file_worker, temp_str, '\n')) {
  405. break;
  406. }
  407. res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data);
  408. if(res != 1) {
  409. break;
  410. }
  411. instance->common.code_last_count_bit = (uint8_t)data;
  412. // Read and parse key data from 3nd line
  413. if(!file_worker_read_until(file_worker, temp_str, '\n')) {
  414. break;
  415. }
  416. // strlen("Key: ") = 5
  417. string_right(temp_str, 5);
  418. uint8_t buf_key[8] = {0};
  419. if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) {
  420. break;
  421. }
  422. for(uint8_t i = 0; i < 8; i++) {
  423. instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i];
  424. }
  425. loaded = true;
  426. } while(0);
  427. string_clear(temp_str);
  428. return loaded;
  429. }
  430. void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context) {
  431. furi_assert(context);
  432. furi_assert(instance);
  433. SubGhzProtocolCommonLoad* data = context;
  434. instance->common.code_last_found = data->code_found;
  435. instance->common.code_last_count_bit = data->code_count_bit;
  436. subghz_protocol_keeloq_check_remote_controller(instance);
  437. }