]> www.vanbest.org Git - sasc-ng.git/commitdiff
irdeto: add support for Irdeto2
authoranon <unknown>
Thu, 28 Aug 2008 13:49:08 +0000 (21:49 +0800)
committeranon <unknown>
Thu, 28 Aug 2008 13:49:08 +0000 (21:49 +0800)
systems/irdeto/irdeto.c
systems/irdeto/irdeto.h
systems/irdeto/irdeto.mk
systems/irdeto/irdeto1.c
systems/irdeto/irdeto2.c [new file with mode: 0644]
systems/irdeto/log-irdeto.h

index e72d501b732d57d6a04b1f0c4776db320b17202f..02b166e2503837c7e8dcada006a094b20cb6dfa1 100644 (file)
@@ -30,7 +30,7 @@ static const struct LogModule lm_sys = {
   (LMOD_ENABLE|L_SYS_ALL)&LOPT_MASK,
   (LMOD_ENABLE|L_SYS_DEFDEF)&LOPT_MASK,
   "irdeto",
-  { L_SYS_DEFNAMES }
+  { L_SYS_DEFNAMES,"rawemm","rawecm" }
   };
 ADD_MODULE(L_SYS,lm_sys)
 
index 6c5709eb71b965da5e15a28e6d50d7e1c308bfea..cd95caaeb682555916be961b6760e20841d86dcf 100644 (file)
@@ -24,6 +24,7 @@
 #define SYSTEM_BETA          0x1700\r
 \r
 #define SYSTEM_NAME          "Irdeto"\r
+#define SYSTEM_NAME2         "Irdeto2"\r
 #define SYSTEM_PRI           -10\r
 \r
 #define TYPE_I1   0\r
index cfde90e5cb23814f23a603414be4e92ca8c845f1..dd1610611bd5afb23b1c1aa9fc9d1f38ac31350e 100644 (file)
@@ -2,4 +2,4 @@
 # Irdeto
 #
 TARGET = irdeto
-OBJS   = irdeto.o irdeto1.o
+OBJS   = irdeto.o irdeto1.o irdeto2.o
index c829316957374c71447f6f59a8eef53aa3751e86..b3285fdded22752a65f2f1fa1c081a0b56f5d33d 100644 (file)
@@ -28,8 +28,6 @@
 #include "irdeto.h"
 #include "log-irdeto.h"
 
