]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
descrambler: fix the AES 64/128 mess
authorJaroslav Kysela <perex@perex.cz>
Tue, 30 May 2017 12:31:34 +0000 (14:31 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 30 May 2017 12:33:39 +0000 (14:33 +0200)
Makefile
src/descrambler.h
src/descrambler/algo/libaes128dec.c [new file with mode: 0644]
src/descrambler/algo/libaes128dec.h [new file with mode: 0644]
src/descrambler/algo/libaesdec.c
src/descrambler/caclient.c
src/descrambler/caclient.h
src/descrambler/constcw.c
src/descrambler/tsdebugcw.c
src/descrambler/tvhcsa.c
src/descrambler/tvhcsa.h

index 56aa69eaebafbe94fe886e9abe3c4ee4a0260437..ebe3fb3f12903aecbbcdfe812a26216435d84970 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -547,6 +547,7 @@ endif
 
 # crypto algorithms
 SRCS-${CONFIG_SSL} += src/descrambler/algo/libaesdec.c
+SRCS-${CONFIG_SSL} += src/descrambler/algo/libaes128dec.c
 SRCS-${CONFIG_SSL} += src/descrambler/algo/libdesdec.c
 
 # DBUS
index bbbbdca554f0f25b9f492b337c5c4099ae633a4b..85d08f8dbba8255b35d9fa1f3f7e1bbad7148da9 100644 (file)
@@ -31,10 +31,15 @@ struct mpegts_table;
 struct mpegts_mux;
 struct th_descrambler_data;
 
-#define DESCRAMBLER_NONE     0
-#define DESCRAMBLER_CSA_CBC  1
-#define DESCRAMBLER_DES_NCB  2 /* no block cipher mode! */
-#define DESCRAMBLER_AES_ECB  3
+#define DESCRAMBLER_NONE       0
+/* 64-bit keys */
+#define DESCRAMBLER_CSA_CBC    1
+#define DESCRAMBLER_DES_NCB    2 /* no block cipher mode! */
+#define DESCRAMBLER_AES_ECB    3
+/* 128-bit keys */
+#define DESCRAMBLER_AES128_ECB  16
+
+#define DESCRAMBLER_KEY_SIZE(type) ((type >= DESCRAMBLER_AES128_ECB) ? 16 : 8)
 
 /**
  * Descrambler superclass
diff --git a/src/descrambler/algo/libaes128dec.c b/src/descrambler/algo/libaes128dec.c
new file mode 100644 (file)
index 0000000..5e5088d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * libaesdec.c
+ *
+ *  Created on: Jun 22, 2014
+ *      Author: spdfrk1
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "openssl/aes.h"
+
+#include "libaes128dec.h"
+
+/* key structure */
+typedef struct aes128_priv {
+  AES_KEY keys[2]; /* 0 = even, 1 = odd */
+} aes128_priv_t;
+
+/* even cw represents one full 128-bit AES key */
+void aes128_set_even_control_word(void *keys, const uint8_t *pk)
+{
+  AES_set_decrypt_key(pk, 128, &((aes128_priv_t *) keys)->keys[0]);
+}
+
+/* odd cw represents one full 128-bit AES key */
+void aes128_set_odd_control_word(void *keys, const uint8_t *pk)
+{
+  AES_set_decrypt_key(pk, 128, &((aes128_priv_t *) keys)->keys[1]);
+}
+
+/* set control words */
+void aes128_set_control_words(void *keys,
+                           const uint8_t *ev,
+                           const uint8_t *od)
+{
+  AES_set_decrypt_key(ev, 128, &((aes128_priv_t *) keys)->keys[0]);
+  AES_set_decrypt_key(od, 128, &((aes128_priv_t *) keys)->keys[1]);
+}
+
+/* allocate key structure */
+void * aes128_get_priv_struct(void)
+{
+  aes128_priv_t *keys;
+
+  keys = (aes128_priv_t *) malloc(sizeof(aes128_priv_t));
+  if (keys) {
+    static const uint8_t pk[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    aes128_set_control_words(keys, pk, pk);
+  }
+  return keys;
+}
+
+/* free key structure */
+void aes128_free_priv_struct(void *keys)
+{
+  free(keys);
+}
+
+/* decrypt */
+void aes128_decrypt_packet(void *keys, const uint8_t *pkt)
+{
+  uint_fast8_t ev_od = 0;
+  uint_fast8_t xc0, offset;
+  AES_KEY *k;
+
+  // skip reserved and not encrypted pkt
+  if (((xc0 = pkt[3]) & 0x80) == 0)
+    return;
+
+  ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
+  ((uint8_t *)pkt)[3] = xc0 & 0x3f;  // consider it decrypted now
+  if (xc0 & 0x20) { // incomplete packet
+    offset = 4 + pkt[4] + 1;
+    if (offset + 16 > 188) { // decrypted==encrypted!
+      return;  // this doesn't need more processing
+    }
+  } else {
+    offset = 4;
+  }
+
+  k = &((aes128_priv_t *) keys)->keys[ev_od];
+  for (; offset <= (188 - 16); offset += 16) {
+    AES_ecb_encrypt(pkt + offset, (uint8_t *)(pkt + offset), k, AES_DECRYPT);
+  }
+}
diff --git a/src/descrambler/algo/libaes128dec.h b/src/descrambler/algo/libaes128dec.h
new file mode 100644 (file)
index 0000000..380008b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * libaes128dec.h
+ *
+ * Created on: Jun 22, 2014
+ *      Author: spdfrk1
+ */
+
+#ifndef LIBAES128DEC_H_
+#define LIBAES128DEC_H_
+
+#include <stdint.h>
+#include "build.h"
+
+#if ENABLE_SSL
+
+void *aes128_get_priv_struct(void);
+void aes128_free_priv_struct(void *keys);
+void aes128_set_control_words(void *keys, const uint8_t *even, const uint8_t *odd);
+void aes128_set_even_control_word(void *keys, const uint8_t *even);
+void aes128_set_odd_control_word(void *keys, const uint8_t *odd);
+void aes128_decrypt_packet(void *keys, const uint8_t *pkt);
+
+#else
+
+// empty functions
+static inline void *aes128_get_priv_struct(void)  { return NULL; };
+static inline void aes128_free_priv_struct(void *keys) { return; };
+static inline void aes128_set_control_words(void *keys, const uint8_t *even, const uint8_t *odd) { return; };
+static inline void aes128_set_even_control_word(void *keys, const uint8_t *even) { return; };
+static inline void aes128_set_odd_control_word(void *keys, const uint8_t *odd) { return; };
+static inline void aes128_decrypt_packet(void *keys, const uint8_t *pkt) { return; };
+
+#endif
+
+#endif /* LIBAES128DEC_H_ */
index 4aac4bc78c53eb4beb294504b483c51937f0702a..81374cb15b8b10f20382fe6180543d0b1bf0001f 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * libaesdec.c
  *
- *  Created on: Jun 22, 2014
- *      Author: spdfrk1
+ * Based on code from spdfrk1
  */
 
 #include <sys/types.h>
@@ -19,16 +18,16 @@ typedef struct aes_priv {
   AES_KEY keys[2]; /* 0 = even, 1 = odd */
 } aes_priv_t;
 
-/* even cw represents one full 128-bit AES key */
+/* even cw represents one full 64-bit AES key */
 void aes_set_even_control_word(void *keys, const uint8_t *pk)
 {
-  AES_set_decrypt_key(pk, 128, &((aes_priv_t *) keys)->keys[0]);
+  AES_set_decrypt_key(pk, 64, &((aes_priv_t *) keys)->keys[0]);
 }
 
-/* odd cw represents one full 128-bit AES key */
+/* odd cw represents one full 64-bit AES key */
 void aes_set_odd_control_word(void *keys, const uint8_t *pk)
 {
-  AES_set_decrypt_key(pk, 128, &((aes_priv_t *) keys)->keys[1]);
+  AES_set_decrypt_key(pk, 64, &((aes_priv_t *) keys)->keys[1]);
 }
 
 /* set control words */
@@ -36,8 +35,8 @@ void aes_set_control_words(void *keys,
                            const uint8_t *ev,
                            const uint8_t *od)
 {
-  AES_set_decrypt_key(ev, 128, &((aes_priv_t *) keys)->keys[0]);
-  AES_set_decrypt_key(od, 128, &((aes_priv_t *) keys)->keys[1]);
+  AES_set_decrypt_key(ev, 64, &((aes_priv_t *) keys)->keys[0]);
+  AES_set_decrypt_key(od, 64, &((aes_priv_t *) keys)->keys[1]);
 }
 
 /* allocate key structure */
@@ -82,7 +81,7 @@ void aes_decrypt_packet(void *keys, const uint8_t *pkt)
   }
 
   k = &((aes_priv_t *) keys)->keys[ev_od];
-  for (; offset <= (188 - 16); offset += 16) {
+  for (; offset <= (188 - 8); offset += 8) {
     AES_ecb_encrypt(pkt + offset, (uint8_t *)(pkt + offset), k, AES_DECRYPT);
   }
 }
index 8432804d9464d2fa6c24384d54f07aa410dc84a1..79042b4a6e57d2ab15842a6b8de740e64da418c0 100644 (file)
@@ -34,6 +34,7 @@ const idclass_t *caclient_classes[] = {
   &caclient_ccw_csa_cbc_class,
   &caclient_ccw_des_ncb_class,
   &caclient_ccw_aes_ecb_class,
+  &caclient_ccw_aes128_ecb_class,
 #endif
   NULL
 };
index b02c6349d4893a6a4cef357e08dba9373cf6dd17..cb1c275c654fd3ccd8a5d17c5e3733868c61d80c 100644 (file)
@@ -31,6 +31,7 @@ extern const idclass_t caclient_capmt_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;
+extern const idclass_t caclient_ccw_aes128_ecb_class;
 
 TAILQ_HEAD(caclient_entry_queue, caclient);
 
index e703a7133cf6d720e20fa394cce1728f4849239d..12b593c7f9d0ad41b82e0d3f8c5239afccc495a9 100644 (file)
@@ -67,6 +67,8 @@ constcw_algo(caclient_t *cac)
     return DESCRAMBLER_DES_NCB;
   if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_aes_ecb_class))
     return DESCRAMBLER_AES_ECB;
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_aes128_ecb_class))
+    return DESCRAMBLER_AES128_ECB;
   return DESCRAMBLER_CSA_CBC;
 }
 
