SASC
DVBSoftCAM

irdeto1.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 "misc.h"
00027 
00028 #include "irdeto.h"
00029 #include "log-irdeto.h"
00030 
00031 // -- cIrdCardInfo -------------------------------------------------------------
00032 
00033 class cIrdCardInfo : public cStructItem, public cProviderIrdeto, public cCardIrdeto {
00034 public:
00035   unsigned char PMK[8], HMK[10];
00036   bool haveHMK;
00037   //
00038   bool Parse(const char *line);
00039   virtual cString ToString(bool hide);
00040   };
00041 
00042 bool cIrdCardInfo::Parse(const char *line)
00043 {
00044   haveHMK=false;
00045   if(GetHex(line,hexSer,sizeof(hexSer)) && GetHex(line,HMK,sizeof(HMK))) haveHMK=true;
00046   return GetHex(line,&provBase,sizeof(provBase)) &&
00047          GetHex(line,provId,sizeof(provId)) &&
00048          GetHex(line,PMK,sizeof(PMK));
00049 }
00050 
00051 cString cIrdCardInfo::ToString(bool hide)
00052 {
00053   char s1[20], s2[24], s3[20], s4[20];
00054   return cString::sprintf("%s %s %02x %s %s",
00055      HexStr(s1,hexSer,sizeof(hexSer)),HexStr(s2,HMK,sizeof(HMK)),provBase,
00056      HexStr(s3,provId,sizeof(provId)),HexStr(s4,PMK,sizeof(PMK)));
00057 }
00058 
00059 // -- cIrdCardInfos ------------------------------------------------------------
00060 
00061 class cIrdCardInfos : public cCardInfos<cIrdCardInfo> {
00062 public:
00063   cIrdCardInfos(void);
00064   bool Update(cIrdCardInfo *ci, const unsigned char *pmk, const unsigned char *id);
00065   };
00066 
00067 static cIrdCardInfos Icards;
00068 
00069 cIrdCardInfos::cIrdCardInfos(void)
00070 :cCardInfos<cIrdCardInfo>("Irdeto cards","Ird-Beta.KID",SL_READWRITE)
00071 {}
00072 
00073 bool cIrdCardInfos::Update(cIrdCardInfo *ci, const unsigned char *pmk, const unsigned char *id)
00074 {
00075   bool res=false;
00076   char str[20], str2[12];
00077   if(memcmp(ci->PMK,pmk,sizeof(ci->PMK))) {
00078     PRINTF(L_GEN_INFO,"new PMK for I card %s: %s",HexStr(str2,ci->hexSer,sizeof(ci->hexSer)),KeyStr(str,pmk));
00079     memcpy(ci->PMK,pmk,sizeof(ci->PMK));
00080     res=true;
00081     }
00082   if(id && memcmp(ci->provId,id,sizeof(ci->provId))) {
00083     PRINTF(L_GEN_INFO,"new PrvID for I card %s: %s",HexStr(str2,ci->hexSer,sizeof(ci->hexSer)),HexStr(str,id,sizeof(ci->provId)));
00084     memcpy(ci->provId,id,sizeof(ci->provId));
00085     res=true;
00086     }
00087   if(res) Modified();
00088   return res;
00089 }
00090 
00091 // -- cIrdeto ------------------------------------------------------------------
00092 
00093 class cIrdeto {
00094 private:
00095   static const unsigned char T0[], T1[], T2[];
00096   unsigned char tempKey[10];
00097   //
00098   void Rotate(unsigned char *p);
00099   void MakeTempKey(const unsigned char *key, int date);
00100 protected:
00101   void SessionKeyCrypt(unsigned char *data, const unsigned char *key, int date);
00102   bool SignatureCheck(const unsigned char *data, int length, const unsigned char *key, int date, const unsigned char *signature, int keylen);
00103   void DecryptIrd(unsigned char *data, unsigned char *key, int rounds, int offset);
00104   };
00105 
00106 const unsigned char cIrdeto::T0[32] = {
00107   0,1,2,3,4,5,6,7, 0,1,2,3,4,5,6,7,
00108   0,1,2,3,4,5,6,7, 0,3,6,1,4,7,2,5
00109   };
00110 
00111 const unsigned char cIrdeto::T1[256] = {
00112   0xDA,0x26,0xE8,0x72,0x11,0x52,0x3E,0x46, 0x32,0xFF,0x8C,0x1E,0xA7,0xBE,0x2C,0x29,
00113   0x5F,0x86,0x7E,0x75,0x0A,0x08,0xA5,0x21, 0x61,0xFB,0x7A,0x58,0x60,0xF7,0x81,0x4F,
00114   0xE4,0xFC,0xDF,0xB1,0xBB,0x6A,0x02,0xB3, 0x0B,0x6E,0x5D,0x5C,0xD5,0xCF,0xCA,0x2A,
00115   0x14,0xB7,0x90,0xF3,0xD9,0x37,0x3A,0x59, 0x44,0x69,0xC9,0x78,0x30,0x16,0x39,0x9A,
00116   0x0D,0x05,0x1F,0x8B,0x5E,0xEE,0x1B,0xC4, 0x76,0x43,0xBD,0xEB,0x42,0xEF,0xF9,0xD0,
00117   0x4D,0xE3,0xF4,0x57,0x56,0xA3,0x0F,0xA6, 0x50,0xFD,0xDE,0xD2,0x80,0x4C,0xD3,0xCB,
00118   0xF8,0x49,0x8F,0x22,0x71,0x84,0x33,0xE0, 0x47,0xC2,0x93,0xBC,0x7C,0x3B,0x9C,0x7D,
00119   0xEC,0xC3,0xF1,0x89,0xCE,0x98,0xA2,0xE1, 0xC1,0xF2,0x27,0x12,0x01,0xEA,0xE5,0x9B,
00120   0x25,0x87,0x96,0x7B,0x34,0x45,0xAD,0xD1, 0xB5,0xDB,0x83,0x55,0xB0,0x9E,0x19,0xD7,
00121   0x17,0xC6,0x35,0xD8,0xF0,0xAE,0xD4,0x2B, 0x1D,0xA0,0x99,0x8A,0x15,0x00,0xAF,0x2D,
00122   0x09,0xA8,0xF5,0x6C,0xA1,0x63,0x67,0x51, 0x3C,0xB2,0xC0,0xED,0x94,0x03,0x6F,0xBA,
00123   0x3F,0x4E,0x62,0x92,0x85,0xDD,0xAB,0xFE, 0x10,0x2E,0x68,0x65,0xE7,0x04,0xF6,0x0C,
00124   0x20,0x1C,0xA9,0x53,0x40,0x77,0x2F,0xA4, 0xFA,0x6D,0x73,0x28,0xE2,0xCD,0x79,0xC8,
00125   0x97,0x66,0x8E,0x82,0x74,0x06,0xC7,0x88, 0x1A,0x4A,0x6B,0xCC,0x41,0xE9,0x9D,0xB8,
00126   0x23,0x9F,0x3D,0xBF,0x8D,0x95,0xC5,0x13, 0xB9,0x24,0x5A,0xDC,0x64,0x18,0x38,0x91,
00127   0x7F,0x5B,0x70,0x54,0x07,0xB6,0x4B,0x0E, 0x36,0xAC,0x31,0xE6,0xD6,0x48,0xAA,0xB4
00128   };
00129 
00130 const unsigned char cIrdeto::T2[256] = {
00131   0x8E,0xD5,0x32,0x53,0x4B,0x18,0x7F,0x95, 0xBE,0x30,0xF3,0xE0,0x22,0xE1,0x68,0x90,
00132   0x82,0xC8,0xA8,0x57,0x21,0xC5,0x38,0x73, 0x61,0x5D,0x5A,0xD6,0x60,0xB7,0x48,0x70,
00133   0x2B,0x7A,0x1D,0xD1,0xB1,0xEC,0x7C,0xAA, 0x2F,0x1F,0x37,0x58,0x72,0x88,0xFF,0x87,
00134   0x1C,0xCB,0x00,0xE6,0x4E,0xAB,0xEB,0xB3, 0xF7,0x59,0x71,0x6A,0x64,0x2A,0x55,0x4D,
00135   0xFC,0xC0,0x51,0x01,0x2D,0xC4,0x54,0xE2, 0x9F,0x26,0x16,0x27,0xF2,0x9C,0x86,0x11,
00136   0x05,0x29,0xA2,0x78,0x49,0xB2,0xA6,0xCA, 0x96,0xE5,0x33,0x3F,0x46,0xBA,0xD0,0xBB,
00137   0x5F,0x84,0x98,0xE4,0xF9,0x0A,0x62,0xEE, 0xF6,0xCF,0x94,0xF0,0xEA,0x1E,0xBF,0x07,
00138   0x9B,0xD9,0xE9,0x74,0xC6,0xA4,0xB9,0x56, 0x3E,0xDB,0xC7,0x15,0xE3,0x80,0xD7,0xED,
00139   0xEF,0x13,0xAC,0xA1,0x91,0xC2,0x89,0x5B, 0x08,0x0B,0x4C,0x02,0x3A,0x5C,0xA9,0x3B,
00140   0xCE,0x6B,0xA7,0xE7,0xCD,0x7B,0xA0,0x47, 0x09,0x6D,0xF8,0xF1,0x8B,0xB0,0x12,0x42,
00141   0x4A,0x9A,0x17,0xB4,0x7E,0xAD,0xFE,0xFD, 0x2C,0xD3,0xF4,0xB6,0xA3,0xFA,0xDF,0xB8,
00142   0xD4,0xDA,0x0F,0x50,0x93,0x66,0x6C,0x20, 0xD8,0x8A,0xDD,0x31,0x1A,0x8C,0x06,0xD2,
00143   0x44,0xE8,0x23,0x43,0x6E,0x10,0x69,0x36, 0xBC,0x19,0x8D,0x24,0x81,0x14,0x40,0xC9,
00144   0x6F,0x2E,0x45,0x52,0x41,0x92,0x34,0xFB, 0x5E,0x0D,0xF5,0x76,0x25,0x77,0x63,0x65,
00145   0xAF,0x4F,0xCC,0x03,0x9D,0x0C,0x28,0x39, 0x85,0xDE,0xB5,0x7D,0x67,0x83,0xBD,0xC3,
00146   0xDC,0x3C,0xAE,0x99,0x04,0x75,0x8F,0x97, 0xC1,0xA5,0x9E,0x35,0x0E,0x3D,0x1B,0x79
00147   };
00148 
00149 void cIrdeto::Rotate(unsigned char *p)
00150 {
00151   unsigned char c, t;
00152   c=p[9]<<7;
00153   t=*p; *p++=(t>>1) | c; c=t<<7;
00154   t=*p; *p++=(t>>1) | c; c=t<<7;
00155   t=*p; *p++=(t>>1) | c; c=t<<7;
00156   t=*p; *p++=(t>>1) | c; c=t<<7;
00157   t=*p; *p++=(t>>1) | c; c=t<<7;
00158   t=*p; *p++=(t>>1) | c; c=t<<7;
00159   t=*p; *p++=(t>>1) | c; c=t<<7;
00160   t=*p; *p++=(t>>1) | c; c=t<<7;
00161   t=*p; *p++=(t>>1) | c; c=t<<7;
00162   t=*p; *p++=(t>>1) | c; c=t<<7;
00163 }
00164 
00165 void cIrdeto::MakeTempKey(const unsigned char *key, int date)
00166 {
00167   memcpy(tempKey,key,8);
00168   tempKey[8]=(unsigned char)(date >> 8) ^ key[0];
00169   tempKey[9]=(unsigned char)date ^ key[1];
00170 }
00171 
00172 void cIrdeto::DecryptIrd(unsigned char *data, unsigned char *key, int rounds, int offset)
00173 {
00174   for(int count=0; count<rounds; count++) {
00175     int index=count % 10;
00176     if(index==0) Rotate(key);
00177     unsigned char k=key[index];
00178     unsigned char d=data[T0[(count & 0x0f) + offset]] ^ k;
00179     d=(k&1) ? T1[d] : T2[d];
00180     data[T0[((count+1) & 0x0f) + offset]] ^= d;
00181     }
00182 }
00183 
00184 void cIrdeto::SessionKeyCrypt(unsigned char *data, const unsigned char *key, int date)
00185 {
00186   MakeTempKey(key,date);
00187   DecryptIrd(data,tempKey,128,16);
00188 }
00189 
00190 bool cIrdeto::SignatureCheck(const unsigned char *data, int length, const unsigned char *key, int date, const unsigned char *signature, int keylen)
00191 {
00192   unsigned char buffer[256];
00193   memcpy(buffer,data,length);
00194   int rounds;
00195   if((length%8)==0) rounds=40;
00196   else {
00197     int i=0x61;
00198     while((length%8)!=0) buffer[length++]=i++;
00199     rounds=104;
00200     }
00201 
00202   if(keylen==10) memcpy(tempKey,key,10);
00203   else MakeTempKey(key,date);
00204 
00205   int i=0;
00206   while(i<length-8) {
00207     DecryptIrd(buffer,tempKey,40,0);
00208     i+=8;
00209     for(int j=0; j<8; j++) buffer[j] ^= buffer[i+j];
00210     Rotate(tempKey);
00211     }
00212   DecryptIrd(buffer,tempKey,rounds,0);
00213   return memcmp(buffer,signature,5)==0;
00214 }
00215 
00216 // -- cSystemIrd ---------------------------------------------------------------
00217 
00218 class cSystemIrd : public cSystem, private cIrdeto {
00219 private:
00220   unsigned char lastKey;
00221 public:
00222   cSystemIrd(void);
00223   virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *source);
00224   virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer);
00225   };
00226 
00227 cSystemIrd::cSystemIrd(void)
00228 :cSystem(SYSTEM_NAME,SYSTEM_PRI)
00229 {
00230   lastKey=0;
00231   hasLogger=true;
00232 }
00233 
00234 bool cSystemIrd::ProcessECM(const cEcmInfo *ecm, unsigned char *source)
00235 {
00236   unsigned char *data=0;
00237   int date=-1, keynr=0;
00238   source+=6;
00239   int length=source[5]+6-5; // 6 header bytes - 5 signature bytes
00240   for(int index=6 ; index<length && (data==0 || date==-1) ;) {
00241     int param=source[index++];
00242     int len  =source[index++] & 0x3f;
00243 
00244     switch(param) {
00245       case 0x78:
00246         keynr = source[index];
00247         data = &source[index+2];
00248         break;
00249       case 0x00:
00250       case 0x40:
00251         date = (source[index]<<8) | source[index+1];
00252         break;
00253       }
00254     index+=len;
00255     }
00256   if(data==0 || date==-1) {
00257     if(doLog) PRINTF(L_SYS_ECM,"incomplete ECM structure");
00258     return false;
00259     }
00260 
00261   cKeySnoop ks(this,'I',source[2],KEYSET(0,TYPE_I1,keynr));
00262   cPlainKey *pk=0;
00263   unsigned char key[8];
00264   while((pk=keys.FindKey('I',source[2],KEYSET(0,TYPE_I1,keynr),sizeof(key),pk))) {
00265     unsigned char save[16];
00266     memcpy(save,data,16); // save the encrypted data
00267     pk->Get(key);
00268     SessionKeyCrypt(&data[0],key,date);
00269     SessionKeyCrypt(&data[8],key,date);
00270     if(SignatureCheck(source,length,key,date,&source[length],8)) {
00271       memcpy(cw,&data[0],16);
00272       ks.OK(pk);
00273       return true;
00274       }
00275     memcpy(data,save,16); // put back the encrypted data if it didn't works
00276     }
00277   return false;
00278 }
00279 
00280 void cSystemIrd::ProcessEMM(int pid, int caid, const unsigned char *data)
00281 {
00282   int i, numKeys=0, date=0;
00283   unsigned char adr[10], id[4], *pk[4], prov, *mk=0, prvId[3]={0,0,0};
00284 
00285   int n=SCT_LEN(data);
00286   unsigned char *buffer=AUTOMEM(n);
00287   memcpy(buffer,data,n);
00288 
00289   int index=cParseIrdeto::AddrLen(buffer);
00290   memset(adr,0,sizeof(adr));
00291   memcpy(adr,&buffer[3],index+1);
00292   index+=4+4; // 3 header + adr type + 4 {0x01 0x00 0x00 len}
00293   
00294   int sindex=index;           // save index for sig. check
00295   int slen=buffer[index-1]-5; // save packet length, 5 signature bytes
00296   int maxIndex=index+slen;
00297   if(maxIndex>n-5) {
00298     PRINTF(L_SYS_EMM,"bad packet length (%d > %d)",maxIndex,n-5);
00299     maxIndex=n-5;
00300     }
00301   bool badnano=false;
00302   while(!badnano && index<maxIndex) {
00303     unsigned char nlen=buffer[index+1] & 0x3F;
00304     //unsigned char prio=buffer[index] & 0x40;
00305     unsigned char nano=buffer[index] & ~0x40;
00306     switch(nano) {
00307       case 0x10: // key update
00308         {
00309         int k=(buffer[index+1]>>6)+1; // key counter
00310         if(nlen!=k*9) { badnano=true; break; }
00311         for(i=0 ; i<k ; i++) {
00312           id[i]= buffer[index+2+0+i*9];
00313           pk[i]=&buffer[index+2+1+i*9];
00314           numKeys++;
00315           }
00316         }
00317         break;
00318       case 0x00: // date
00319         if(nlen<2) { badnano=true; break; }
00320         date=WORD(buffer,index+2,0xFFFF);
00321         break;
00322       case 0x28: // pmk & provid update
00323         if(nlen!=13) { badnano=true; break; }
00324         prov= buffer[index+2+0];
00325         mk=  &buffer[index+2+2];
00326         prvId[0]=buffer[index+2+10];
00327         prvId[1]=buffer[index+2+11];
00328         prvId[2]=buffer[index+2+12];
00329         break;
00330       case 0x29: // pmk update
00331         if(nlen!=10) { badnano=true; break; }
00332         prov= buffer[index+2+0];
00333         mk=  &buffer[index+2+2];
00334         break;
00335       case 0x11: // channel id
00336         if(nlen!=6) { badnano=true; break; }
00337         //chId[0]=buffer[index+2+0];
00338         //chId[1]=buffer[index+2+1];
00339         break;
00340       case 0x91: // erase channel id
00341         if(nlen!=6) { badnano=true; break; }
00342         //eraseChId[0]=buffer[index+2+0];
00343         //eraseChId[1]=buffer[index+2+1];
00344         break;
00345       case 0x8B: // CB20-matrix
00346         if(nlen!=0x20) { badnano=true; break; }
00347         //cb20ptr=&buffer[index+2];
00348         break;
00349       case 0x22: // set country code
00350         if(nlen!=3) { badnano=true; break; }
00351         //
00352         break;
00353       case 0x95: // unknown
00354         if(nlen!=2) { badnano=true; break; }
00355         //
00356         break;
00357       case 0x1E: // unknown
00358         if(nlen!=15) { badnano=true; break; }
00359         //
00360         break;
00361       case 0x1F: // unknown
00362         if(nlen!=3) { badnano=true; break; }
00363         //
00364         break;
00365       case 0x16: // unknown
00366         if(nlen!=2) { badnano=true; break; }
00367         //
00368         break;
00369       case 0x12: // unknown
00370         if(nlen!=6) { badnano=true; break; }
00371         //
00372         break;
00373 
00374       default:
00375         PRINTF(L_SYS_EMM,"unhandled nano 0x%02x",nano);
00376         break;
00377       }
00378     index+=nlen+2;
00379     }
00380   if(badnano || index!=maxIndex) {
00381     PRINTF(L_SYS_EMM,"bad nano/bad paket");
00382     return;
00383     }
00384 
00385   // lastKey: save cpu time if we get bursts of the same key
00386   if((numKeys>0 && (id[0]!=lastKey || numKeys>1)) || mk) {
00387     cIrdCardInfo *ci=Icards.First();
00388     unsigned char *chkkey=AUTOMEM(max(sizeof(ci->PMK),sizeof(ci->HMK)));
00389     while(ci) {
00390       ci->hexBase=cParseIrdeto::AddrBase(buffer);
00391       if((numKeys>0         && (ci->cProviderIrdeto::MatchEMM(buffer) || CheckNull(ci->provId,sizeof(ci->provId)) )) ||
00392          (mk && ci->haveHMK && (ci->cCardIrdeto::MatchEMM(buffer)))) {
00393         LBSTARTF(L_SYS_EMM);
00394         LBPUT("%02x %02x%02x%02x",buffer[3],buffer[4],buffer[5],buffer[6]);
00395 
00396         for(i=0 ; i<numKeys ; i++) {
00397           lastKey=id[i];
00398           SessionKeyCrypt(pk[i],ci->PMK,date);
00399           }
00400         int keylen;
00401         if(mk) {
00402           memcpy(chkkey,ci->HMK,sizeof(ci->HMK)); // key is modified in decryptIrd()
00403           DecryptIrd(mk,chkkey,128,16);
00404           keylen=sizeof(ci->HMK);
00405           memcpy(chkkey,ci->HMK,sizeof(ci->HMK)); // signature check with HMK
00406           }
00407        else {
00408           keylen=sizeof(ci->PMK);
00409           memcpy(chkkey,ci->PMK,sizeof(ci->PMK)); // signature check with PMK
00410           }
00411 
00412         memcpy(&buffer[sindex-6],adr,5);
00413         if(SignatureCheck(&buffer[sindex-6],slen+6,chkkey,date,&buffer[sindex+slen],keylen))
00414           {
00415           char str[20];
00416           LBPUT(" - OK");
00417           for(i=0 ; i<numKeys ; i++) LBPUT(" - PK %02x %s",id[i],KeyStr(str,pk[i]));
00418           if(mk) LBPUT(" - PMK %s",KeyStr(str,mk));
00419 
00420           for(i=0 ; i<numKeys ; i++) {
00421             FoundKey();
00422             if(keys.NewKey('I',ci->provBase,id[i],pk[i],8)) NewKey();
00423             }
00424           if(mk) {
00425             FoundKey();
00426             if(Icards.Update(ci,mk,prvId[0]?prvId:0)) NewKey();
00427             }
00428           break;
00429           }
00430         else {
00431           LBPUT(" - FAIL");
00432           }
00433         LBEND();
00434 
00435         memcpy(buffer,data,n); // restore the buffer
00436         }
00437       ci=Icards.Next(ci);
00438       }
00439     }
00440 }
00441 
00442 // -- cSystemLinkIrd -----------------------------------------------------------
00443 
00444 class cSystemLinkIrd : public cSystemLink {
00445 public:
00446   cSystemLinkIrd(void);
00447   virtual bool CanHandle(unsigned short SysId);
00448   virtual cSystem *Create(void) { return new cSystemIrd; }
00449   };
00450 
00451 static cSystemLinkIrd staticInit;
00452 
00453 cSystemLinkIrd::cSystemLinkIrd(void)
00454 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
00455 {
00456   Feature.NeedsKeyFile();
00457 }
00458 
00459 bool cSystemLinkIrd::CanHandle(unsigned short SysId)
00460 {
00461   return (SysId&SYSTEM_MASK)==SYSTEM_IRDETO || (SysId&SYSTEM_MASK)==SYSTEM_BETA;
00462 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines