]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
descrambler: fix the descrambling modes (CSA CBC, DES NCB, AES ECB)
authorJaroslav Kysela <perex@perex.cz>
Wed, 24 May 2017 12:36:52 +0000 (14:36 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 24 May 2017 12:36:52 +0000 (14:36 +0200)
src/descrambler.h
src/descrambler/caclient.c
src/descrambler/caclient.h
src/descrambler/capmt.c
src/descrambler/cccam.c
src/descrambler/constcw.c
src/descrambler/cwc.c
src/descrambler/tvhcsa.c

index 7060469ecdea64b6aebdc0804c9aefcf393732e8..e635bf3bfd09dc25f80d5558edab85c8d63f7cad 100644 (file)
@@ -31,9 +31,10 @@ struct mpegts_table;
 struct mpegts_mux;
 struct th_descrambler_data;
 
-#define DESCRAMBLER_NONE 0
-#define DESCRAMBLER_DES  1
-#define DESCRAMBLER_AES  2
+#define DESCRAMBLER_NONE     0
+#define DESCRAMBLER_CSA_CBC  1
+#define DESCRAMBLER_DES_NCB  2 /* no block cipher mode! */
+#define DESCRAMBLER_AES_ECB  3
 
 /**
  * Descrambler superclass
index c16234f00273b792e8e324ec41865ef34d902cd9..8432804d9464d2fa6c24384d54f07aa410dc84a1 100644 (file)
@@ -31,8 +31,9 @@ const idclass_t *caclient_classes[] = {
   &caclient_capmt_class,
 #endif
 #if ENABLE_CONSTCW
-  &caclient_ccw_des_class,
-  &caclient_ccw_aes_class,
+  &caclient_ccw_csa_cbc_class,
+  &caclient_ccw_des_ncb_class,
+  &caclient_ccw_aes_ecb_class,
 #endif
   NULL
 };
@@ -92,8 +93,8 @@ caclient_create
   if ((s = htsmsg_get_str(conf, "class")) != NULL)
     c = caclient_class_find(s);
   if (c == NULL) {
-    tvherror(LS_CACLIENT, "wrong class %s!", s);
-    abort();
+    tvherror(LS_CACLIENT, "unknown class %s!", s);
+    return NULL;
   }
 #if ENABLE_CWC
   if (c == &caclient_cwc_class)
@@ -108,9 +109,9 @@ caclient_create
     cac = capmt_create();
 #endif
 #if ENABLE_CONSTCW
-  if (c == &caclient_ccw_des_class)
-    cac = constcw_create();
-  if (c == &caclient_ccw_aes_class)
+  if (c == &caclient_ccw_csa_cbc_class ||
+      c == &caclient_ccw_des_ncb_class ||
+      c == &caclient_ccw_aes_ecb_class)
     cac = constcw_create();
 #endif
   if (cac == NULL) {
index 0c96c8fd434e1ec004ed1a5452f092ec2298aa67..d7db76512646daa7b33e551b800d9c40e7f0440f 100644 (file)
@@ -28,8 +28,9 @@ extern const idclass_t caclient_class;
 extern const idclass_t caclient_cwc_class;
 extern const idclass_t caclient_cccam_class;
 extern const idclass_t caclient_capmt_class;
-extern const idclass_t caclient_ccw_des_class;
-extern const idclass_t caclient_ccw_aes_class;
+extern const idclass_t caclient_ccw_csa_cbc_class;
+extern const idclass_t caclient_ccw_des_ncb_class;
+extern const idclass_t caclient_ccw_aes_ecb_class;
 
 TAILQ_HEAD(caclient_entry_queue, caclient);
 
index 2b8c728de743a3b48e5c3601200c49a610f24ea6..c84c3b282d77c4c937114debd0390f3ddeeacf2b 100644 (file)
@@ -1264,9 +1264,9 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
     if (adapter >= MAX_CA || index >= MAX_INDEX)
       return;
     if (parity == 0) {
-      capmt_process_key(capmt, adapter, index, DESCRAMBLER_DES, cw, empty, 1);
+      capmt_process_key(capmt, adapter, index, DESCRAMBLER_CSA_CBC, cw, empty, 1);
     } else if (parity == 1) {
-      capmt_process_key(capmt, adapter, index, DESCRAMBLER_DES, empty, cw, 1);
+      capmt_process_key(capmt, adapter, index, DESCRAMBLER_CSA_CBC, empty, cw, 1);
     } else
       tvherror(LS_CAPMT, "%s: Invalid parity %d in CA_SET_DESCR for adapter%d", capmt_name(capmt), parity, adapter);
 
@@ -1286,9 +1286,9 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
     if (adapter >= MAX_CA || index >= MAX_INDEX)
       return;
     if (parity == 0) {
-      capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES, cw, empty, 1);
+      capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES_ECB, cw, empty, 1);
     } else if (parity == 1) {
-      capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES, empty, cw, 1);
+      capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES_ECB, empty, cw, 1);
     } else
       tvherror(LS_CAPMT, "%s: Invalid parity %d in CA_SET_DESCR_AES for adapter%d", capmt_name(capmt), parity, adapter);
 
@@ -1619,7 +1619,7 @@ handle_ca0_wrapper(capmt_t *capmt)
 
       capmt_process_key(capmt, 0,
                         buffer[0] | ((uint16_t)buffer[1] << 8),
-                        DESCRAMBLER_DES,
+                        DESCRAMBLER_CSA_CBC,
                         buffer + 2, buffer + 10,
                         ret == 18);
     }
index 8466e17b3b5e01b6e49cb390d24b375a99f32dcf..7af24f739dcc60f90f729366cabaee8bd82c3f1a 100644 (file)
@@ -701,7 +701,7 @@ forbid:
     es3 = *es;
     pthread_mutex_unlock(&cccam->cccam_mutex);
     descrambler_keys((th_descrambler_t *)ct,
-                     off == 16 ? DESCRAMBLER_AES : DESCRAMBLER_DES,
+                     off == 16 ? DESCRAMBLER_AES_ECB : DESCRAMBLER_CSA_CBC,
                      dcw, dcw + off);
     snprintf(chaninfo, sizeof(chaninfo), "%s:%i", cccam->cccam_hostname, cccam->cccam_port);
     descrambler_notify((th_descrambler_t *)ct,
index 8117d2000b689489a98bd257bee0705dbdfe7187..14f9c5b7f15caf03fb7a98e6125818df8bfe0ea1 100644 (file)
@@ -55,6 +55,21 @@ constcw_name(constcw_t *ccw)
   return idnode_get_title(&ccw->cac_id, NULL);
 }
 
+/**
+ *
+ */
+static int
+constcw_algo(caclient_t *cac)
+{
+  constcw_t *ccw = (constcw_t *)cac;
+
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_des_ncb_class))
+    return DESCRAMBLER_DES_NCB;
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_aes_ecb_class))
+    return DESCRAMBLER_AES_ECB;
+  return DESCRAMBLER_CSA_CBC;
+}
+
 /**
  *
  */
