From 1a039a86f8fdd37c9bfeecab3e5f6f2cf2ad6bf1 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 16 Jul 2021 19:37:48 +0400 Subject: [PATCH] Skorp sub ghz add protocol (#581) * SubGhz: Add Star Line protocol * Rollback ReadMe changes * SubGhz: add shared keystore for keeloq derived protocols. * SubGhz: add missing key load routine Co-authored-by: Aleksandr Kutuzov --- lib/fl_subghz/protocols/subghz_protocol.c | 62 ++-- .../protocols/subghz_protocol_keeloq.c | 117 ++----- .../protocols/subghz_protocol_keeloq.h | 13 +- .../protocols/subghz_protocol_keeloq_common.c | 49 +++ .../protocols/subghz_protocol_keeloq_common.h | 46 +++ .../protocols/subghz_protocol_star_line.c | 287 ++++++++++++++++++ .../protocols/subghz_protocol_star_line.h | 53 ++++ lib/fl_subghz/subghz_keystore.c | 86 ++++++ lib/fl_subghz/subghz_keystore.h | 25 ++ 9 files changed, 584 insertions(+), 154 deletions(-) create mode 100644 lib/fl_subghz/protocols/subghz_protocol_keeloq_common.c create mode 100644 lib/fl_subghz/protocols/subghz_protocol_keeloq_common.h create mode 100644 lib/fl_subghz/protocols/subghz_protocol_star_line.c create mode 100644 lib/fl_subghz/protocols/subghz_protocol_star_line.h create mode 100644 lib/fl_subghz/subghz_keystore.c create mode 100644 lib/fl_subghz/subghz_keystore.h diff --git a/lib/fl_subghz/protocols/subghz_protocol.c b/lib/fl_subghz/protocols/subghz_protocol.c index e85c4268..32e7dc05 100644 --- a/lib/fl_subghz/protocols/subghz_protocol.c +++ b/lib/fl_subghz/protocols/subghz_protocol.c @@ -1,5 +1,4 @@ #include "subghz_protocol.h" - #include "subghz_protocol_came.h" #include "subghz_protocol_cfm.h" #include "subghz_protocol_keeloq.h" @@ -10,14 +9,16 @@ #include "subghz_protocol_ido.h" #include "subghz_protocol_faac_slh.h" #include "subghz_protocol_nero_sketch.h" +#include "subghz_protocol_star_line.h" + +#include "../subghz_keystore.h" #include #include -#include - -#define FILE_BUFFER_SIZE 64 struct SubGhzProtocol { + SubGhzKeystore* keystore; + SubGhzProtocolCame* came; SubGhzProtocolKeeloq* keeloq; SubGhzProtocolNiceFlo* nice_flo; @@ -27,6 +28,7 @@ struct SubGhzProtocol { SubGhzProtocolIDo* ido; SubGhzProtocolFaacSLH* faac_slh; SubGhzProtocolNeroSketch* nero_sketch; + SubGhzProtocolStarLine* star_line; SubGhzProtocolTextCallback text_callback; void* text_callback_context; @@ -58,8 +60,10 @@ static void subghz_protocol_parser_rx_callback(SubGhzProtocolCommon* parser, voi SubGhzProtocol* subghz_protocol_alloc() { SubGhzProtocol* instance = furi_alloc(sizeof(SubGhzProtocol)); + instance->keystore = subghz_keystore_alloc(); + instance->came = subghz_protocol_came_alloc(); - instance->keeloq = subghz_protocol_keeloq_alloc(); + instance->keeloq = subghz_protocol_keeloq_alloc(instance->keystore); instance->princeton = subghz_protocol_princeton_alloc(); instance->nice_flo = subghz_protocol_nice_flo_alloc(); instance->nice_flor_s = subghz_protocol_nice_flor_s_alloc(); @@ -67,6 +71,7 @@ SubGhzProtocol* subghz_protocol_alloc() { instance->ido = subghz_protocol_ido_alloc(); instance->faac_slh = subghz_protocol_faac_slh_alloc(); instance->nero_sketch = subghz_protocol_nero_sketch_alloc(); + instance->star_line = subghz_protocol_star_line_alloc(instance->keystore); return instance; } @@ -83,6 +88,9 @@ void subghz_protocol_free(SubGhzProtocol* instance) { subghz_protocol_ido_free(instance->ido); subghz_protocol_faac_slh_free(instance->faac_slh); subghz_protocol_nero_sketch_free(instance->nero_sketch); + subghz_protocol_star_line_free(instance->star_line); + + subghz_keystore_free(instance->keystore); free(instance); } @@ -99,6 +107,7 @@ void subghz_protocol_enable_dump_text(SubGhzProtocol* instance, SubGhzProtocolTe subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->ido, subghz_protocol_text_rx_callback, instance); subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->faac_slh, subghz_protocol_text_rx_callback, instance); subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nero_sketch, subghz_protocol_text_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->star_line, subghz_protocol_text_rx_callback, instance); instance->text_callback = callback; instance->text_callback_context = context; @@ -116,56 +125,19 @@ void subghz_protocol_enable_dump(SubGhzProtocol* instance, SubGhzProtocolCommonC subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->ido, subghz_protocol_parser_rx_callback, instance); subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->faac_slh, subghz_protocol_parser_rx_callback, instance); subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nero_sketch, subghz_protocol_parser_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->star_line, subghz_protocol_parser_rx_callback, instance); instance->parser_callback = callback; instance->parser_callback_context = context; } -static void subghz_protocol_load_keeloq_file_process_line(SubGhzProtocol* instance, string_t line) { - uint64_t key = 0; - uint16_t type = 0; - char skey[17] = {0}; - char name[65] = {0}; - int ret = sscanf(string_get_cstr(line), "%16s:%hu:%64s", skey, &type, name); - key = strtoull(skey, NULL, 16); - if (ret == 3) { - subghz_protocol_keeloq_add_manafacture_key(instance->keeloq, name, key, type); - } else { - printf("Failed to load line: %s\r\n", string_get_cstr(line)); - } -} void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name); } void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file_name) { - File manufacture_keys_file; - FS_Api* fs_api = furi_record_open("sdcard"); - fs_api->file.open(&manufacture_keys_file, file_name, FSAM_READ, FSOM_OPEN_EXISTING); - string_t line; - string_init(line); - if(manufacture_keys_file.error_id == FSE_OK) { - printf("Loading manufacture keys file %s\r\n", file_name); - char buffer[FILE_BUFFER_SIZE]; - uint16_t ret; - do { - ret = fs_api->file.read(&manufacture_keys_file, buffer, FILE_BUFFER_SIZE); - for (uint16_t i=0; i < ret; i++) { - if (buffer[i] == '\n' && string_size(line) > 0) { - subghz_protocol_load_keeloq_file_process_line(instance, line); - string_clean(line); - } else { - string_push_back(line, buffer[i]); - } - } - } while(ret > 0); - } else { - printf("Manufacture keys file is not found: %s\r\n", file_name); - } - string_clear(line); - fs_api->file.close(&manufacture_keys_file); - furi_record_close("sdcard"); + subghz_keystore_load(instance->keystore, file_name); } void subghz_protocol_reset(SubGhzProtocol* instance) { @@ -178,6 +150,7 @@ void subghz_protocol_reset(SubGhzProtocol* instance) { subghz_protocol_ido_reset(instance->ido); subghz_protocol_faac_slh_reset(instance->faac_slh); subghz_protocol_nero_sketch_reset(instance->nero_sketch); + subghz_protocol_star_line_reset(instance->star_line); } void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { @@ -190,4 +163,5 @@ void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t durati subghz_protocol_ido_parse(instance->ido, level, duration); subghz_protocol_faac_slh_parse(instance->faac_slh, level, duration); subghz_protocol_nero_sketch_parse(instance->nero_sketch, level, duration); + subghz_protocol_star_line_parse(instance->star_line, level, duration); } diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq.c b/lib/fl_subghz/protocols/subghz_protocol_keeloq.c index 02bc23d5..b34b606b 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq.c @@ -1,91 +1,23 @@ #include "subghz_protocol_keeloq.h" +#include "subghz_protocol_keeloq_common.h" + +#include "../subghz_keystore.h" #include #include -#include - -/* - * Keeloq - * https://ru.wikipedia.org/wiki/KeeLoq - * https://phreakerclub.com/forum/showthread.php?t=1094 - * - */ - -#define KEELOQ_NLF 0x3A5C742E -#define bit(x,n) (((x)>>(n))&1) -#define g5(x,a,b,c,d,e) (bit(x,a)+bit(x,b)*2+bit(x,c)*4+bit(x,d)*8+bit(x,e)*16) - -/* - * KeeLoq learning types - * https://phreakerclub.com/forum/showthread.php?t=67 - */ -#define KEELOQ_LEARNING_UNKNOWN 0u -#define KEELOQ_LEARNING_SIMPLE 1u -#define KEELOQ_LEARNING_NORMAL 2u -#define KEELOQ_LEARNING_SECURE 3u - -typedef struct { - string_t name; - uint64_t key; - uint16_t type; -} KeeLoqManufactureCode; - -ARRAY_DEF(KeeLoqManufactureCodeArray, KeeLoqManufactureCode, M_POD_OPLIST) -#define M_OPL_KeeLoqManufactureCodeArray_t() ARRAY_OPLIST(KeeLoqManufactureCodeArray, M_POD_OPLIST) struct SubGhzProtocolKeeloq { SubGhzProtocolCommon common; - KeeLoqManufactureCodeArray_t manufacture_codes; + SubGhzKeystore* keystore; const char* manufacture_name; }; -/** Simple Learning Encrypt - * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter - * @param key - manufacture (64bit) - * @return keelog encrypt data - */ -inline uint32_t subghz_protocol_keeloq_encrypt(const uint32_t data, const uint64_t key) { - uint32_t x = data, r; - for (r = 0; r < 528; r++) - x = (x>>1)^((bit(x,0)^bit(x,16)^(uint32_t)bit(key,r&63)^bit(KEELOQ_NLF,g5(x,1,9,20,26,31)))<<31); - return x; -} - -/** Simple Learning Decrypt - * @param data - keelog encrypt data - * @param key - manufacture (64bit) - * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter - */ -inline uint32_t subghz_protocol_keeloq_decrypt(const uint32_t data, const uint64_t key) { - uint32_t x = data, r; - for (r = 0; r < 528; r++) - x = (x<<1)^bit(x,31)^bit(x,15)^(uint32_t)bit(key,(15-r)&63)^bit(KEELOQ_NLF,g5(x,0,8,19,25,30)); - return x; -} - -/** Normal Learning - * @param data - serial number (28bit) - * @param key - manufacture (64bit) - * @return manufacture for this serial number (64bit) - */ -inline uint64_t subghz_protocol_keeloq_normal_learning(uint32_t data, const uint64_t key){ - uint32_t k1,k2; - - data&=0x0FFFFFFF; - data|=0x20000000; - k1=subghz_protocol_keeloq_decrypt(data, key); - - data&=0x0FFFFFFF; - data|=0x60000000; - k2=subghz_protocol_keeloq_decrypt(data, key); - - return ((uint64_t)k2<<32)| k1; // key - shifrovanoya -} - -SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc() { +SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) { SubGhzProtocolKeeloq* instance = furi_alloc(sizeof(SubGhzProtocolKeeloq)); + instance->keystore = keystore; + instance->common.name = "KeeLoq"; instance->common.code_min_count_bit_for_found = 64; instance->common.te_shot = 400; @@ -93,29 +25,14 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc() { instance->common.te_delta = 140; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str; - KeeLoqManufactureCodeArray_init(instance->manufacture_codes); - return instance; } void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance) { furi_assert(instance); - for - M_EACH(manufacture_code, instance->manufacture_codes, KeeLoqManufactureCodeArray_t) { - string_clear(manufacture_code->name); - manufacture_code->key = 0; - } - KeeLoqManufactureCodeArray_clear(instance->manufacture_codes); free(instance); } -void subghz_protocol_keeloq_add_manafacture_key(SubGhzProtocolKeeloq* instance, const char* name, uint64_t key, uint16_t type) { - KeeLoqManufactureCode* manufacture_code = KeeLoqManufactureCodeArray_push_raw(instance->manufacture_codes); - string_init_set_str(manufacture_code->name, name); - manufacture_code->key = key; - manufacture_code->type = type; -} - /** Checking the accepted code against the database manafacture key * * @param instance SubGhzProtocolKeeloq instance @@ -130,11 +47,11 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe uint64_t man_normal_learning; for - M_EACH(manufacture_code, instance->manufacture_codes, KeeLoqManufactureCodeArray_t) { + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { switch (manufacture_code->type){ case KEELOQ_LEARNING_SIMPLE: //Simple Learning - decrypt = subghz_protocol_keeloq_decrypt(hop, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if((decrypt>>28 == btn) && ((((uint16_t)(decrypt>>16)) & 0x3FF) == end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt = decrypt & 0x0000FFFF; @@ -144,8 +61,8 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe case KEELOQ_LEARNING_NORMAL: // Normal_Learning // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = subghz_protocol_keeloq_normal_learning(fix, manufacture_code->key); - decrypt=subghz_protocol_keeloq_decrypt(hop, man_normal_learning); + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); if( (decrypt>>28 ==btn)&& ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt = decrypt & 0x0000FFFF; @@ -154,7 +71,7 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe break; case KEELOQ_LEARNING_UNKNOWN: // Simple Learning - decrypt=subghz_protocol_keeloq_decrypt(hop, manufacture_code->key); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt = decrypt & 0x0000FFFF; @@ -167,7 +84,7 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe man_rev_byte=(uint8_t)(manufacture_code->key >> i); man_rev = man_rev | man_rev_byte << (56-i); } - decrypt=subghz_protocol_keeloq_decrypt(hop, man_rev); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_rev); if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt= decrypt&0x0000FFFF; @@ -176,8 +93,8 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe //########################### // Normal_Learning // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 - man_normal_learning = subghz_protocol_keeloq_normal_learning(fix, manufacture_code->key); - decrypt=subghz_protocol_keeloq_decrypt(hop, man_normal_learning); + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); if( (decrypt>>28 ==btn)&& ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt= decrypt&0x0000FFFF; @@ -190,8 +107,8 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector(SubGhzProtocolKe man_rev_byte = (uint8_t)(manufacture_code->key >> i); man_rev = man_rev | man_rev_byte << (56-i); } - man_normal_learning = subghz_protocol_keeloq_normal_learning(fix, man_rev); - decrypt=subghz_protocol_keeloq_decrypt(hop, man_normal_learning); + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); if( (decrypt>>28 ==btn) && ((((uint16_t)(decrypt>>16))&0x3FF)==end_serial)){ instance->manufacture_name = string_get_cstr(manufacture_code->name); instance->common.cnt= decrypt&0x0000FFFF; diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq.h b/lib/fl_subghz/protocols/subghz_protocol_keeloq.h index 5d9185f0..298a6e97 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_keeloq.h +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq.h @@ -2,13 +2,15 @@ #include "subghz_protocol_common.h" +typedef struct SubGhzKeystore SubGhzKeystore; + typedef struct SubGhzProtocolKeeloq SubGhzProtocolKeeloq; /** Allocate SubGhzProtocolKeeloq * * @return SubGhzProtocolKeeloq* */ -SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(); +SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore); /** Free SubGhzProtocolKeeloq * @@ -16,15 +18,6 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(); */ void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance); -/** Loading of manufacture keys - * - * @param instance - SubGhzProtocolKeeloq instance - * @param name - key name - * @param key - manufacture (64bit) - * @param type - type manufacture key - */ -void subghz_protocol_keeloq_add_manafacture_key(SubGhzProtocolKeeloq* instance, const char* name, uint64_t key, uint16_t type); - /** Sends the key on the air * * @param instance - SubGhzProtocolKeeloq instance diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.c b/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.c new file mode 100644 index 00000000..1d02eba8 --- /dev/null +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.c @@ -0,0 +1,49 @@ +#include "subghz_protocol_keeloq_common.h" + +#include + +#include +#include + +/** Simple Learning Encrypt + * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter + * @param key - manufacture (64bit) + * @return keelog encrypt data + */ +inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) { + uint32_t x = data, r; + for (r = 0; r < 528; r++) + x = (x>>1)^((bit(x,0)^bit(x,16)^(uint32_t)bit(key,r&63)^bit(KEELOQ_NLF,g5(x,1,9,20,26,31)))<<31); + return x; +} + +/** Simple Learning Decrypt + * @param data - keelog encrypt data + * @param key - manufacture (64bit) + * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter + */ +inline uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const uint64_t key) { + uint32_t x = data, r; + for (r = 0; r < 528; r++) + x = (x<<1)^bit(x,31)^bit(x,15)^(uint32_t)bit(key,(15-r)&63)^bit(KEELOQ_NLF,g5(x,0,8,19,25,30)); + return x; +} + +/** Normal Learning + * @param data - serial number (28bit) + * @param key - manufacture (64bit) + * @return manufacture for this serial number (64bit) + */ +inline uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint64_t key){ + uint32_t k1,k2; + + data&=0x0FFFFFFF; + data|=0x20000000; + k1=subghz_protocol_keeloq_common_decrypt(data, key); + + data&=0x0FFFFFFF; + data|=0x60000000; + k2=subghz_protocol_keeloq_common_decrypt(data, key); + + return ((uint64_t)k2<<32)| k1; // key - shifrovanoya +} diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.h b/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.h new file mode 100644 index 00000000..c9c16cc5 --- /dev/null +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq_common.h @@ -0,0 +1,46 @@ +#pragma once +#include "subghz_protocol_common.h" + +#include + +/* + * Keeloq + * https://ru.wikipedia.org/wiki/KeeLoq + * https://phreakerclub.com/forum/showthread.php?t=1094 + * + */ + +#define KEELOQ_NLF 0x3A5C742E +#define bit(x,n) (((x)>>(n))&1) +#define g5(x,a,b,c,d,e) (bit(x,a)+bit(x,b)*2+bit(x,c)*4+bit(x,d)*8+bit(x,e)*16) + +/* + * KeeLoq learning types + * https://phreakerclub.com/forum/showthread.php?t=67 + */ +#define KEELOQ_LEARNING_UNKNOWN 0u +#define KEELOQ_LEARNING_SIMPLE 1u +#define KEELOQ_LEARNING_NORMAL 2u +#define KEELOQ_LEARNING_SECURE 3u + + +/** Simple Learning Encrypt + * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter + * @param key - manufacture (64bit) + * @return keelog encrypt data + */ +uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key); + +/** Simple Learning Decrypt + * @param data - keelog encrypt data + * @param key - manufacture (64bit) + * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter + */ +uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const uint64_t key); + +/** Normal Learning + * @param data - serial number (28bit) + * @param key - manufacture (64bit) + * @return manufacture for this serial number (64bit) + */ +uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint64_t key); \ No newline at end of file diff --git a/lib/fl_subghz/protocols/subghz_protocol_star_line.c b/lib/fl_subghz/protocols/subghz_protocol_star_line.c new file mode 100644 index 00000000..44fb1e07 --- /dev/null +++ b/lib/fl_subghz/protocols/subghz_protocol_star_line.c @@ -0,0 +1,287 @@ +#include "subghz_protocol_star_line.h" +#include "subghz_protocol_keeloq_common.h" + +#include "../subghz_keystore.h" + +#include + +#include +#include + + +struct SubGhzProtocolStarLine { + SubGhzProtocolCommon common; + SubGhzKeystore* keystore; + const char* manufacture_name; +}; + +SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore) { + SubGhzProtocolStarLine* instance = furi_alloc(sizeof(SubGhzProtocolStarLine)); + + instance->keystore = keystore; + + instance->common.name = "Star Line"; + instance->common.code_min_count_bit_for_found = 64; + instance->common.te_shot = 250; + instance->common.te_long = 500; + instance->common.te_delta = 120; + instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_star_line_to_str; + + return instance; +} + +void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) { + furi_assert(instance); + free(instance); +} + +/** Send bit + * + * @param instance - SubGhzProtocolStarLine instance + * @param bit - bit + */ +void subghz_protocol_star_line_send_bit(SubGhzProtocolStarLine* instance, uint8_t bit) { + if (bit) { + //send bit 1 + SUBGHZ_TX_PIN_HIGTH(); + delay_us(instance->common.te_long); + SUBGHZ_TX_PIN_LOW(); + delay_us(instance->common.te_long); + } else { + //send bit 0 + SUBGHZ_TX_PIN_HIGTH(); + delay_us(instance->common.te_shot); + SUBGHZ_TX_PIN_LOW(); + delay_us(instance->common.te_shot); + } +} + +void subghz_protocol_star_line_send_key(SubGhzProtocolStarLine* instance, uint64_t key, uint8_t bit,uint8_t repeat) { + while (repeat--) { + //Send header + for(uint8_t i = 0; i < 6; i++){ + SUBGHZ_TX_PIN_HIGTH(); + delay_us(instance->common.te_long * 2); + SUBGHZ_TX_PIN_LOW(); + delay_us(instance->common.te_long * 2); + } + //Send Start bit ?????????? + //Send key data + for (uint8_t i = bit; i > 0; i--) { + subghz_protocol_star_line_send_bit(instance, bit_read(key, i - 1)); + } + //Send Stop bit ?????????? + } +} + +void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance) { + instance->common.parser_step = 0; +} + +/** Checking the accepted code against the database manafacture key + * + * @param instance SubGhzProtocolStarLine instance + * @param fix fix part of the parcel + * @param hop hop encrypted part of the parcel + * @return true on successful search + */ +uint8_t subghz_protocol_star_line_check_remote_controller_selector(SubGhzProtocolStarLine* instance, uint32_t fix , uint32_t hop) { + uint16_t end_serial = (uint16_t)(fix&0xFF); + uint8_t btn = (uint8_t)(fix>>24); + uint32_t decrypt = 0; + uint64_t man_normal_learning; + + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + switch (manufacture_code->type){ + case KEELOQ_LEARNING_SIMPLE: + //Simple Learning + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + if((decrypt>>24 == btn) && ((((uint16_t)(decrypt>>16)) & 0x00FF) == end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + break; + case KEELOQ_LEARNING_NORMAL: + // Normal_Learning + // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if( (decrypt>>24 ==btn)&& ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + break; + case KEELOQ_LEARNING_UNKNOWN: + // Simple Learning + decrypt=subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt = decrypt & 0x0000FFFF; + return 1; + } + // Check for mirrored man + uint64_t man_rev=0; + uint64_t man_rev_byte=0; + for(uint8_t i=0; i<64; i+=8){ + man_rev_byte=(uint8_t)(manufacture_code->key >> i); + man_rev = man_rev | man_rev_byte << (56-i); + } + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_rev); + if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt= decrypt&0x0000FFFF; + return 1; + } + //########################### + // Normal_Learning + // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if( (decrypt>>24 ==btn)&& ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt= decrypt&0x0000FFFF; + return 1; + } + // Check for mirrored man + man_rev=0; + man_rev_byte=0; + for(uint8_t i=0; i<64; i+=8){ + man_rev_byte = (uint8_t)(manufacture_code->key >> i); + man_rev = man_rev | man_rev_byte << (56-i); + } + man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); + decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); + if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ + instance->manufacture_name = string_get_cstr(manufacture_code->name); + instance->common.cnt= decrypt&0x0000FFFF; + return 1; + } + break; + } + } + + instance->manufacture_name = "Unknown"; + instance->common.cnt=0; + + return 0; +} + +/** Analysis of received data + * + * @param instance SubGhzProtocolStarLine instance + */ +void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance) { + uint64_t key = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + uint32_t key_fix = key >> 32; + uint32_t key_hop = key & 0x00000000ffffffff; + + subghz_protocol_star_line_check_remote_controller_selector(instance, key_fix, key_hop); + + instance ->common.serial= key_fix&0x00FFFFFF; + instance->common.btn = key_fix >> 24; + + + if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + +} + +void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool level, uint32_t duration) { + switch (instance->common.parser_step) { + case 0: + if (level){ + if(DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 2) { + instance->common.parser_step = 1; + instance->common.header_count++; + } else if(instance->common.header_count>4){ + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + instance->common.te_last = duration; + instance->common.parser_step = 3; + } + }else{ + instance->common.parser_step = 0; + instance->common.header_count = 0; + } + break; + case 1: + if ((!level) + && (DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 2)) { + //Found Preambula + instance->common.parser_step = 0; + } else { + instance->common.header_count = 0; + instance->common.parser_step = 0; + } + break; + case 2: + if (level) { + if (duration >= (instance->common.te_long + instance->common.te_delta)) { + instance->common.parser_step = 0; + if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { + if(instance->common.code_last_found != instance->common.code_found){ + subghz_protocol_star_line_check_remote_controller(instance); + } + } + instance->common.code_found = 0; + instance->common.code_count_bit = 0; + instance->common.header_count = 0; + break; + } else { + instance->common.te_last = duration; + instance->common.parser_step = 3; + } + + }else{ + instance->common.parser_step = 0; + } + break; + case 3: + if(!level){ + if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot)< instance->common.te_delta) + && (DURATION_DIFF(duration,instance->common.te_shot)< instance->common.te_delta)) { + subghz_protocol_common_add_bit(&instance->common, 0); + instance->common.parser_step = 2; + } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long )< instance->common.te_delta) + && (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta)) { + subghz_protocol_common_add_bit(&instance->common, 1); + instance->common.parser_step = 2; + } else { + instance->common.parser_step = 0; + } + } else { + instance->common.parser_step = 0; + } + break; + } +} + +void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output) { + uint32_t code_found_hi = instance->common.code_found >> 32; + uint32_t code_found_lo = instance->common.code_found & 0x00000000ffffffff; + + uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_found, instance->common.code_count_bit); + + uint32_t code_found_reverse_hi = code_found_reverse>>32; + uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff; + string_cat_printf( + output, + "Protocol %s, %d Bit\r\n" + "KEY:0x%lX%lX\r\n" + "FIX:%08lX MF:%s \r\n" + "HOP:%08lX \r\n" + "SN:%06lX CNT:%04X B:%02lX\r\n", + instance->common.name, + instance->common.code_count_bit, + code_found_hi, + code_found_lo, + code_found_reverse_hi, + instance->manufacture_name, + code_found_reverse_lo, + instance->common.serial, + instance->common.cnt, + instance->common.btn + ); +} \ No newline at end of file diff --git a/lib/fl_subghz/protocols/subghz_protocol_star_line.h b/lib/fl_subghz/protocols/subghz_protocol_star_line.h new file mode 100644 index 00000000..e39cbbc6 --- /dev/null +++ b/lib/fl_subghz/protocols/subghz_protocol_star_line.h @@ -0,0 +1,53 @@ +#pragma once + +#include "subghz_protocol_common.h" + +typedef struct SubGhzKeystore SubGhzKeystore; + +typedef struct SubGhzProtocolStarLine SubGhzProtocolStarLine; + +/** Allocate SubGhzProtocolStarLine + * + * @return SubGhzProtocolStarLine* + */ +SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore); + +/** Free SubGhzProtocolStarLine + * + * @param instance + */ +void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance); + +/** Sends the key on the air + * + * @param instance - SubGhzProtocolStarLine instance + * @param key - key send + * @param bit - count bit key + * @param repeat - repeat send key + */ +void subghz_protocol_star_line_send_key(SubGhzProtocolStarLine* instance, uint64_t key, uint8_t bit, uint8_t repeat); + +/** Reset internal state + * @param instance - SubGhzProtocolStarLine instance + */ +void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance); + +/** Analysis of received data + * + * @param instance SubGhzProtocolStarLine instance + */ +void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance); + +/** Parse accepted duration + * + * @param instance - SubGhzProtocolStarLine instance + * @param data - LevelDuration level_duration + */ +void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool level, uint32_t duration); + +/** Outputting information from the parser + * + * @param instance - SubGhzProtocolStarLine* instance + * @param output - output string + */ +void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output); diff --git a/lib/fl_subghz/subghz_keystore.c b/lib/fl_subghz/subghz_keystore.c new file mode 100644 index 00000000..02015df6 --- /dev/null +++ b/lib/fl_subghz/subghz_keystore.c @@ -0,0 +1,86 @@ +#include "subghz_keystore.h" + +#include +#include + +#define FILE_BUFFER_SIZE 64 + +struct SubGhzKeystore { + SubGhzKeyArray_t data; +}; + +SubGhzKeystore* subghz_keystore_alloc() { + SubGhzKeystore* instance = furi_alloc(sizeof(SubGhzKeystore)); + + SubGhzKeyArray_init(instance->data); + + return instance; +} + +void subghz_keystore_free(SubGhzKeystore* instance) { + furi_assert(instance); + + for + M_EACH(manufacture_code, instance->data, SubGhzKeyArray_t) { + string_clear(manufacture_code->name); + manufacture_code->key = 0; + } + SubGhzKeyArray_clear(instance->data); + + free(instance); +} + +static void subghz_keystore_add_key(SubGhzKeystore* instance, const char* name, uint64_t key, uint16_t type) { + SubGhzKey* manufacture_code = SubGhzKeyArray_push_raw(instance->data); + string_init_set_str(manufacture_code->name, name); + manufacture_code->key = key; + manufacture_code->type = type; +} + +static void subghz_keystore_process_line(SubGhzKeystore* instance, string_t line) { + uint64_t key = 0; + uint16_t type = 0; + char skey[17] = {0}; + char name[65] = {0}; + int ret = sscanf(string_get_cstr(line), "%16s:%hu:%64s", skey, &type, name); + key = strtoull(skey, NULL, 16); + if (ret == 3) { + subghz_keystore_add_key(instance, name, key, type); + } else { + printf("Failed to load line: %s\r\n", string_get_cstr(line)); + } +} + +void subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) { + File manufacture_keys_file; + FS_Api* fs_api = furi_record_open("sdcard"); + fs_api->file.open(&manufacture_keys_file, file_name, FSAM_READ, FSOM_OPEN_EXISTING); + string_t line; + string_init(line); + if(manufacture_keys_file.error_id == FSE_OK) { + printf("Loading manufacture keys file %s\r\n", file_name); + char buffer[FILE_BUFFER_SIZE]; + uint16_t ret; + do { + ret = fs_api->file.read(&manufacture_keys_file, buffer, FILE_BUFFER_SIZE); + for (uint16_t i=0; i < ret; i++) { + if (buffer[i] == '\n' && string_size(line) > 0) { + subghz_keystore_process_line(instance, line); + string_clean(line); + } else { + string_push_back(line, buffer[i]); + } + } + } while(ret > 0); + } else { + printf("Manufacture keys file is not found: %s\r\n", file_name); + } + string_clear(line); + fs_api->file.close(&manufacture_keys_file); + furi_record_close("sdcard"); +} + +SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance) { + furi_assert(instance); + return &instance->data; +} diff --git a/lib/fl_subghz/subghz_keystore.h b/lib/fl_subghz/subghz_keystore.h new file mode 100644 index 00000000..4b10730b --- /dev/null +++ b/lib/fl_subghz/subghz_keystore.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +typedef struct { + string_t name; + uint64_t key; + uint16_t type; +} SubGhzKey; + +ARRAY_DEF(SubGhzKeyArray, SubGhzKey, M_POD_OPLIST) + +#define M_OPL_SubGhzKeyArray_t() ARRAY_OPLIST(SubGhzKeyArray, M_POD_OPLIST) + +typedef struct SubGhzKeystore SubGhzKeystore; + +SubGhzKeystore* subghz_keystore_alloc(); + +void subghz_keystore_free(SubGhzKeystore* instance); + +void subghz_keystore_load(SubGhzKeystore* instance, const char* filename); + +SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance);