SASC-NG
DVBSoftCAM

sc-videoguard2.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 "smartcard.h"
00025 #include "data.h"
00026 #include "crypto.h"
00027 #include "misc.h"
00028 #include "parse.h"
00029 #include "helper.h"
00030 #include "log-sc.h"
00031 #include "log-core.h"
00032 #include "version.h"
00033 
00034 SCAPIVERSTAG();
00035 
00036 #define SYSTEM_VIDEOGUARD2   0x0900
00037 
00038 #define SYSTEM_NAME          "SC-VideoGuard2"
00039 #define SYSTEM_PRI           -5
00040 
00041 #define SC_NAME "VideoGuard2"
00042 #define SC_ID   MAKE_SC_ID('V','i','G','2')
00043 
00044 #define L_SC        17
00045 #define L_SC_ALL    LALL(L_SC_LASTDEF)
00046 
00047 static const struct LogModule lm_sc = {
00048   (LMOD_ENABLE|L_SC_ALL)&LOPT_MASK,
00049   (LMOD_ENABLE|L_SC_DEFDEF)&LOPT_MASK,
00050   "sc-videoguard2",
00051   { L_SC_DEFNAMES }
00052   };
00053 ADD_MODULE(L_SC,lm_sc)
00054 
00055 // -- cSystemScVideoGuard2 ---------------------------------------------------------------
00056 
00057 class cSystemScVideoGuard2 : public cSystemScCore {
00058 public:
00059   cSystemScVideoGuard2(void);
00060   };
00061 
00062 cSystemScVideoGuard2::cSystemScVideoGuard2(void)
00063 :cSystemScCore(SYSTEM_NAME,SYSTEM_PRI,SC_ID,"SC VideoGuard2")
00064 {
00065   hasLogger=true;
00066 }
00067 
00068 // -- cSystemLinkScVideoGuard2 --------------------------------------------------------
00069 
00070 class cSystemLinkScVideoGuard2 : public cSystemLink {
00071 public:
00072   cSystemLinkScVideoGuard2(void);
00073   virtual bool CanHandle(unsigned short SysId);
00074   virtual cSystem *Create(void) { return new cSystemScVideoGuard2; }
00075   };
00076 
00077 static cSystemLinkScVideoGuard2 staticInit;
00078 
00079 cSystemLinkScVideoGuard2::cSystemLinkScVideoGuard2(void)
00080 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
00081 {
00082   Feature.NeedsSmartCard();
00083 }
00084 
00085 bool cSystemLinkScVideoGuard2::CanHandle(unsigned short SysId)
00086 {
00087   bool res=false;
00088   cSmartCard *card=smartcards.LockCard(SC_ID);
00089   if(card) {
00090     res=card->CanHandle(SysId);
00091     smartcards.ReleaseCard(card);
00092     }
00093   return res;
00094 }
00095 
00096 // -- cSmartCardDataVideoGuard2 -----------------------------------------------------
00097 
00098 enum eDataType { dtBoxId, dtSeed };
00099 
00100 class cSmartCardDataVideoGuard2 : public cSmartCardData {
00101 public:
00102   eDataType type;
00103   unsigned char boxid[4];
00104   unsigned char seed0[64], seed1[64];
00105   //
00106   cSmartCardDataVideoGuard2(void);
00107   cSmartCardDataVideoGuard2(eDataType Type);
00108   virtual bool Parse(const char *line);
00109   virtual bool Matches(cSmartCardData *param);
00110   };
00111 
00112 cSmartCardDataVideoGuard2::cSmartCardDataVideoGuard2(void)
00113 :cSmartCardData(SC_ID)
00114 {}
00115 
00116 cSmartCardDataVideoGuard2::cSmartCardDataVideoGuard2(eDataType Type)
00117 :cSmartCardData(SC_ID)
00118 {
00119   type=Type;
00120 }
00121 
00122 bool cSmartCardDataVideoGuard2::Matches(cSmartCardData *param)
00123 {
00124   cSmartCardDataVideoGuard2 *cd=(cSmartCardDataVideoGuard2 *)param;
00125   return cd->type==type;
00126 }
00127 
00128 bool cSmartCardDataVideoGuard2::Parse(const char *line)
00129 {
00130   line=skipspace(line);
00131   if(!strncasecmp(line,"BOXID",5))     { type=dtBoxId; line+=5; }
00132   else if(!strncasecmp(line,"SEED",4)) { type=dtSeed; line+=4; }
00133   else {
00134     PRINTF(L_CORE_LOAD,"smartcarddatavideoguard2: format error: datatype");
00135     return false;
00136     }
00137   line=skipspace(line);
00138   switch(type) {
00139     case dtBoxId:
00140       if(GetHex(line,boxid,sizeof(boxid))!=sizeof(boxid)) {
00141         PRINTF(L_CORE_LOAD,"smartcarddatavideoguard2: format error: boxid");
00142         return false;
00143         }
00144       break;
00145     case dtSeed:
00146       if(GetHex(line,seed0,sizeof(seed0))!=sizeof(seed0)) {
00147         PRINTF(L_CORE_LOAD,"smartcarddatacryptoworks: format error: seed0");
00148         return false;
00149         }
00150       line=skipspace(line);
00151       if(GetHex(line,seed1,sizeof(seed1))!=sizeof(seed1)) {
00152         PRINTF(L_CORE_LOAD,"smartcarddatacryptoworks: format error: seed1");
00153         return false;
00154         }
00155       break;
00156     }
00157   return true;
00158 }
00159 
00160 // -- cCamCryptVG2 -------------------------------------------------------------
00161 
00162 #define xor16(v1,v2,d) xxor((d),16,(v1),(v2))
00163 #define val_by2on3(x)  ((0xaaab*(x))>>16) //fixed point *2/3
00164 
00165 class cCamCryptVG2 : private cAES {
00166 private:
00167   unsigned short cardkeys[3][32];
00168   unsigned char stateD3A[16];
00169   //
00170   void LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry);
00171   void PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey);
00172   void RotateRightAndHash(unsigned char *p);
00173   void Reorder16A(unsigned char *dest, const unsigned char *src);
00174   void ReorderAndEncrypt(unsigned char *p);
00175   //
00176   void Process_D0(const unsigned char *ins, unsigned char *data, const unsigned char *status);
00177   void Process_D1(const unsigned char *ins, unsigned char *data, const unsigned char *status);
00178   void Decrypt_D3(unsigned char *ins, unsigned char *data, const unsigned char *status);
00179 public:
00180   void PostProcess_Decrypt(unsigned char *buff, int len, unsigned char *cw1, unsigned char *cw2);
00181   void SetSeed(const unsigned char *Key1, const unsigned char *Key2);
00182   void GetCamKey(unsigned char *buff);
00183 };
00184 
00185 void cCamCryptVG2::SetSeed(const unsigned char *Key1, const unsigned char *Key2)
00186 {
00187   memcpy(cardkeys[1],Key1,sizeof(cardkeys[1]));
00188   memcpy(cardkeys[2],Key2,sizeof(cardkeys[2]));
00189 }
00190 
00191 void cCamCryptVG2::GetCamKey(unsigned char *buff)
00192 {
00193   unsigned short *tb2=(unsigned short *)buff, c=1;
00194   memset(tb2,0,64);
00195   tb2[0]=1;
00196   for(int i=0; i<32; i++) LongMult(tb2,&c,cardkeys[1][i],0);
00197 }
00198 
00199 void cCamCryptVG2::PostProcess_Decrypt(unsigned char *buff, int len, unsigned char *cw1, unsigned char *cw2)
00200 {
00201   switch(buff[0]) {
00202     case 0xD0:
00203       Process_D0(buff,buff+5,buff+buff[4]+5);
00204       break;
00205     case 0xD1:
00206       Process_D1(buff,buff+5,buff+buff[4]+5);
00207       break;
00208     case 0xD3:
00209       Decrypt_D3(buff,buff+5,buff+buff[4]+5);
00210       if(buff[1]==0x54) {
00211         memcpy(cw1,buff+5,8);
00212         for(int ind=14; ind<len+5;) {
00213           if(buff[ind]==0x25) {
00214             memcpy(cw2,buff+5+ind+2,8);
00215             break;
00216             }
00217           if(buff[ind+1]==0) break;
00218           ind+=buff[ind+1];
00219           }
00220         }
00221       break;
00222     }
00223 }
00224 
00225 void cCamCryptVG2::Process_D0(const unsigned char *ins, unsigned char *data, const unsigned char *status)
00226 {
00227   switch(ins[1]) {
00228     case 0xb4:
00229       memcpy(cardkeys[0],data,sizeof(cardkeys[0]));
00230       break;
00231     case 0xbc: 
00232       {
00233       unsigned short *idata=(unsigned short *)data;
00234       const unsigned short *key1=(const unsigned short *)cardkeys[1];
00235       unsigned short key2[32];
00236       memcpy(key2,cardkeys[2],sizeof(key2));
00237       for(int count2=0; count2<32; count2++) {
00238         unsigned int rem=0, div=key1[count2];
00239         for(int i=31; i>=0; i--) {
00240           unsigned int x=idata[i] | (rem<<16);
00241           rem=(x%div)&0xffff;
00242           }
00243         unsigned int carry=1, t=val_by2on3(div) | 1;
00244         while(t) {
00245           if(t&1) carry=((carry*rem)%div)&0xffff;
00246           rem=((rem*rem)%div)&0xffff;
00247           t>>=1;
00248           }
00249         PartialMod(carry,count2,key2,key1);
00250         }
00251       unsigned short idatacount=0;
00252       for(int i=31; i>=0; i--) LongMult(idata,&idatacount,key1[i],key2[i]);
00253       unsigned char stateD1[16];
00254       Reorder16A(stateD1,data);
00255       cAES::SetKey(stateD1);
00256       break;
00257       }
00258   }
00259 }
00260 
00261 void cCamCryptVG2::Process_D1(const unsigned char *ins, unsigned char *data, const unsigned char *status)
00262 {
00263   unsigned char iter[16], tmp[16];
00264   memset(iter,0,sizeof(iter));
00265   memcpy(iter,ins,5);
00266   xor16(iter,stateD3A,iter);
00267   memcpy(stateD3A,iter,sizeof(iter));
00268 
00269   int datalen=status-data;
00270   int datalen1=datalen;
00271   if(datalen<0) datalen1+=15;
00272   int blocklen=datalen1>>4;
00273   for(int i=0,iblock=0; i<blocklen+2; i++,iblock+=16) {
00274     unsigned char in[16];
00275     if(blocklen==i) {
00276       memset(in,0,sizeof(in));
00277       memcpy(in,&data[iblock],datalen-(datalen1&~0xf));
00278       }
00279     else if(blocklen+1==i) {
00280       memset(in,0,sizeof(in));
00281       memcpy(&in[5],status,2);
00282       }
00283     else
00284       memcpy(in,&data[iblock],sizeof(in));
00285 
00286     xor16(iter,in,tmp);
00287     ReorderAndEncrypt(tmp);
00288     xor16(tmp,stateD3A,iter);
00289     }
00290   memcpy(stateD3A,tmp,16);
00291 }
00292 
00293 void cCamCryptVG2::Decrypt_D3(unsigned char *ins, unsigned char *data, const unsigned char *status)
00294 {
00295   if(ins[4]>16) ins[4]-=16;
00296   if(ins[1]==0xbe) memset(stateD3A,0,sizeof(stateD3A));
00297 
00298   unsigned char tmp[16];
00299   memset(tmp,0,sizeof(tmp));
00300   memcpy(tmp,ins,5);
00301   xor16(tmp,stateD3A,stateD3A);
00302 
00303   int len1=ins[4];
00304   int blocklen=len1>>4;
00305   if(ins[1]!=0xbe) blocklen++;
00306 
00307   unsigned char iter[16], states[16][16];
00308   memset(iter,0,sizeof(iter));
00309   for(int blockindex=0; blockindex<blocklen; blockindex++) {
00310     iter[0]+=blockindex;
00311     xor16(iter,stateD3A,iter);
00312     ReorderAndEncrypt(iter);
00313     xor16(iter,&data[blockindex*16],states[blockindex]);
00314     if(blockindex==(len1>>4)) {
00315       int c=len1-(blockindex*16);
00316       if(c<16) memset(&states[blockindex][c],0,16-c);
00317       }
00318     xor16(states[blockindex],stateD3A,stateD3A);
00319     RotateRightAndHash(stateD3A);
00320     }
00321   memset(tmp,0,sizeof(tmp));
00322   memcpy(tmp+5,status,2);
00323   xor16(tmp,stateD3A,stateD3A);
00324   ReorderAndEncrypt(stateD3A);
00325 
00326   memcpy(stateD3A,status-16,sizeof(stateD3A));
00327   ReorderAndEncrypt(stateD3A);
00328 
00329   memcpy(data,states[0],len1);
00330   if(ins[1]==0xbe) {
00331     Reorder16A(tmp,states[0]);
00332     cAES::SetKey(tmp);
00333     }
00334 }
00335 
00336 void cCamCryptVG2::ReorderAndEncrypt(unsigned char *p)
00337 {
00338   unsigned char tmp[16];
00339   Reorder16A(tmp,p); cAES::Encrypt(tmp,16,tmp); Reorder16A(p,tmp);
00340 }
00341 
00342 // reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD
00343 
00344 void cCamCryptVG2::Reorder16A(unsigned char *dest, const unsigned char *src)
00345 {
00346   for(int i=0,k=0; i<4; i++)
00347     for(int j=i; j<16; j+=4,k++)
00348       dest[k]=src[j];
00349 }
00350 
00351 void cCamCryptVG2::LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry)
00352 {
00353   for(int i=0; i<*pLen; i++) {
00354     carry+=pData[i]*mult;
00355     pData[i]=(unsigned short)carry;
00356     carry>>=16;
00357     }
00358   if(carry) pData[(*pLen)++]=carry;
00359 }
00360 
00361 void cCamCryptVG2::PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey)
00362 {
00363   if(count) {
00364     unsigned int mod=inkey[count];
00365     unsigned short mult=(inkey[count]-outkey[count-1])&0xffff;
00366     for(unsigned int i=0,ib1=count-2; i<count-1; i++,ib1--) {
00367       unsigned int t=(inkey[ib1]*mult)%mod;
00368       mult=t-outkey[ib1];
00369       if(mult>t) mult+=mod;
00370       }
00371     mult+=val;
00372     if((val>mult) || (mod<mult)) mult-=mod;
00373     outkey[count]=(outkey[count]*mult)%mod;
00374     }
00375   else 
00376     outkey[0]=val;
00377 }
00378 
00379 static const unsigned char table1[256] = {
00380   0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
00381   0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
00382   0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
00383   0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
00384   0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
00385   0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
00386   0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
00387   0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
00388   0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
00389   0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
00390   0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
00391   0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
00392   0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
00393   0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
00394   0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
00395   0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
00396   };
00397 
00398 void cCamCryptVG2::RotateRightAndHash(unsigned char *p)
00399 {
00400   unsigned char t1=p[15];
00401   for(int i=0; i<16; i++) {
00402     unsigned char t2=t1;
00403     t1=p[i]; p[i]=table1[(t1>>1)|((t2&1)<<7)];
00404     }
00405 }
00406 
00407 // -- cCmdTable ----------------------------------------------------------------
00408 
00409 struct CmdTabEntry {
00410   unsigned char cla;
00411   unsigned char cmd;
00412   unsigned char len;
00413   unsigned char mode;
00414 };
00415 
00416 struct CmdTab {
00417   unsigned char index;
00418   unsigned char size;
00419   unsigned char Nentries; 
00420   unsigned char dummy;
00421   CmdTabEntry e[1];
00422 };
00423 
00424 class CmdTable {
00425 private:
00426   struct CmdTab *tab;
00427 public:
00428   CmdTable(const unsigned char *mem, int size);
00429   ~CmdTable();
00430   bool GetInfo(const unsigned char *cmd, unsigned char &rlen, unsigned char &rmode);
00431   };
00432 
00433 CmdTable::CmdTable(const unsigned char *mem, int size)
00434 {
00435   tab=(struct CmdTab *)new unsigned char[size];
00436   memcpy(tab,mem,size);
00437 }
00438 
00439 CmdTable::~CmdTable()
00440 {
00441   delete[] tab;
00442 }
00443 
00444 bool CmdTable::GetInfo(const unsigned char *cmd, unsigned char &rlen, unsigned char & rmode)
00445 {
00446   struct CmdTabEntry *pcte=tab->e;
00447   for(int i=0; i<tab->Nentries; i++,pcte++)
00448     if(cmd[1]==pcte->cmd) {
00449       rlen=pcte->len;
00450       rmode=pcte->mode;
00451       return true;
00452       }
00453   return false;
00454 }
00455 
00456 // -- cSmartCardVideoGuard2 -----------------------------------------------------------
00457 
00458 #define BASEYEAR 2000 // for date calculation
00459 
00460 class cSmartCardVideoGuard2 : public cSmartCard, private cIdSet {
00461 private:
00462   unsigned char CW1[8], CW2[8];
00463   unsigned char cardID[4], groupID[4], boxID[4];
00464   unsigned int CAID;
00465   cCamCryptVG2 state;
00466   CmdTable *cmdList;
00467 public:
00468   void ReadTiers(void);
00469   void RevDateCalc(const unsigned char *Date, int &year, int &mon, int &day, int &hh, int &mm, int &ss);
00470   void Datecalc(int year, int mon, int day, int hh, int mm, int ss , unsigned char * Date);
00471   int DoCmd(const unsigned char *ins, const unsigned char *txbuff=0, unsigned char *rxbuff=0);
00472   int ReadCmdLen(const unsigned char *cmd);
00473 public:
00474   cSmartCardVideoGuard2(void);
00475   ~cSmartCardVideoGuard2();
00476   virtual bool Init(void);
00477   virtual bool Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
00478   virtual bool Update(int pid, int caid, const unsigned char *data);
00479   virtual bool CanHandle(unsigned short SysId);
00480   };
00481 
00482 static const struct StatusMsg msgs[] = {
00483   { { 0x90,0x00 }, "Instruction executed without errors, noupdate, nofilter, IRD# not set", true },
00484   { { 0x90,0x01 }, "Instruction executed without errors, update, nofilter, IRD# not set", true },
00485   { { 0x90,0x20 }, "Instruction executed without errors, noupdate, nofilter, IRD# set", true },
00486   { { 0x90,0x21 }, "Instruction executed without errors, update, nofilter, IRD# set", true },
00487   { { 0x90,0x80 }, "Instruction executed without errors, noupdate, filter, IRD# not set", true },
00488   { { 0x90,0x81 }, "Instruction executed without errors, update, filter, IRD# not set", true },
00489   { { 0x90,0xa0 }, "Instruction executed without errors, noupdate, filter, IRD# set", true },
00490   { { 0x90,0xa1 }, "Instruction executed without errors, update, filter, IRD# set", true },
00491   { { 0x91,0x00 }, "Instruction executed without errors, noupdate, nofilter, IRD# not set", true },
00492   { { 0x91,0x01 }, "Instruction executed without errors, update, nofilter, IRD# not set", true },
00493   { { 0x91,0x20 }, "Instruction executed without errors, noupdate, nofilter, IRD# set", true },
00494   { { 0x91,0x21 }, "Instruction executed without errors, update, nofilter, IRD# set", true },
00495   { { 0x91,0x80 }, "Instruction executed without errors, noupdate, filter, IRD# not set", true },
00496   { { 0x91,0x81 }, "Instruction executed without errors, update, filter, IRD# not set", true },
00497   { { 0x91,0xa0 }, "Instruction executed without errors, noupdate, filter, IRD# set", true },
00498   { { 0x91,0xa1 }, "Instruction executed without errors, update, filter, IRD# set", true },
00499   { { 0xFF,0xFF }, 0, false }
00500   };
00501 
00502 static const struct CardConfig cardCfg = {
00503   SM_8O2,2000,1400
00504   };
00505 
00506 static const struct CardConfig cardCfgDelay = {
00507   SM_8O2,2000,1400,20
00508   };
00509 
00510 cSmartCardVideoGuard2::cSmartCardVideoGuard2(void)
00511 :cSmartCard(&cardCfg,msgs)
00512 {
00513   cmdList=0; CAID=0;
00514 }
00515 
00516 cSmartCardVideoGuard2::~cSmartCardVideoGuard2(void)
00517 {
00518   delete cmdList;
00519 }
00520 
00521 bool cSmartCardVideoGuard2::CanHandle(unsigned short SysId)
00522 {
00523   return SysId==CAID;
00524 }
00525 
00526 bool cSmartCardVideoGuard2::Init(void)
00527 {
00528   static const unsigned char vg2Hist[] = { 'i',0xff,'J','P' };
00529   if(atr->histLen<4 || memcmp(&atr->hist[3],vg2Hist,4)) {
00530     PRINTF(L_SC_INIT,"doesn't look like a VideoGuard2 card");
00531     return false;
00532     }
00533 
00534   infoStr.Begin();
00535   infoStr.Strcat("VideoGuard2 smartcard\n");
00536   snprintf(idStr,sizeof(idStr),"%s (%c%c.%d)",SC_NAME,atr->hist[10],atr->hist[11],atr->hist[12]);
00537   
00538   ResetIdSet();
00539   delete cmdList; cmdList=0;
00540 
00541   static unsigned char ins7401[] = { 0xD0,0x74,0x01,0x00,0x00 };
00542   int l;
00543   if((l=ReadCmdLen(ins7401))<0) {
00544     PRINTF(L_SC_ERROR,"bogus answer. Now try delayed mode");
00545     NewCardConfig(&cardCfgDelay);
00546     if((l=ReadCmdLen(ins7401))<0) return false;
00547     }
00548   ins7401[4]=l;
00549   unsigned char buff[256];
00550   if(!IsoRead(ins7401,buff) || !Status()) {
00551     PRINTF(L_SC_ERROR,"failed to read cmd list");
00552     return false;
00553     }
00554   cmdList=new CmdTable(buff,l);
00555 
00556   static const unsigned char ins7416[5] = { 0xD0,0x74,0x16,0x00,0x00 };
00557   if(DoCmd(ins7416)<0 || !Status()) {
00558     PRINTF(L_SC_ERROR,"cmd 7416 failed");
00559     return false;
00560     }
00561 
00562   static const unsigned char ins36[5] = { 0xD0,0x36,0x00,0x00,0x00 };
00563   bool boxidOK=false;
00564   if((l=DoCmd(ins36,0,buff))>0 && Status())
00565     for(int i=0; i<l ;i++) {
00566       if(buff[i]==0x00 && buff[i+1]==0xF3) {
00567         memcpy(&boxID,&buff[i+2],sizeof(boxID));
00568         boxidOK=true;
00569         break;
00570         }
00571       }
00572   if(!boxidOK) {
00573     cSmartCardDataVideoGuard2 cd(dtBoxId);
00574     cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd);
00575     if(entry) {
00576       memcpy(&boxID,entry->boxid,sizeof(boxID));
00577       boxidOK=true;
00578       }
00579     }
00580   if(!boxidOK) {
00581     PRINTF(L_SC_ERROR,"no boxID available");
00582     return false;
00583     }
00584 
00585   static const unsigned char ins4C[5] = { 0xD0,0x4C,0x00,0x00,0x00 }; 
00586   static unsigned char payload4C[9] = { 0,0,0,0, 3,0,0,2,4 };
00587   memcpy(payload4C,boxID,4);
00588   if(DoCmd(ins4C,payload4C)<0 || !Status()) {
00589     PRINTF(L_SC_ERROR,"sending boxid failed");
00590     return false;
00591     }
00592 
00593   static const unsigned char ins58[5] = { 0xD0,0x58,0x00,0x00,0x00 };
00594   if(DoCmd(ins58,0,buff)<0 || !Status()) {
00595     PRINTF(L_SC_ERROR,"failed to read card details");
00596     return false;
00597     }
00598   
00599   unsigned int c=WORD(buff,0x1D,0xFFFF);
00600   if(c!=CAID) CaidsChanged();
00601   CAID=c;
00602   memcpy(&cardID,&buff[8],4);
00603   memcpy(&groupID,&buff[8],4); groupID[3]=0;
00604   SetCard(new cCardNDS(cardID));
00605   AddProv(new cProviderNDS(groupID));
00606   char str[20], str2[20];
00607   infoStr.Printf("Cardtype: %c%c.%d\n"
00608                  "BoxID %s Caid %04x CardID %s\n",
00609                  atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4));
00610   PRINTF(L_SC_INIT,"cardtype: %c%c.%d boxID %s caid %04x cardID %s",atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4));
00611 
00612   cSmartCardDataVideoGuard2 cd(dtSeed);
00613   cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd);
00614   if(!entry) {
00615     PRINTF(L_SC_ERROR,"no NDS seed available");
00616     return false;
00617     }
00618   state.SetSeed(entry->seed0,entry->seed1);
00619   unsigned char tbuff[64];
00620   state.GetCamKey(tbuff);
00621 
00622   static const unsigned char insB4[5] = { 0xD0,0xB4,0x00,0x00,0x00 };
00623   if(DoCmd(insB4,tbuff)<0 || !Status()) {
00624     PRINTF(L_SC_ERROR,"cmd D0B4 failed");
00625     return false;
00626     }
00627   
00628   static const unsigned char insBC[5] = { 0xD0,0xBC,0x00,0x00,0x00 };
00629   if(DoCmd(insBC)<0 || !Status()) {
00630     PRINTF(L_SC_ERROR,"cmd D0BC failed");
00631     return false;
00632     }
00633   static const unsigned char insBE[5] = { 0xD3,0xBE,0x00,0x00,0x00 };
00634   if(DoCmd(insBE)<0 || !Status()) {
00635     PRINTF(L_SC_ERROR,"cmd D3BE failed");
00636     return false;
00637     }
00638 
00639   static const unsigned char ins58a[5] = { 0xD1,0x58,0x00,0x00,0x00 }; 
00640   if(DoCmd(ins58a)<0 || !Status()) {
00641     PRINTF(L_SC_ERROR,"cmd D158 failed");
00642     return false;
00643     }
00644   static const unsigned char ins4Ca[5] = { 0xD1,0x4C,0x00,0x00,0x00 }; 
00645   if(DoCmd(ins4Ca,payload4C)<0 || !Status()) {
00646     PRINTF(L_SC_ERROR,"cmd D14C failed");
00647     return false;
00648     }
00649   ReadTiers();
00650   return true;
00651 }
00652 
00653 bool cSmartCardVideoGuard2::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
00654 {
00655   static unsigned char ins40[5] = { 0xD1,0x40,0x40,0x80,0xFF };
00656   static const unsigned char ins54[5] = { 0xD3,0x54,0x00,0x00,0x00 };
00657   int posECMpart2=data[6]+7;
00658   int lenECMpart2=data[posECMpart2]+1;
00659   unsigned char tbuff[264];
00660   tbuff[0]=0;
00661   memcpy(&tbuff[1],&data[posECMpart2+1],lenECMpart2);
00662   ins40[4]=lenECMpart2;
00663   if(DoCmd(ins40,tbuff)>0 && Status()) {
00664     if(DoCmd(ins54)>0 && Status()) {
00665       if(data[0]&1) memcpy(cw+8,CW1,8);
00666       else          memcpy(cw+0,CW1,8);
00667       return true;
00668       }
00669     }
00670   return false;
00671 }
00672 
00673 bool cSmartCardVideoGuard2::Update(int pid, int caid, const unsigned char *data)
00674 {
00675   static unsigned char ins42[5] = { 0xD1,0x42,0x00,0x00,0xFF }; 
00676   if(MatchEMM(data)) {
00677     const unsigned char *payloaddata=cParseNDS::PayloadStart(data,cardID); //points to 02 xx yy
00678     int lenEMM;
00679     switch(payloaddata[0]) {
00680       case 2:
00681         lenEMM=payloaddata[payloaddata[1]+2];
00682         payloaddata+=3+payloaddata[1]; // skip len specifier
00683         break;
00684       default:
00685 //        di(printf("scvg2: ***ERROR***: EMM: bad payload type byte %02x\n",payloaddata[0]));
00686 //        DUMP3("VG2EMM",data,32);
00687         return false;
00688       }
00689 //    di(printf("scvg2: EMM: pid %d (%x) caid %d (%x) len %d (%x)\n",pid,pid,caid,caid,lenEMM,lenEMM));
00690 //    DUMP3("VG2EMM",data,32);
00691     if(lenEMM<=8 || lenEMM>188) {
00692 //      di(printf("scvg2: ***ERROR***: EMM: len %d bad\n",lenEMM));
00693       return false;
00694       }
00695     ins42[4]=lenEMM;
00696     if(DoCmd(ins42,payloaddata)>0 && Status())
00697       return true;
00698     }
00699   return false;
00700 }
00701 
00702 /*
00703 bool cSmartCardVideoGuard2::ZKT(void)
00704 {
00705   static unsigned char payload4A[1] = { 0x01 };
00706   static unsigned char ins4A[5] = { 0xD0,0x4A,0x15,0x01,0x01 };
00707   DoCmd(ins4A,payload4A);
00708   static unsigned char ins5A1[5] = { 0xD0,0x5A,0x15,0x01,0x10 };
00709   DoCmd(ins5A1);
00710   static unsigned char ins5A2[5] = { 0xD0,0x5A,0x11,0x02,0x40 };
00711   DoCmd(ins5A2);
00712   DoCmd(ins4A,payload4A);
00713   DoCmd(ins5A1);
00714   static unsigned char ins5A3[5] = { 0xD0,0x5A,0x10,0x02,0x40 };
00715   DoCmd(ins5A3);
00716   return true;
00717 }
00718 */
00719 
00720 void cSmartCardVideoGuard2::ReadTiers(void)
00721 {
00722   static const unsigned char ins2a[5] = { 0xd0,0x2a,0x00,0x00,0x00 };
00723   if(DoCmd(ins2a)<0 || !Status()) return;
00724   static unsigned char ins76[5] = { 0xd0,0x76,0x00,0x00,0x00 };
00725   ins76[3]=0x7f; ins76[4]=2;
00726   unsigned char buff[270];
00727   if(!IsoRead(ins76,buff) || !Status()) return;
00728   ins76[3]=0; ins76[4]=0;
00729   int num=buff[1];
00730   if(num>0) {
00731     infoStr.Strcat("Tier\tExpiry Date\n");
00732     infoStr.Strcat("----\t-----------\n");
00733     }
00734   for(int i=0; i<num; i++) {
00735     ins76[2]=i;
00736     if(DoCmd(ins76,0,buff)<0 || !Status()) return;
00737     if(buff[5+2]==0 && buff[5+3]==0) break;
00738     int y,m,d,H,M,S;
00739     RevDateCalc(&buff[5+4],y,m,d,H,M,S);
00740     char str[100];
00741     snprintf(str,sizeof(str),"%02x%02x\t%04d/%02d/%02d-%02d:%02d:%02d\n",buff[5+2],buff[5+3],y,m,d,H,M,S);
00742     infoStr.Strcat(str);
00743     PRINTF(L_SC_INIT,"Tier %02x%02x expires %04d/%02d/%02d-%02d:%02d:%02d",buff[5+2],buff[5+3],y,m,d,H,M,S);
00744     }
00745 }
00746 
00747 void cSmartCardVideoGuard2::RevDateCalc(const unsigned char *Date, int &year, int &mon, int &day, int &hh, int &mm, int &ss)
00748 { 
00749   year=(Date[0]/12)+BASEYEAR; 
00750   mon=(Date[0]%12)+1; 
00751   day=Date[1]; 
00752   hh=Date[2]/8; 
00753   mm=(0x100*(Date[2]-hh*8)+Date[3])/32; 
00754   ss=(Date[3]-mm*32)*2; 
00755 }
00756 
00757 void cSmartCardVideoGuard2::Datecalc(int year, int mon, int day, int hh, int mm, int ss , unsigned char *Date)
00758 { 
00759   Date[0]=((year-BASEYEAR)*12 + (mon-1)); 
00760   Date[1]=day; 
00761   Date[2]=hh*8+mm/8; 
00762   Date[3]=ss/2+mm*32; 
00763 } 
00764 
00765 int cSmartCardVideoGuard2::DoCmd(const unsigned char *ins, const unsigned char *txbuff, unsigned char *rxbuff)
00766 {
00767   unsigned char ins2[5];
00768   memcpy(ins2,ins,5);
00769   unsigned char len=0, mode=0;
00770   if(cmdList->GetInfo(ins2,len,mode)) {
00771     if(len==0xFF && mode==2) {
00772       if(ins2[4]==0) ins2[4]=len=ReadCmdLen(ins2);
00773       }
00774     else if(mode!=0) ins2[4]=len;
00775     }
00776   if(ins2[0]==0xd3) ins2[4]=len+16;
00777   len=ins2[4];
00778 
00779   unsigned char b[256], tmp[264];
00780   if(!rxbuff) rxbuff=tmp;
00781   if(mode>1) {
00782     if(!IsoRead(ins2,b) || !Status()) return -1;
00783     memcpy(rxbuff,ins2,5);
00784     memcpy(rxbuff+5,b,len);
00785     memcpy(rxbuff+5+len,sb,2);
00786     }
00787   else {
00788     if(!IsoWrite(ins2,txbuff) || !Status()) return -1;
00789     memcpy(rxbuff,ins2,5);
00790     memcpy(rxbuff+5,txbuff,len);
00791     memcpy(rxbuff+5+len,sb,2);
00792     }
00793   state.PostProcess_Decrypt(rxbuff,len,CW1,CW2);
00794   return len;
00795 }
00796 
00797 int cSmartCardVideoGuard2::ReadCmdLen(const unsigned char *cmd)
00798 {
00799   unsigned char cmd2[5], resp[16];
00800   memcpy(cmd2,cmd,5);
00801   cmd2[3]=0x80;
00802   cmd2[4]=1;
00803   if(!IsoRead(cmd2,resp) || !Status()) {
00804     PRINTF(L_SC_ERROR,"failed to read %02x%02x cmd length",cmd[1],cmd[2]);
00805     return -1;
00806     }
00807   return resp[0];  
00808 }
00809 
00810 // -- cSmartCardLinkVG2 -------------------------------------------------------
00811 
00812 class cSmartCardLinkVG2 : public cSmartCardLink {
00813 public:
00814   cSmartCardLinkVG2(void):cSmartCardLink(SC_NAME,SC_ID) {}
00815   virtual cSmartCard *Create(void) { return new cSmartCardVideoGuard2; }
00816   virtual cSmartCardData *CreateData(void) { return new cSmartCardDataVideoGuard2; }
00817   };
00818 
00819 static cSmartCardLinkVG2 staticScInit;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines