subghz_protocol_keeloq.c 20 KB

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