subghz_protocol_keeloq.c 21 KB

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