-#define SYSTEM_CAN_HANDLE(x) ((x)==SYSTEM_IRDETO || (x)==SYSTEM_BETA)
-
 // -- cIrdCardInfo -------------------------------------------------------------
 
 class cIrdCardInfo : public cStructItem, public cProviderIrdeto, public cCardIrdeto {
@@ -464,6 +462,5 @@ cSystemLinkIrd::cSystemLinkIrd(void)
 
 bool cSystemLinkIrd::CanHandle(unsigned short SysId)
 {
-  SysId&=SYSTEM_MASK;
-  return SYSTEM_CAN_HANDLE(SysId);
+  return SysId==SYSTEM_IRDETO || (SysId&SYSTEM_MASK)==SYSTEM_BETA;
 }
diff --git a/systems/irdeto/irdeto2.c b/systems/irdeto/irdeto2.c
new file mode 100644 (file)
index 0000000..da8ac92
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Softcam plugin to VDR (C++)
+ *
+ * This code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "system-common.h"
+#include "data.h"
+#include "parse.h"
+#include "helper.h"
+#include "misc.h"
+
+#include <openssl/des.h>
+#include "openssl-compat.h"
+
+#include "irdeto.h"
+#include "log-irdeto.h"
+
+// -- cIrdeto2 -----------------------------------------------------------------
+
+class cIrdeto2 {
+private:
+  DES_key_schedule ks1, ks2;
+  //
+  void ScheduleKey(const unsigned char *key);
+  void DES3(unsigned char *data, int mode);
+protected:
+  void Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len);
+  void Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len);
+  bool CalculateHash(const unsigned char *Key, const unsigned char *IV_PAD, const unsigned char *Data2Sign, int DataLen);
+  };
+
+void cIrdeto2::ScheduleKey(const unsigned char *key)
+{
+  DES_key_sched((DES_cblock *)key,&ks1);
+  DES_key_sched((DES_cblock *)(key+8),&ks2);
+}
+
+void cIrdeto2::DES3(unsigned char *data, int mode)
+{
+  int m1, m2;
+  if(mode) { m1=DES_DECRYPT; m2=DES_ENCRYPT; }
+  else     { m1=DES_ENCRYPT; m2=DES_DECRYPT; }
+  DES_ecb_encrypt(DES_CAST(data),DES_CAST(data),&ks1,m1);
+  DES_ecb_encrypt(DES_CAST(data),DES_CAST(data),&ks2,m2);
+  DES_ecb_encrypt(DES_CAST(data),DES_CAST(data),&ks1,m1);
+}
+
+void cIrdeto2::Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len)
+{
+  ScheduleKey(key);
+  len&=~7;
+  const unsigned char *tmp=seed;
+  for(int i=0; i<len; i+=8) {
+    xxor(&data[i],8,&data[i],tmp); tmp=&data[i];
+    DES3(&data[i],0);
+    }
+}
+
+void cIrdeto2::Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len)
+{
+  ScheduleKey(key);
+  len&=~7;
+  unsigned char buf[2][8];
+  int n=0;
+  memcpy(buf[n],seed,8);
+  for(int i=0; i<len; i+=8,data+=8,n^=1) {
+    memcpy(buf[1-n],data,8);
+    DES3(data,1);
+    xxor(data,8,data,buf[n]);
+    }
+}
+
+bool cIrdeto2::CalculateHash(const unsigned char *Key, const unsigned char *IV_PAD, const unsigned char *Data2Sign, int DataLen)
+{
+  ScheduleKey(Key);
+  unsigned char CryptBuffer[8];
+  memset(CryptBuffer,0,sizeof(CryptBuffer));
+  DataLen-=8;
+  for(int y=0; y<DataLen; y+=8) {
+    if(y<DataLen-8) {
+      xxor(CryptBuffer,8,CryptBuffer,&Data2Sign[y]);
+      LDUMP(L_SYS_VERBOSE,CryptBuffer,8,"3DES XOR in:");
+      }
+    else {
+      int l=DataLen-y;
+      xxor(CryptBuffer,l,CryptBuffer,&Data2Sign[y]);
+      xxor(CryptBuffer+l,8-l,CryptBuffer+l,IV_PAD+8);
+      LDUMP(L_SYS_VERBOSE,CryptBuffer,8,"3DES XOR(%d) in:",8-l);
+      }
+    DES3(CryptBuffer,0);
+    LDUMP(L_SYS_VERBOSE,CryptBuffer,8,"3DES out:");
+    }
+  LDUMP(L_SYS_VERBOSE,CryptBuffer,8,"CryptBuffer:");
+  LDUMP(L_SYS_VERBOSE,&Data2Sign[DataLen],8,"MACBuffer:");
+  return memcmp(CryptBuffer,&Data2Sign[DataLen],8)==0;
+}
+
+// -- cSystemIrd2 --------------------------------------------------------------
+
+class cSystemIrd2 : public cSystem, private cIrdeto2 {
+private:
+  void PrepareSeed(unsigned char *seed, const unsigned char *key);
+  void NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv);
+public:
+  cSystemIrd2(void);
+  virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data);
+  virtual void ProcessEMM(int pid, int caid, unsigned char *data);
+  };
+
+cSystemIrd2::cSystemIrd2(void)
+:cSystem(SYSTEM_NAME2,SYSTEM_PRI)
+{
+  hasLogger=true;
+}
+
+void cSystemIrd2::PrepareSeed(unsigned char *seed, const unsigned char *key)
+{
+  unsigned char blank[16];
+  memset(blank,0,16);
+  Encrypt(seed,blank,key,16);
+}
+
+void cSystemIrd2::NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv)
+{
+  while(i<len) {
+    int l=data[i+1] ? (data[i+1]&0x3F)+2 : 1;
+    switch(data[i]) {
+      case 0x10:
+      case 0x50: if(l==0x13 && i<=len-l) Decrypt(&data[i+3],iv,key,16); break;
+      case 0x78: if(l==0x14 && i<=len-l) Decrypt(&data[i+4],iv,key,16); break;
+      }
+    i+=l;
+    }
+}
+
+bool cSystemIrd2::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
+{
+  int len=data[11];
+  if(len!=0x28 || SCT_LEN(data)<len+12) {
+    if(doLog) PRINTF(L_SYS_ECM,"bad ECM length");
+    return false;
+    }
+  int prov=data[8];
+  cPlainKey *pk;
+  unsigned char ECM_IV[16];
+  if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_IV,0),16))) {
+    if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x IV key",ecm->caId,prov);
+    return false;
+    }
+  pk->Get(ECM_IV);
+
+  unsigned char ECM_Seed[16];
+  if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_SEED,0),16))) {
+    if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x ECM key",ecm->caId,prov);
+    return false;
+    }
+  pk->Get(ECM_Seed);
+
+  cKeySnoop ks(this,'I',ecm->caId,KEYSET(prov,TYPE_OP,data[9]));
+  unsigned char key[16];
+  if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_OP,data[9]),16))) return false;
+  pk->Get(key);
+  PrepareSeed(ECM_Seed,key);
+
+  data+=12;
+  Decrypt(data,ECM_IV,ECM_Seed,len);
+  int i=(data[0]&7)+1;
+  NanoDecrypt(data,i,len-8,key,ECM_IV);
+  if(CalculateHash(ECM_Seed,ECM_IV,data-6,len+6)) {
+    HEXDUMP(L_SYS_RAWECM,data-12,len+12,"Irdeto2 RAWECM");
+    while(i<len-8) {
+      int l=data[i+1] ? (data[i+1]&0x3F)+2 : 1;
+      switch(data[i]) {
+        case 0x78:
+          memcpy(cw,&data[i+4],16);
+          ks.OK(pk);
+          return true;
+        }
+      i+=l;
+      }
+    }
+  else {
+    if(doLog) PRINTF(L_SYS_ECM,"hash failed");
+    }
+  return false;
+}
+
+void cSystemIrd2::ProcessEMM(int pid, int caid, unsigned char *data)
+{
+  int prov=0; //XXX how to get provider here??
+
+  int len=SCT_LEN(data);
+  unsigned char *emm=AUTOMEM(len);
+
+  cPlainKey *pk;
+  if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_IV,0),16))) {
+    PRINTF(L_SYS_EMM,"missing %04x %02x IV key",caid,prov);
+    return;
+    }
+  unsigned char EMM_IV[16];
+  pk->Get(EMM_IV);
+
+  for(int keyno=0; keyno<2; keyno++) {
+    if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_PMK,keyno),16))) {
+      PRINTF(L_SYS_EMM,"missing %04x %02x MK%d key",caid,prov,keyno);
+      continue;
+      }
+    unsigned char PMK[16];
+    pk->Get(PMK);
+
+    if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_SEED,1),16))) {
+      PRINTF(L_SYS_EMM,"missing %04x %02x EMM key",caid,prov);
+      return;
+      }
+    unsigned char EMM_Seed[16];
+    pk->Get(EMM_Seed);
+    PrepareSeed(EMM_Seed,PMK);
+
+    memcpy(emm,data,len);
+    Decrypt(&emm[10],EMM_IV,EMM_Seed,len-10);
+    NanoDecrypt(emm,16,len-8,PMK,EMM_IV);
+    memcpy(emm+6,emm+7,len-7); // removing padding byte
+    if(CalculateHash(EMM_Seed,EMM_IV,emm+3,len-4)) {
+      HEXDUMP(L_SYS_RAWEMM,emm,len,"Irdeto2 RAWEMM");
+      for(int i=15; i<len-9;) {
+        int l=emm[i+1] ? (emm[i+1]&0x3F)+2 : 1;
+        switch(emm[i]) {
+          case 0x10:
+          case 0x50:
+            if(l==0x13 && i+l<=len-9) {
+              FoundKey();
+              if(keys.NewKey('I',caid,KEYSET(prov,TYPE_OP,emm[i+2]>>2),&emm[i+3],16)) NewKey();
+              }
+            break;
+          }
+        i+=l;
+        }
+      break;
+      }
+    else
+      PRINTF(L_SYS_EMM,"hash failed MK%d",keyno);
+    }
+}
+
+// -- cSystemLinkIrd -----------------------------------------------------------
+
+class cSystemLinkIrd2 : public cSystemLink {
+public:
+  cSystemLinkIrd2(void);
+  virtual bool CanHandle(unsigned short SysId);
+  virtual cSystem *Create(void) { return new cSystemIrd2; }
+  };
+
+static cSystemLinkIrd2 staticInit2;
+
+cSystemLinkIrd2::cSystemLinkIrd2(void)
+:cSystemLink(SYSTEM_NAME2,SYSTEM_PRI)
+{
+  Feature.NeedsKeyFile();
+}
+
+bool cSystemLinkIrd2::CanHandle(unsigned short SysId)
+{
+  return SysId!=SYSTEM_IRDETO && (SysId&SYSTEM_MASK)==SYSTEM_IRDETO;
+}
index 6d09216d59cb2294be4a1139736f0965d5a52dce..2dbac626bec45749a5b6d6c470e8a40723d5e6a7 100644 (file)
@@ -23,6 +23,8 @@
 #include "log-sys.h"\r
 \r
 #define L_SYS        5\r
-#define L_SYS_ALL    LALL(L_SYS_LASTDEF)\r
+#define L_SYS_RAWEMM   LCLASS(L_SYS,L_SYS_LASTDEF<<1)\r
+#define L_SYS_RAWECM   LCLASS(L_SYS,L_SYS_LASTDEF<<2)\r
+#define L_SYS_ALL    LALL(L_SYS_RAWECM)\r
 \r
 #endif\r