@@ -78,11 +80,9 @@ constcw_key_size(caclient_t *cac)
 {
   constcw_t *ccw = (constcw_t *)cac;
 
-  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;
+  if (idnode_is_instance(&ccw->cac_id, &caclient_ccw_aes128_ecb_class))
+    return 16;
+  return 8;
 }
 
 /*
@@ -431,6 +431,72 @@ const idclass_t caclient_ccw_aes_ecb_class =
   .ic_super      = &caclient_class,
   .ic_class      = "caclient_ccw_aes_ecb",
   .ic_caption    = N_("AES ECB 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_aes128_ecb_class =
+{
+  .ic_super      = &caclient_class,
+  .ic_class      = "caclient_ccw_aes128_ecb",
+  .ic_caption    = N_("AES128 ECB Constant Code Word"),
   .ic_properties = (const property_t[]){
     {
       .type     = PT_U16,
index b42449ac12a1ff76c96338423f8ff24400edc820..3bcc7c20309fe0a7901185ff8542c7bc27ee584d 100644 (file)
@@ -116,7 +116,7 @@ tsdebugcw_new_keys(service_t *t, int type, uint16_t pid, uint8_t *odd, uint8_t *
   th_descrambler_t *td;
   tsdebugcw_service_t *ct;
   tsdebugcw_request_t *ctr;
-  int keylen = type == DESCRAMBLER_AES_ECB ? 16 : 8;
+  int keylen = DESCRAMBLER_KEY_SIZE(type);
 
   LIST_FOREACH(td, &t->s_descramblers, td_service_link)
     if (td->td_stop == tsdebugcw_service_destroy)
index af7b4923185ff9b4393aac3e26e02679f4c40965..3f909e746be2c4d24bc4a17b3a645922fb373a65 100644 (file)
 #include "input.h"
 #include "input/mpegts/tsdemux.h"
 
+#include "descrambler/algo/libaesdec.h"
+#include "descrambler/algo/libaes128dec.h"
+#include "descrambler/algo/libdesdec.h"
+
 #include <stdlib.h>
 #include <unistd.h>
 #include <assert.h>
@@ -38,7 +42,18 @@ tvhcsa_aes_ecb_descramble
   const uint8_t *tsb2, *end2;
 
   for (tsb2 = tsb, end2 = tsb + len; tsb2 < end2; tsb2 += 188)
-    aes_decrypt_packet(csa->csa_aes_priv, tsb2);
+    aes_decrypt_packet(csa->csa_priv, tsb2);
+  ts_recv_packet2(s, tsb, len);
+}
+
+static void
+tvhcsa_aes128_ecb_descramble
+  ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int len )
+{
+  const uint8_t *tsb2, *end2;
+
+  for (tsb2 = tsb, end2 = tsb + len; tsb2 < end2; tsb2 += 188)
+    aes128_decrypt_packet(csa->csa_priv, tsb2);
   ts_recv_packet2(s, tsb, len);
 }
 
@@ -49,7 +64,7 @@ tvhcsa_des_ncb_descramble
   const uint8_t *tsb2, *end2;
 
   for (tsb2 = tsb, end2 = tsb + len; tsb2 < end2; tsb2 += 188)
-    des_decrypt_packet(csa->csa_des_priv, tsb2);
+    des_decrypt_packet(csa->csa_priv, tsb2);
   ts_recv_packet2(s, tsb, len);
 }
 
@@ -212,15 +227,21 @@ tvhcsa_set_type( tvhcsa_t *csa, int type )
 #endif
     break;
   case DESCRAMBLER_DES_NCB:
-    csa->csa_des_priv      = des_get_priv_struct();
+    csa->csa_priv          = des_get_priv_struct();
     csa->csa_descramble    = tvhcsa_des_ncb_descramble;
     csa->csa_flush         = tvhcsa_empty_flush;
     csa->csa_keylen        = 8;
     break;
   case DESCRAMBLER_AES_ECB:
-    csa->csa_aes_priv      = aes_get_priv_struct();
+    csa->csa_priv          = aes_get_priv_struct();
     csa->csa_descramble    = tvhcsa_aes_ecb_descramble;
     csa->csa_flush         = tvhcsa_empty_flush;
+    csa->csa_keylen        = 8;
+    break;
+  case DESCRAMBLER_AES128_ECB:
+    csa->csa_priv          = aes128_get_priv_struct();
+    csa->csa_descramble    = tvhcsa_aes128_ecb_descramble;
+    csa->csa_flush         = tvhcsa_empty_flush;
     csa->csa_keylen        = 16;
     break;
   default:
@@ -242,10 +263,13 @@ void tvhcsa_set_key_even( tvhcsa_t *csa, const uint8_t *even )
 #endif
     break;
   case DESCRAMBLER_DES_NCB:
-    des_set_even_control_word(csa->csa_des_priv, even);
+    des_set_even_control_word(csa->csa_priv, even);
     break;
   case DESCRAMBLER_AES_ECB:
-    aes_set_even_control_word(csa->csa_aes_priv, even);
+    aes_set_even_control_word(csa->csa_priv, even);
+    break;
+  case DESCRAMBLER_AES128_ECB:
+    aes128_set_even_control_word(csa->csa_priv, even);
     break;
   default:
     assert(0);
@@ -264,10 +288,13 @@ void tvhcsa_set_key_odd( tvhcsa_t *csa, const uint8_t *odd )
 #endif
     break;
   case DESCRAMBLER_DES_NCB:
-    des_set_odd_control_word(csa->csa_des_priv, odd);
+    des_set_odd_control_word(csa->csa_priv, odd);
     break;
   case DESCRAMBLER_AES_ECB:
-    aes_set_odd_control_word(csa->csa_aes_priv, odd);
+    aes_set_odd_control_word(csa->csa_priv, odd);
+    break;
+  case DESCRAMBLER_AES128_ECB:
+    aes128_set_odd_control_word(csa->csa_priv, odd);
     break;
   default:
     assert(0);
@@ -311,12 +338,24 @@ tvhcsa_destroy ( tvhcsa_t *csa )
     free(csa->csa_tsbcluster);
     csa->csa_tsbcluster = NULL;
   }
-  if (csa->csa_aes_priv) {
-    aes_free_priv_struct(csa->csa_aes_priv);
-    csa->csa_aes_priv = NULL;
-  }
-  if (csa->csa_des_priv) {
-    des_free_priv_struct(csa->csa_des_priv);
-    csa->csa_des_priv = NULL;
+  if (csa->csa_priv) {
+    switch (csa->csa_type) {
+    case DESCRAMBLER_CSA_CBC:
+      break;
+    case DESCRAMBLER_DES_NCB:
+      des_free_priv_struct(csa->csa_priv);
+      break;
+    case DESCRAMBLER_AES_ECB:
+      aes_free_priv_struct(csa->csa_priv);
+      break;
+    case DESCRAMBLER_AES128_ECB:
+      aes128_free_priv_struct(csa->csa_priv);
+      break;
+    default:
+      assert(0);
+    }
+    csa->csa_priv = NULL;
   }
+  csa->csa_type   = 0;
+  csa->csa_keylen = 0;
 }
index ef727b090ce39dfd2fa1cb37d9dfd44e2bb676c1..ec6f3ecd2c38907decfa84b8a5c71b72d4f4751c 100644 (file)
@@ -30,9 +30,6 @@ struct elementary_stream;
 #include "ffdecsa/FFdecsa.h"
 #endif
 
-#include "algo/libaesdec.h"
-#include "algo/libdesdec.h"
-
 typedef struct tvhcsa
 {
 
@@ -62,9 +59,8 @@ typedef struct tvhcsa
 #else
   void *csa_keys;
 #endif
-  void *csa_aes_priv;
-  void *csa_des_priv;
-  
+  void *csa_priv;
+
 } tvhcsa_t;
 
 #if ENABLE_TVHCSA