mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-20 00:48:11 -07:00
subghz upgrades [ci skip]
docs update pr template update changelog update
This commit is contained in:
@@ -290,9 +290,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
||||
printf("\r\n");
|
||||
break;
|
||||
}
|
||||
if(additional_access_rights_len >
|
||||
MF_DESFIRE_MAX_KEYS * sizeof(MfDesfireFileAccessRights))
|
||||
break;
|
||||
if(additional_access_rights_len > MF_DESFIRE_MAX_KEYS - 1) break;
|
||||
|
||||
memcpy(
|
||||
&file_settings_temp.access_rights[1],
|
||||
|
||||
@@ -169,6 +169,10 @@ static MfUltralightCommand
|
||||
|
||||
MfUltralightPage pages[64] = {};
|
||||
uint8_t page_cnt = (end_page - start_page) + 1;
|
||||
if(page_cnt > COUNT_OF(pages)) {
|
||||
command = MfUltralightCommandNotProcessedNAK;
|
||||
break;
|
||||
}
|
||||
mf_ultralight_listener_perform_read(pages, instance, start_page, page_cnt, do_i2c_check);
|
||||
|
||||
bit_buffer_copy_bytes(instance->tx_buffer, (uint8_t*)pages, page_cnt * 4);
|
||||
|
||||
@@ -258,6 +258,10 @@ static void subghz_protocol_encoder_came_atomo_get_upload(
|
||||
btn = 0x4;
|
||||
} else if(btn == 0x4) {
|
||||
btn = 0x6;
|
||||
} else if(btn == 0x5) {
|
||||
btn = 0x0C;
|
||||
} else if(btn == 0x6) {
|
||||
btn = 0x0E;
|
||||
}
|
||||
|
||||
// override button if we change it with signal settings button editor
|
||||
@@ -482,9 +486,11 @@ void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
switch(instance->decoder.parser_step) {
|
||||
case CameAtomoDecoderStepReset:
|
||||
// There are two known options for the header: 72K us (TOP42R, TOP44R) or 12k us (found on TOP44RBN)
|
||||
// There are two known options for the header: 72K us (TOP42R, TOP44R) or 12k us (found on TOP44RBN) / 19k us (TOPD4REN)
|
||||
if((!level) && ((DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 10) <
|
||||
subghz_protocol_came_atomo_const.te_delta * 20) ||
|
||||
(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 16) <
|
||||
subghz_protocol_came_atomo_const.te_delta * 10) ||
|
||||
(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 60) <
|
||||
subghz_protocol_came_atomo_const.te_delta * 40))) {
|
||||
//Found header CAME
|
||||
@@ -661,6 +667,10 @@ static void subghz_protocol_came_atomo_remote_controller(SubGhzBlockGeneric* ins
|
||||
instance->btn = 0x3;
|
||||
} else if(btn_decode == 0x6) {
|
||||
instance->btn = 0x4;
|
||||
} else if(btn_decode == 0x0C) {
|
||||
instance->btn = 0x5;
|
||||
} else if(btn_decode == 0x0E) {
|
||||
instance->btn = 0x6;
|
||||
}
|
||||
|
||||
uint32_t hi = pack[0] << 24 | pack[1] << 16 | pack[2] << 8 | pack[3];
|
||||
@@ -671,7 +681,7 @@ static void subghz_protocol_came_atomo_remote_controller(SubGhzBlockGeneric* ins
|
||||
if(subghz_custom_btn_get_original() == 0) {
|
||||
subghz_custom_btn_set_original(instance->btn);
|
||||
}
|
||||
subghz_custom_btn_set_max(3);
|
||||
subghz_custom_btn_set_max(4);
|
||||
}
|
||||
|
||||
void atomo_encrypt(uint8_t* buff) {
|
||||
@@ -738,6 +748,12 @@ static uint8_t subghz_protocol_came_atomo_get_btn_code(void) {
|
||||
case 0x4:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x5:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x6:
|
||||
btn = 0x1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -756,6 +772,12 @@ static uint8_t subghz_protocol_came_atomo_get_btn_code(void) {
|
||||
case 0x4:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x5:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x6:
|
||||
btn = 0x2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -774,6 +796,36 @@ static uint8_t subghz_protocol_came_atomo_get_btn_code(void) {
|
||||
case 0x4:
|
||||
btn = 0x3;
|
||||
break;
|
||||
case 0x5:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x6:
|
||||
btn = 0x4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x5;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x5;
|
||||
break;
|
||||
case 0x3:
|
||||
btn = 0x5;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x5;
|
||||
break;
|
||||
case 0x5:
|
||||
btn = 0x6;
|
||||
break;
|
||||
case 0x6:
|
||||
btn = 0x5;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -367,7 +367,7 @@ static bool subghz_protocol_keeloq_gen_data(
|
||||
} else if(
|
||||
(strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Clemsa_Mutancode") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Came_Space") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Genius_Bravo") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "GSN") == 0) ||
|
||||
@@ -376,20 +376,33 @@ static bool subghz_protocol_keeloq_gen_data(
|
||||
(strcmp(instance->manufacture_name, "Pecinin") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Steelmate") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Cardin_S449") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Stilmatic") == 0)) {
|
||||
(strcmp(instance->manufacture_name, "Stilmatic") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Wisniowski") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "ATA_PTX4") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Fadini") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Seav") == 0)) {
|
||||
// DTM Neo, Came_Space uses 12bit serial -> simple learning
|
||||
// FAAC_RC,XT , Mutanco_Mutancode, Genius_Bravo, GSN 12bit serial -> normal learning
|
||||
// FAAC_RC,XT , Clemsa_Mutancode, Genius_Bravo, GSN 12bit serial -> normal learning
|
||||
// Rosh, Rossi, Pecinin -> 12bit serial - simple learning
|
||||
// Steelmate -> 12bit serial - normal learning
|
||||
// Cardin_S449 -> 12bit serial - normal learning
|
||||
// Stilmatic (r-tech) -> 12bit serial - normal learning
|
||||
// Wisniowski -> 12bit serial - normal learning
|
||||
// ATA_PTX4 -> 12bit serial - normal learning
|
||||
// Fadini -> 12bit serial - simple learning
|
||||
// Seav -> 12bit serial - normal learning
|
||||
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 |
|
||||
instance->generic.cnt;
|
||||
} else if(
|
||||
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0)) {
|
||||
// Nice Smilo, MHouse, JCM -> 8bit serial - simple learning
|
||||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Pujol_Vario") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Pujol") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Erreka") == 0)) {
|
||||
// Nice Smilo, MHouse, JCM, Pujol_Vario -> 8bit serial - simple learning
|
||||
// Pujol -> 8bit serial - special learning
|
||||
// Erreka -> 8bit serial - secure learning with seed
|
||||
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 |
|
||||
instance->generic.cnt;
|
||||
} else if(
|
||||
@@ -453,6 +466,28 @@ static bool subghz_protocol_keeloq_gen_data(
|
||||
fix, manufacture_code->key);
|
||||
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
|
||||
break;
|
||||
case KEELOQ_LEARNING_AERF:
|
||||
man = subghz_protocol_keeloq_common_learning_aerf(
|
||||
fix, manufacture_code->key);
|
||||
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
|
||||
break;
|
||||
case KEELOQ_LEARNING_ERREKA:
|
||||
man = subghz_protocol_keeloq_common_learning_erreka(
|
||||
fix, instance->generic.seed, manufacture_code->key);
|
||||
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
|
||||
break;
|
||||
case KEELOQ_LEARNING_PUJOL:
|
||||
man = subghz_protocol_keeloq_common_learning_pujol(
|
||||
fix, manufacture_code->key);
|
||||
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
|
||||
break;
|
||||
case KEELOQ_LEARNING_SIMPLE_JCM:
|
||||
//Simple Learning 8 bit serial
|
||||
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 |
|
||||
instance->generic.cnt;
|
||||
hop = subghz_protocol_keeloq_common_encrypt(
|
||||
decrypt, manufacture_code->key);
|
||||
break;
|
||||
case KEELOQ_LEARNING_UNKNOWN:
|
||||
if(kl_type_en == 1) {
|
||||
hop = subghz_protocol_keeloq_common_encrypt(
|
||||
@@ -511,7 +546,7 @@ bool subghz_protocol_keeloq_create_data(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool subghz_protocol_keeloq_bft_create_data(
|
||||
bool subghz_protocol_keeloq_seed_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
@@ -1101,6 +1136,55 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller_selector(
|
||||
return decrypt;
|
||||
}
|
||||
break;
|
||||
case KEELOQ_LEARNING_AERF:
|
||||
man = subghz_protocol_keeloq_common_learning_aerf(fix, manufacture_code->key);
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt_derived(hop, man, 0x240u);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt_derived(hop, man, 0x210u);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
break;
|
||||
case KEELOQ_LEARNING_ERREKA:
|
||||
man = subghz_protocol_keeloq_common_learning_erreka(
|
||||
fix, instance->seed, manufacture_code->key);
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
break;
|
||||
case KEELOQ_LEARNING_PUJOL:
|
||||
man = subghz_protocol_keeloq_common_learning_pujol(fix, manufacture_code->key);
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
break;
|
||||
case KEELOQ_LEARNING_SIMPLE_JCM:
|
||||
// Simple Learning 8 bit serial
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
|
||||
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
|
||||
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
|
||||
keystore->mfname = *manufacture_name;
|
||||
return decrypt;
|
||||
}
|
||||
break;
|
||||
case KEELOQ_LEARNING_UNKNOWN:
|
||||
// Simple Learning
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
|
||||
@@ -1625,7 +1709,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output
|
||||
code_found_reverse_lo,
|
||||
instance->generic.btn,
|
||||
instance->manufacture_name);
|
||||
} else if(strcmp(instance->manufacture_name, "BFT") == 0) {
|
||||
} else if(
|
||||
(strcmp(instance->manufacture_name, "BFT") == 0) ||
|
||||
(strcmp(instance->manufacture_name, "Erreka") == 0)) {
|
||||
// Allow counter edit
|
||||
subghz_block_generic_global.cnt_is_available = true;
|
||||
subghz_block_generic_global.cnt_length_bit = 16;
|
||||
|
||||
@@ -140,3 +140,97 @@ inline uint64_t
|
||||
subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man) {
|
||||
return (man & 0xFFFFFFFFFF000000) | (data & 0xFFFFFF);
|
||||
}
|
||||
|
||||
// Key utils
|
||||
|
||||
static inline uint32_t subghz_protocol_keeloq_common_manufacturer_nl_extend(
|
||||
uint32_t x,
|
||||
uint32_t k_lo,
|
||||
uint32_t k_hi,
|
||||
uint32_t outer_limit) {
|
||||
uint32_t r4 = outer_limit;
|
||||
uint32_t r5 = 0u;
|
||||
const uint32_t r6 = KEELOQ_NLF;
|
||||
|
||||
while(r5 != r4) {
|
||||
if(r5 < 0x210u) {
|
||||
uint32_t r1 = (x >> 15) & 1u;
|
||||
uint32_t r7 = r1 ^ ((x >> 1) | (x << 31));
|
||||
r1 = (15u - r5) & 0x3Fu;
|
||||
uint32_t lr = 32u - r1;
|
||||
uint32_t ip = r1 - 32u;
|
||||
lr = k_hi << lr;
|
||||
r1 = k_lo >> r1;
|
||||
ip = (r1 < 32u) ? (k_hi >> ip) : 0u;
|
||||
r1 = (r1 | lr | ip) & 1u;
|
||||
ip = (x >> 30) & 1u;
|
||||
r1 ^= r7;
|
||||
r7 = (x >> 25) & 1u;
|
||||
r7 += ip << 1;
|
||||
ip = (x >> 19) & 1u;
|
||||
ip += r7 << 1;
|
||||
r7 = (x >> 8) & 1u;
|
||||
r7 += ip << 1;
|
||||
x &= 1u;
|
||||
x += r7 << 1;
|
||||
x = (int32_t)r6 >> (x & 31u);
|
||||
x &= 1u;
|
||||
x ^= r1;
|
||||
}
|
||||
r5 += 1u;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32_t subghz_protocol_keeloq_common_word_rotate16(uint32_t v) {
|
||||
return (v >> 16) | (v << 16);
|
||||
}
|
||||
|
||||
inline uint32_t subghz_protocol_keeloq_common_decrypt_derived(
|
||||
uint32_t hop_encrypted,
|
||||
uint64_t derived_manufacturing_key,
|
||||
uint32_t outer_limit) {
|
||||
return subghz_protocol_keeloq_common_manufacturer_nl_extend(
|
||||
hop_encrypted,
|
||||
(uint32_t)derived_manufacturing_key,
|
||||
(uint32_t)(derived_manufacturing_key >> 32u),
|
||||
outer_limit);
|
||||
}
|
||||
|
||||
// Protocol (Manufacturer) specific learning
|
||||
// TODO: Better documentation for these functions
|
||||
|
||||
inline uint64_t subghz_protocol_keeloq_common_learning_aerf(uint32_t data, const uint64_t key) {
|
||||
uint32_t k_lo = (uint32_t)key;
|
||||
uint32_t k_hi = (uint32_t)(key >> 32);
|
||||
uint32_t d = data & 0x0FFFFFFFu;
|
||||
uint32_t x = d | 0x20000000u;
|
||||
x = subghz_protocol_keeloq_common_manufacturer_nl_extend(x, k_lo, k_hi, 0x40u);
|
||||
uint32_t k1 = x;
|
||||
x = d | 0x60000000u;
|
||||
x = subghz_protocol_keeloq_common_manufacturer_nl_extend(x, k_lo, k_hi, 0x40u);
|
||||
return ((uint64_t)x << 32) | k1;
|
||||
}
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_learning_erreka(uint32_t data, uint32_t mix, const uint64_t key) {
|
||||
uint32_t d = data & 0x0FFFFFFFu;
|
||||
uint32_t k1 = subghz_protocol_keeloq_common_decrypt(d | 0x20000000u, key);
|
||||
uint32_t r4 = mix >> 4;
|
||||
uint32_t r1 = (mix << 4) & 0xF000F000u;
|
||||
r4 = (r4 & 0x0F000F00u) | r1;
|
||||
uint32_t r5 = mix & 0x00FF00FFu;
|
||||
uint32_t x = r4 | r5;
|
||||
x |= 0x60000000u;
|
||||
uint32_t k2 = subghz_protocol_keeloq_common_decrypt(x, key);
|
||||
return ((uint64_t)k2 << 32) | k1;
|
||||
}
|
||||
|
||||
inline uint64_t subghz_protocol_keeloq_common_learning_pujol(uint32_t data, const uint64_t key) {
|
||||
uint32_t d = data & 0x0FFFFFFFu;
|
||||
uint32_t w1 = subghz_protocol_keeloq_common_decrypt(d | 0x20000000u, key);
|
||||
uint32_t w2 = subghz_protocol_keeloq_common_decrypt(d | 0x60000000u, key);
|
||||
uint32_t k1 = subghz_protocol_keeloq_common_word_rotate16(w1);
|
||||
uint32_t k2 = subghz_protocol_keeloq_common_word_rotate16(w2);
|
||||
return ((uint64_t)k2 << 32) | k1;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
// #define BENINCA_ARC_KEY_TYPE 9u -- RESERVED
|
||||
#define KEELOQ_LEARNING_SIMPLE_KINGGATES 10u
|
||||
#define KEELOQ_LEARNING_NORMAL_JAROLIFT 11u
|
||||
#define KEELOQ_LEARNING_ERREKA 12u
|
||||
#define KEELOQ_LEARNING_PUJOL 13u
|
||||
#define KEELOQ_LEARNING_AERF 14u
|
||||
#define KEELOQ_LEARNING_SIMPLE_JCM 15u
|
||||
|
||||
/**
|
||||
* Simple Learning Encrypt
|
||||
@@ -101,3 +105,19 @@ uint64_t subghz_protocol_keeloq_common_magic_serial_type2_learning(uint32_t data
|
||||
*/
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man);
|
||||
|
||||
// Protocol (Manufacturer) specific learning
|
||||
// TODO: Better documentation for these functions
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_learning_aerf(uint32_t data, const uint64_t key);
|
||||
|
||||
uint64_t
|
||||
subghz_protocol_keeloq_common_learning_erreka(uint32_t data, uint32_t mix, const uint64_t key);
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_learning_pujol(uint32_t data, const uint64_t key);
|
||||
|
||||
// Utils
|
||||
uint32_t subghz_protocol_keeloq_common_decrypt_derived(
|
||||
uint32_t hop_encrypted,
|
||||
uint64_t derived_manufacturing_key,
|
||||
uint32_t outer_limit);
|
||||
|
||||
@@ -57,7 +57,7 @@ bool subghz_protocol_keeloq_create_data(
|
||||
* @param preset Modulation, SubGhzRadioPreset
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_keeloq_bft_create_data(
|
||||
bool subghz_protocol_keeloq_seed_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
|
||||
Reference in New Issue
Block a user