@@ -63,7 +78,9 @@ constcw_key_size(caclient_t *cac)
 {
   constcw_t *ccw = (constcw_t *)cac;
 
-  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_des_class))
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_csa_cbc_class))
+    return 8;
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_des_ncb_class))
     return 8;
   return 16;
 }
@@ -151,8 +168,7 @@ constcw_service_start(caclient_t *cac, service_t *t)
 
   LIST_INSERT_HEAD(&ccw->ccw_services, ct, cs_link);
 
-  descrambler_keys(td, constcw_key_size(cac) == 8 ?
-                   DESCRAMBLER_DES : DESCRAMBLER_AES,
+  descrambler_keys(td, constcw_algo(cac),
                    ccw->ccw_key_even, ccw->ccw_key_odd);
 }
 
@@ -278,11 +294,77 @@ constcw_class_key_odd_get(void *o)
   return constcw_class_key_get(o, ccw->ccw_key_odd);
 }
 
-const idclass_t caclient_ccw_des_class =
+const idclass_t caclient_ccw_csa_cbc_class =
+{
+  .ic_super      = &caclient_class,
+  .ic_class      = "caclient_ccw_csa_cbc",
+  .ic_caption    = N_("CSA CBC Constant Code Word"),
+  .ic_properties = (const property_t[]){
+    {
+      .type     = PT_U16,
+      .id       = "caid",
+      .name     = N_("CA ID"),
+      .desc     = N_("Conditional Access Identification."),
+      .off      = offsetof(constcw_t, ccw_caid),
+      .opts     = PO_HEXA,
+      .def.u16  = 0x2600
+    },
+    {
+      .type     = PT_U32,
+      .id       = "providerid",
+      .name     = N_("Provider ID"),
+      .desc     = N_("The provider's ID."),
+      .off      = offsetof(constcw_t, ccw_providerid),
+      .opts     = PO_HEXA,
+      .def.u32  = 0
+    },
+    {
+      .type     = PT_U16,
+      .id       = "tsid",
+      .name     = N_("Transponder ID"),
+      .desc     = N_("The transponder ID."),
+      .off      = offsetof(constcw_t, ccw_tsid),
+      .opts     = PO_HEXA,
+      .def.u16  = 1,
+    },
+    {
+      .type     = PT_U16,
+      .id       = "sid",
+      .name     = N_("Service ID"),
+      .desc     = N_("The service ID."),
+      .off      = offsetof(constcw_t, ccw_sid),
+      .opts     = PO_HEXA,
+      .def.u16  = 1,
+    },
+    {
+      .type     = PT_STR,
+      .id       = "key_even",
+      .name     = N_("Even key"),
+      .desc     = N_("Even key."),
+      .set      = constcw_class_key_even_set,
+      .get      = constcw_class_key_even_get,
+      .opts     = PO_PASSWORD,
+      .def.s    = "00:00:00:00:00:00:00:00",
+    },
+    {
+      .type     = PT_STR,
+      .id       = "key_odd",
+      .name     = N_("Odd key"),
+      .desc     = N_("Odd key."),
+      .set      = constcw_class_key_odd_set,
+      .get      = constcw_class_key_odd_get,
+      .opts     = PO_PASSWORD,
+      .def.s    = "00:00:00:00:00:00:00:00",
+    },
+    { }
+  }
+};
+
+const idclass_t caclient_ccw_des_ncb_class =
 {
   .ic_super      = &caclient_class,
-  .ic_class      = "caclient_ccw_des",
-  .ic_caption    = N_("DES Constant Code Word"),
+  .ic_class      = "caclient_ccw_des_ncb",
+  .ic_caption    = N_("DES NCB Constant Code Word"),
   .ic_properties = (const property_t[]){
     {
       .type     = PT_U16,
@@ -344,11 +426,11 @@ const idclass_t caclient_ccw_des_class =
   }
 };
 
-const idclass_t caclient_ccw_aes_class =
+const idclass_t caclient_ccw_aes_ecb_class =
 {
   .ic_super      = &caclient_class,
-  .ic_class      = "caclient_ccw_aes",
-  .ic_caption    = N_("AES Constant Code Word"),
+  .ic_class      = "caclient_ccw_aes_ecb",
+  .ic_caption    = N_("AES ECB Constant Code Word"),
   .ic_properties = (const property_t[]){
     {
       .type     = PT_U16,
index 44a1d26e20823eb8648de1e3118df008fb7725ab..5b1fd9798c571aa3c73bf76d68067ef5121890ed 100644 (file)
@@ -849,7 +849,7 @@ forbid:
     es3 = *es;
     pthread_mutex_unlock(&cwc->cwc_mutex);
     descrambler_keys((th_descrambler_t *)ct,
-                     off == 16 ? DESCRAMBLER_AES : DESCRAMBLER_DES,
+                     off == 16 ? DESCRAMBLER_AES_ECB : DESCRAMBLER_CSA_CBC,
                      msg + 3, msg + 3 + off);
     snprintf(chaninfo, sizeof(chaninfo), "%s:%i", cwc->cwc_hostname, cwc->cwc_port);
     descrambler_notify((th_descrambler_t *)ct,
index 99ff46a018d1fb963031ed4412462d98a111e39a..137823be487839d4af8a15497df4b5fcec8b5ec6 100644 (file)
@@ -43,7 +43,7 @@ tvhcsa_aes_descramble
 }
 
 static void
-tvhcsa_des_flush
+tvhcsa_csa_cbc_flush
   ( tvhcsa_t *csa, struct mpegts_service *s )
 {
 #if ENABLE_DVBCSA
@@ -90,7 +90,7 @@ tvhcsa_des_flush
 }
 
 static void
-tvhcsa_des_descramble
+tvhcsa_csa_cbc_descramble
   ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int tsb_len )
 {
   const uint8_t *tsb_end = tsb + tsb_len;
@@ -149,7 +149,7 @@ tvhcsa_des_descramble
    } while(0);
 
    if(csa->csa_fill == csa->csa_cluster_size)
-     tvhcsa_des_flush(csa, s);
+     tvhcsa_csa_cbc_flush(csa, s);
 
   }
 
@@ -161,7 +161,7 @@ tvhcsa_des_descramble
     csa->csa_fill++;
 
     if(csa->csa_fill == csa->csa_cluster_size)
-      tvhcsa_des_flush(csa, s);
+      tvhcsa_csa_cbc_flush(csa, s);
 
   }
 
@@ -176,12 +176,12 @@ tvhcsa_set_type( tvhcsa_t *csa, int type )
   if (csa->csa_descramble)
     return -1;
   switch (type) {
-  case DESCRAMBLER_DES:
-    csa->csa_descramble = tvhcsa_des_descramble;
-    csa->csa_flush      = tvhcsa_des_flush;
+  case DESCRAMBLER_CSA_CBC:
+    csa->csa_descramble = tvhcsa_csa_cbc_descramble;
+    csa->csa_flush      = tvhcsa_csa_cbc_flush;
     csa->csa_keylen     = 8;
     break;
-  case DESCRAMBLER_AES:
+  case DESCRAMBLER_AES_ECB:
     csa->csa_descramble = tvhcsa_aes_descramble;
     csa->csa_flush      = tvhcsa_aes_flush;
     csa->csa_keylen     = 16;
@@ -197,14 +197,14 @@ tvhcsa_set_type( tvhcsa_t *csa, int type )
 void tvhcsa_set_key_even( tvhcsa_t *csa, const uint8_t *even )
 {
   switch (csa->csa_type) {
-  case DESCRAMBLER_DES:
+  case DESCRAMBLER_CSA_CBC:
 #if ENABLE_DVBCSA
     dvbcsa_bs_key_set(even, csa->csa_key_even);
 #else
     set_even_control_word((csa)->csa_keys, even);
 #endif
     break;
-  case DESCRAMBLER_AES:
+  case DESCRAMBLER_AES_ECB:
     aes_set_even_control_word(csa->csa_aes_keys, even);
     break;
   default:
@@ -216,14 +216,14 @@ void tvhcsa_set_key_odd( tvhcsa_t *csa, const uint8_t *odd )
 {
   assert(csa->csa_type);
   switch (csa->csa_type) {
-  case DESCRAMBLER_DES:
+  case DESCRAMBLER_CSA_CBC:
 #if ENABLE_DVBCSA
     dvbcsa_bs_key_set(odd, csa->csa_key_odd);
 #else
     set_odd_control_word((csa)->csa_keys, odd);
 #endif
     break;
-  case DESCRAMBLER_AES:
+  case DESCRAMBLER_AES_ECB:
     aes_set_odd_control_word(csa->csa_aes_keys, odd);
     break;
   default: