Просмотр исходного кода

SubGhz: Add new man key (#817)

* SubGhz: fix kelog pattern
* SubGhz: add Keloog Secure Learning
* SubGhz: add man NICE_Smilo, NICE_MHOUSE, DEA, Genius, FAAC_RC,XT, Came_Space, DTM

Co-authored-by: あく <alleteam@gmail.com>
Skorpionm 4 лет назад
Родитель
Сommit
6792e24b6e

+ 7 - 2
assets/resources/subghz/keeloq_mfcodes

@@ -23,5 +23,10 @@ C38CBE29F22D0E83E58A52E94AA2485DA8E702FBDB89D27249473CB8A19AEF61
 9F0EB580F7474985E8460E1682451E213778B77A9CAB4734B75C5386851050BF
 2364EBB8237363B21226565675B9F478482CADAE41E795C27287E26137797C10
 775C9A28BA50D759FB438D0200121F01F7DB11986D44D3960F745EAA1E7A2CE2AD92AD718AFCD98BC3269C39F65ADC53
-6911E7EAFFAC15B4E3ABDAD271E92EAEFE1F2E288789EC7599AAA32986273306
-5387D67534234AFD8BAB90DC74BA39598B938526CBFAF14F75AA36A29C13836A31897A86D2E1178AE66191E771A7FEA4
+80F637A04446BF1FBEF3399307527403A15031FC4030F7C1E8217A2367B21A52
+1E3EC8CCECC14E8898D13BB2EEEC1EABABCD83D6930DBB8D381D8378EC5FAF22
+46A68DD969BFF20ADFAC767AFA87D3CA98AE6C056B0B4D43A5A24A7ABBD88D57
+FEC591F298259129A9EC9BE66D903C2D5D94A17D38CD889C878664FC3C118FDA
+2BC0AA2C0909417140615C7E901566A9AD2F88BCF500A0AF82A79BE4C0B013CE
+D9C9119FE35EB25800F60C2D5D2F018D43CC888147D469BF26F86A8DBABB2DCB
+6FFECFF334702D6E32B55B5CDE4191176D2D3CC3A3CE10E880425BD7FC262193

+ 62 - 41
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_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;
                 }
-                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))) {
+
+                // 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

+ 36 - 13
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;
+}

+ 18 - 9
lib/subghz/protocols/subghz_protocol_keeloq_common.h

@@ -2,7 +2,6 @@
 #include "subghz_protocol_common.h"
 #include "file-worker.h"
 
-
 #include <furi.h>
 
 /*
@@ -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);