subghz_protocol_keeloq.c 19 KB

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