subghz_protocol_keeloq.c 17 KB

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