diff --git a/assets/resources/subghz/keeloq_mfcodes b/assets/resources/subghz/keeloq_mfcodes index 9f5ff755..3733b76c 100644 --- a/assets/resources/subghz/keeloq_mfcodes +++ b/assets/resources/subghz/keeloq_mfcodes @@ -23,5 +23,10 @@ C38CBE29F22D0E83E58A52E94AA2485DA8E702FBDB89D27249473CB8A19AEF61 9F0EB580F7474985E8460E1682451E213778B77A9CAB4734B75C5386851050BF 2364EBB8237363B21226565675B9F478482CADAE41E795C27287E26137797C10 775C9A28BA50D759FB438D0200121F01F7DB11986D44D3960F745EAA1E7A2CE2AD92AD718AFCD98BC3269C39F65ADC53 -6911E7EAFFAC15B4E3ABDAD271E92EAEFE1F2E288789EC7599AAA32986273306 -5387D67534234AFD8BAB90DC74BA39598B938526CBFAF14F75AA36A29C13836A31897A86D2E1178AE66191E771A7FEA4 +80F637A04446BF1FBEF3399307527403A15031FC4030F7C1E8217A2367B21A52 +1E3EC8CCECC14E8898D13BB2EEEC1EABABCD83D6930DBB8D381D8378EC5FAF22 +46A68DD969BFF20ADFAC767AFA87D3CA98AE6C056B0B4D43A5A24A7ABBD88D57 +FEC591F298259129A9EC9BE66D903C2D5D94A17D38CD889C878664FC3C118FDA +2BC0AA2C0909417140615C7E901566A9AD2F88BCF500A0AF82A79BE4C0B013CE +D9C9119FE35EB25800F60C2D5D2F018D43CC888147D469BF26F86A8DBABB2DCB +6FFECFF334702D6E32B55B5CDE4191176D2D3CC3A3CE10E880425BD7FC262193 diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index f3f33085..42352462 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -49,6 +49,20 @@ void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance) { free(instance); } +static inline bool subghz_protocol_keeloq_check_decrypt( + SubGhzProtocolKeeloq* instance, + uint32_t decrypt, + uint8_t btn, + uint32_t end_serial) { + furi_assert(instance); + if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) || + ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) { + instance->common.cnt = decrypt & 0x0000FFFF; + return true; + } + return false; +} + /** Checking the accepted code against the database manafacture key * * @param instance SubGhzProtocolKeeloq instance @@ -60,10 +74,15 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( SubGhzProtocolKeeloq* instance, uint32_t fix, uint32_t hop) { - uint16_t end_serial = (uint16_t)(fix & 0x3FF); + // protocol HCS300 uses 10 bits in discriminator, HCS200 uses 8 bits, for backward compatibility, we are looking for the 8-bit pattern + // HCS300 -> uint16_t end_serial = (uint16_t)(fix & 0x3FF); + // HCS200 -> uint16_t end_serial = (uint16_t)(fix & 0xFF); + + uint16_t end_serial = (uint16_t)(fix & 0xFF); uint8_t btn = (uint8_t)(fix >> 28); uint32_t decrypt = 0; - uint64_t man_normal_learning; + uint64_t man_learning; + uint32_t seed = 0; for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { @@ -71,36 +90,36 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( case KEELOQ_LEARNING_SIMPLE: // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); - if((decrypt >> 28 == btn) && - (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, 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 = + man_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) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + break; + case KEELOQ_LEARNING_SECURE: + man_learning = subghz_protocol_keeloq_common_secure_learning( + fix, seed, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, 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 >> 28 == btn) && - (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt = decrypt & 0x0000FFFF; return 1; } // Check for mirrored man @@ -111,40 +130,42 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( man_rev = man_rev | man_rev_byte << (56 - i); } decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev); - if((decrypt >> 28 == btn) && - (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, 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 = + man_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) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, 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 >> 28 == btn) && - (((((uint16_t)(decrypt >> 16)) & 0x3FF) == end_serial) || - ((((uint16_t)(decrypt >> 16)) & 0x3FF) == 0))) { + man_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + + // Secure Learning + man_learning = subghz_protocol_keeloq_common_secure_learning( + fix, seed, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + + // Check for mirrored man + + man_learning = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { instance->manufacture_name = string_get_cstr(manufacture_code->name); - instance->common.cnt = decrypt & 0x0000FFFF; return 1; } break; @@ -214,7 +235,7 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context) { uint32_t decrypt = instance->common.btn << 28 | (instance->common.serial & 0x3FF) << 16 | instance->common.cnt; uint32_t hop = 0; - uint64_t man_normal_learning = 0; + uint64_t man_learning = 0; int res = 0; for @@ -228,9 +249,9 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context) { break; case KEELOQ_LEARNING_NORMAL: //Simple Learning - man_normal_learning = + man_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); - hop = subghz_protocol_keeloq_common_encrypt(decrypt, man_normal_learning); + hop = subghz_protocol_keeloq_common_encrypt(decrypt, man_learning); break; case KEELOQ_LEARNING_UNKNOWN: hop = 0; //todo diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.c b/lib/subghz/protocols/subghz_protocol_keeloq_common.c index 1c69f701..0726a604 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.c @@ -12,8 +12,10 @@ */ 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); + 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; } @@ -24,8 +26,9 @@ inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const */ 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)); + 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; } @@ -34,16 +37,36 @@ inline uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const * @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; +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 |= 0x20000000; + k1 = subghz_protocol_keeloq_common_decrypt(data, key); - data&=0x0FFFFFFF; - data|=0x60000000; - k2=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 + return ((uint64_t)k2 << 32) | k1; // key - shifrovanoya } + +/** Secure Learning + * @param data - serial number (28bit) + * @param seed - serial number (32bit) + * @param key - manufacture (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t subghz_protocol_keeloq_common_secure_learning( + uint32_t data, + uint32_t seed, + const uint64_t key) { + uint32_t k1, k2; + + data &= 0x0FFFFFFF; + k1 = subghz_protocol_keeloq_common_decrypt(data, key); + k2 = subghz_protocol_keeloq_common_decrypt(seed, key); + + return ((uint64_t)k1 << 32) | k2; +} \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.h b/lib/subghz/protocols/subghz_protocol_keeloq_common.h index 41cd76e5..cd21a039 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.h @@ -2,7 +2,6 @@ #include "subghz_protocol_common.h" #include "file-worker.h" - #include /* @@ -12,19 +11,19 @@ * */ -#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) +#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 - +#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 @@ -46,3 +45,13 @@ uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const uint64 * @return manufacture for this serial number (64bit) */ uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint64_t key); + +/** Secure Learning + * @param data - serial number (28bit) + * @param seed - serial number (32bit) + * @param key - manufacture (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t + subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key); \ No newline at end of file