SASC
DVBSoftCAM

irdeto2.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <string.h>
00022 
00023 #include "system-common.h"
00024 #include "data.h"
00025 #include "parse.h"
00026 #include "helper.h"
00027 #include "misc.h"
00028 
00029 #include <openssl/des.h>
00030 #include "openssl-compat.h"
00031 
00032 #include "irdeto.h"
00033 #include "log-irdeto.h"
00034 
00035 // -- cIrdeto2 -----------------------------------------------------------------
00036 
00037 class cIrdeto2 {
00038 private:
00039   DES_key_schedule ks1, ks2;
00040   //
00041   void ScheduleKey(const unsigned char *key);
00042   void DES3(unsigned char *data, int mode);
00043 protected:
00044   void Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len);
00045   void Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len);
00046   bool CalculateHash(const unsigned char *key, const unsigned char *iv, const unsigned char *data, int len);
00047   };
00048 
00049 void cIrdeto2::ScheduleKey(const unsigned char *key)
00050 {
00051   DES_key_sched((DES_cblock *)key,&ks1);
00052   DES_key_sched((DES_cblock *)(key+8),&ks2);
00053 }
00054 
00055 void cIrdeto2::DES3(unsigned char *data, int mode)
00056 {
00057   int m1, m2;
00058   if(mode) { m1=DES_DECRYPT; m2=DES_ENCRYPT; }
00059   else     { m1=DES_ENCRYPT; m2=DES_DECRYPT; }
00060   DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks1,m1);
00061   DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks2,m2);
00062   DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks1,m1);
00063 }
00064 
00065 void cIrdeto2::Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len)
00066 {
00067   ScheduleKey(key);
00068   len&=~7;
00069   const unsigned char *tmp=seed;
00070   for(int i=0; i<len; i+=8) {
00071     xxor(&data[i],8,&data[i],tmp); tmp=&data[i];
00072     DES3(&data[i],0);
00073     }
00074 }
00075 
00076 void cIrdeto2::Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len)
00077 {
00078   ScheduleKey(key);
00079   len&=~7;
00080   unsigned char buf[2][8];
00081   int n=0;
00082   memcpy(buf[n],seed,8);
00083   for(int i=0; i<len; i+=8,data+=8,n^=1) {
00084     memcpy(buf[1-n],data,8);
00085     DES3(data,1);
00086     xxor(data,8,data,buf[n]);
00087     }
00088 }
00089 
00090 bool cIrdeto2::CalculateHash(const unsigned char *key, const unsigned char *iv, const unsigned char *data, int len)
00091 {
00092   ScheduleKey(key);
00093   unsigned char cbuff[8];
00094   memset(cbuff,0,sizeof(cbuff));
00095   len-=8;
00096   for(int y=0; y<len; y+=8) {
00097     if(y<len-8) {
00098       xxor(cbuff,8,cbuff,&data[y]);
00099       LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES XOR in:");
00100       }
00101     else {
00102       int l=len-y;
00103       xxor(cbuff,l,cbuff,&data[y]);
00104       xxor(cbuff+l,8-l,cbuff+l,iv+8);
00105       LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES XOR(%d) in:",8-l);
00106       }
00107     DES3(cbuff,0);
00108     LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES out:");
00109     }
00110   LDUMP(L_SYS_VERBOSE,cbuff,8,"CryptBuffer:");
00111   LDUMP(L_SYS_VERBOSE,&data[len],8,"MACBuffer:");
00112   return memcmp(cbuff,&data[len],8)==0;
00113 }
00114 
00115 // -- cSystemIrd2 --------------------------------------------------------------
00116 
00117 #define NANOLEN(_a) ((_a) ? ((_a)&0x3F)+2 : 1)
00118 
00119 class cSystemIrd2 : public cSystem, private cIrdeto2 {
00120 private:
00121   void PrepareSeed(unsigned char *seed, const unsigned char *key);
00122   void NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv);
00123 public:
00124   cSystemIrd2(void);
00125   virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data);
00126   virtual void ProcessEMM(int pid, int caid, const unsigned char *data);
00127   };
00128 
00129 cSystemIrd2::cSystemIrd2(void)
00130 :cSystem(SYSTEM_NAME2,SYSTEM_PRI2)
00131 {
00132   hasLogger=true;
00133 }
00134 
00135 void cSystemIrd2::PrepareSeed(unsigned char *seed, const unsigned char *key)
00136 {
00137   unsigned char blank[16];
00138   memset(blank,0,16);
00139   Encrypt(seed,blank,key,16);
00140 }
00141 
00142 void cSystemIrd2::NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv)
00143 {
00144   while(i<len) {
00145     int l=NANOLEN(data[i+1]);
00146     switch(data[i]) {
00147       case 0x10:
00148       case 0x50: if(l==0x13 && i<=len-l) Decrypt(&data[i+3],iv,key,16); break;
00149       case 0x78: if(l==0x14 && i<=len-l) Decrypt(&data[i+4],iv,key,16); break;
00150       }
00151     i+=l;
00152     }
00153 }
00154 
00155 bool cSystemIrd2::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
00156 {
00157   int len=data[11];
00158   if(len!=0x28 || SCT_LEN(data)<len+12) {
00159     if(doLog) PRINTF(L_SYS_ECM,"bad ECM length");
00160     return false;
00161     }
00162   int prov=data[8];
00163   cPlainKey *pk;
00164   unsigned char ECM_IV[16];
00165   if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_IV,0),16))) {
00166     if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x IV key",ecm->caId,prov);
00167     return false;
00168     }
00169   pk->Get(ECM_IV);
00170 
00171   unsigned char ECM_Seed[16];
00172   if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_SEED,0),16))) {
00173     if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x ECM key",ecm->caId,prov);
00174     return false;
00175     }
00176   pk->Get(ECM_Seed);
00177 
00178   cKeySnoop ks(this,'I',ecm->caId,KEYSET(prov,TYPE_OP,data[9]));
00179   unsigned char key[16];
00180   if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_OP,data[9]),16))) return false;
00181   pk->Get(key);
00182   PrepareSeed(ECM_Seed,key);
00183 
00184   data+=12;
00185   Decrypt(data,ECM_IV,ECM_Seed,len);
00186   int i=(data[0]&7)+1;
00187   NanoDecrypt(data,i,len-8,key,ECM_IV);
00188   if(CalculateHash(ECM_Seed,ECM_IV,data-6,len+6)) {
00189     HEXDUMP(L_SYS_RAWECM,data-12,len+12,"Irdeto2 RAWECM");
00190     while(i<len-8) {
00191       int l=NANOLEN(data[i+1]);
00192       switch(data[i]) {
00193         case 0x78:
00194           memcpy(cw,&data[i+4],16);
00195           ks.OK(pk);
00196           return true;
00197         }
00198       i+=l;
00199       }
00200     }
00201   else {
00202     if(doLog) PRINTF(L_SYS_ECM,"hash failed");
00203     }
00204   return false;
00205 }
00206 
00207 void cSystemIrd2::ProcessEMM(int pid, int caid, const unsigned char *data)
00208 {
00209   int prov=0; //XXX how to get provider here??
00210 
00211   int len=SCT_LEN(data);
00212   unsigned char *emm=AUTOMEM(len);
00213 
00214   cPlainKey *pk;
00215   if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_IV,0),16))) {
00216     PRINTF(L_SYS_EMM,"missing %04x %02x IV key",caid,prov);
00217     return;
00218     }
00219   unsigned char EMM_IV[16];
00220   pk->Get(EMM_IV);
00221 
00222   for(int keyno=0; keyno<2; keyno++) {
00223     if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_PMK,keyno),16))) {
00224       PRINTF(L_SYS_EMM,"missing %04x %02x MK%d key",caid,prov,keyno);
00225       continue;
00226       }
00227     unsigned char PMK[16];
00228     pk->Get(PMK);
00229 
00230     if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_SEED,1),16))) {
00231       PRINTF(L_SYS_EMM,"missing %04x %02x EMM key",caid,prov);
00232       return;
00233       }
00234     unsigned char EMM_Seed[16];
00235     pk->Get(EMM_Seed);
00236     PrepareSeed(EMM_Seed,PMK);
00237 
00238     memcpy(emm,data,len);
00239     Decrypt(&emm[10],EMM_IV,EMM_Seed,len-10);
00240     NanoDecrypt(emm,16,len-8,PMK,EMM_IV);
00241     memmove(emm+6,emm+7,len-7); // removing padding byte
00242     if(CalculateHash(EMM_Seed,EMM_IV,emm+3,len-4)) {
00243       HEXDUMP(L_SYS_RAWEMM,emm,len,"Irdeto2 RAWEMM");
00244       for(int i=15; i<len-9;) {
00245         int l=NANOLEN(emm[i+1]);
00246         switch(emm[i]) {
00247           case 0x10:
00248           case 0x50:
00249             if(l==0x13 && i+l<=len-9) {
00250               FoundKey();
00251               if(keys.NewKey('I',caid,KEYSET(prov,TYPE_OP,emm[i+2]>>2),&emm[i+3],16)) NewKey();
00252               }
00253             break;
00254           }
00255         i+=l;
00256         }
00257       break;
00258       }
00259     else
00260       PRINTF(L_SYS_EMM,"hash failed MK%d",keyno);
00261     }
00262 }
00263 
00264 // -- cSystemLinkIrd -----------------------------------------------------------
00265 
00266 class cSystemLinkIrd2 : public cSystemLink {
00267 public:
00268   cSystemLinkIrd2(void);
00269   virtual bool CanHandle(unsigned short SysId);
00270   virtual cSystem *Create(void) { return new cSystemIrd2; }
00271   };
00272 
00273 static cSystemLinkIrd2 staticInit2;
00274 
00275 cSystemLinkIrd2::cSystemLinkIrd2(void)
00276 :cSystemLink(SYSTEM_NAME2,SYSTEM_PRI2)
00277 {
00278   Feature.NeedsKeyFile();
00279 }
00280 
00281 bool cSystemLinkIrd2::CanHandle(unsigned short SysId)
00282 {
00283   return SysId!=SYSTEM_IRDETO && (SysId&SYSTEM_MASK)==SYSTEM_IRDETO;
00284 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines