|
SASC
DVBSoftCAM
|
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;