SASC-NG
DVBSoftCAM

sc-nagra.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 <openssl/rand.h>
00024 
00025 #include "system-common.h"
00026 #include "smartcard.h"
00027 #include "parse.h"
00028 #include "crypto.h"
00029 #include "helper.h"
00030 #include "opts.h"
00031 #include "log-sc.h"
00032 #include "log-core.h"
00033 #include "version.h"
00034 
00035 SCAPIVERSTAG();
00036 
00037 #define SYSTEM_NAGRA         0x1800
00038 
00039 #define SYSTEM_NAME          "SC-Nagra"
00040 #define SYSTEM_PRI           -5
00041 
00042 #define SC_NAME "Nagra"
00043 #define SC_ID   MAKE_SC_ID('N','a','g','r')
00044 
00045 #define L_SC        11
00046 #define L_SC_PROC   LCLASS(L_SC,L_SC_LASTDEF<<1)
00047 #define L_SC_ALL    LALL(L_SC_PROC)
00048 
00049 static const struct LogModule lm_sc = {
00050   (LMOD_ENABLE|L_SC_ALL)&LOPT_MASK,
00051   (LMOD_ENABLE|L_SC_DEFDEF|L_SC_PROC)&LOPT_MASK,
00052   "sc-nagra",
00053   { L_SC_DEFNAMES,"process" }
00054   };
00055 ADD_MODULE(L_SC,lm_sc)
00056 
00057 static int allowT14=0;
00058 
00059 // -- cSystemScNagra ---------------------------------------------------------------------
00060 
00061 class cSystemScNagra : public cSystemScCore {
00062 public:
00063   cSystemScNagra(void);
00064   };
00065 
00066 cSystemScNagra::cSystemScNagra(void)
00067 :cSystemScCore(SYSTEM_NAME,SYSTEM_PRI,SC_ID,"SC Nagra")
00068 {
00069   hasLogger=true;
00070 }
00071 
00072 // -- cSystemLinkScNagra --------------------------------------------------------------
00073 
00074 class cSystemLinkScNagra : public cSystemLink {
00075 public:
00076   cSystemLinkScNagra(void);
00077   virtual bool CanHandle(unsigned short SysId);
00078   virtual cSystem *Create(void) { return new cSystemScNagra; }
00079   };
00080 
00081 static cSystemLinkScNagra staticInit;
00082 
00083 cSystemLinkScNagra::cSystemLinkScNagra(void)
00084 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
00085 {
00086   opts=new cOpts(SYSTEM_NAME,1);
00087   opts->Add(new cOptBool("AllowT14",trNOOP("SC-Nagra: use T14 Nagra mode"),&allowT14));
00088   Feature.NeedsSmartCard();
00089 }
00090 
00091 bool cSystemLinkScNagra::CanHandle(unsigned short SysId)
00092 {
00093   bool res=false;
00094   cSmartCard *card=smartcards.LockCard(SC_ID);
00095   if(card) {
00096     res=card->CanHandle(SysId);
00097     smartcards.ReleaseCard(card);
00098     }
00099   return res;
00100 }
00101 
00102 // -- cCamCryptNagra ------------------------------------------------------------------
00103 
00104 class cCamCryptNagra {
00105 private:
00106   cIDEA idea;
00107   cRSA rsa;
00108   cBN camMod, camExp;
00109   IdeaKS sessKey;
00110   unsigned int cardid;
00111   unsigned char boxkey[8], signature[8];
00112   bool hasMod;
00113   //
00114   void InitKey(unsigned char *key, const unsigned char *bk, unsigned int id);
00115   void Signature(unsigned char *sig, const unsigned char *key, const unsigned char *msg, int len);
00116 public:
00117   cCamCryptNagra(void);
00118   void SetCardData(unsigned int id, const unsigned char *bk, BIGNUM *exp);
00119   void SetCamMod(BIGNUM *m);
00120   bool HasCamMod(void) { return hasMod; }
00121   bool DecryptDT08(const unsigned char *dt08, unsigned int irdid, cBN *irdmod, bool fakeid);
00122   bool MakeSessionKey(unsigned char *out, const unsigned char *in);
00123   void DecryptCW(unsigned char *cw, const unsigned char *ecw1, const unsigned char *ecw2);
00124   };
00125 
00126 cCamCryptNagra::cCamCryptNagra(void)
00127 {
00128   hasMod=false;
00129 }
00130 
00131 void cCamCryptNagra::SetCardData(unsigned int id, const unsigned char *bk, BIGNUM *exp)
00132 {
00133   cardid=id;
00134   memcpy(boxkey,bk,sizeof(boxkey));
00135   BN_copy(camExp,exp);
00136   if(LOG(L_SC_PROC)) {
00137     unsigned char bb[4];
00138     camExp.Put(bb,2);
00139     LDUMP(L_SC_PROC,boxkey,sizeof(boxkey),"Active card data: CARDID: %08x EXP: %02x%02x BOXKEY:",cardid,bb[0],bb[1]);
00140     }
00141 }
00142 
00143 void cCamCryptNagra::SetCamMod(BIGNUM *m)
00144 {
00145   BN_copy(camMod,m);
00146   memcpy(signature,boxkey,sizeof(signature));
00147   hasMod=true;
00148 }
00149 
00150 void cCamCryptNagra::InitKey(unsigned char *key, const unsigned char *bk, unsigned int id)
00151 {
00152   memcpy(key,bk,8);
00153   BYTE4_BE(key+8 , id);
00154   BYTE4_BE(key+12,~id);
00155 }
00156 
00157 void cCamCryptNagra::Signature(unsigned char *sig, const unsigned char *key, const unsigned char *msg, int len)
00158 {
00159   unsigned char buff[16];
00160   memcpy(buff,key,16);
00161   for(int i=0; i<len; i+=8) {
00162     idea.Decrypt(msg+i,8,buff,buff,0);
00163     xxor(buff,8,buff,&msg[i]);
00164     memcpy(&buff[8],buff,8);
00165     }
00166   memcpy(sig,buff,8);
00167 }
00168 
00169 bool cCamCryptNagra::DecryptDT08(const unsigned char *dt08, unsigned int irdid, cBN *irdmod, bool fakeid)
00170 {
00171   if(LOG(L_SC_PROC)) {
00172     unsigned char bb[64];
00173     irdmod->Put(bb,sizeof(bb));
00174     LDUMP(L_SC_PROC,bb,sizeof(bb),"DT08 decrypt IRDID: %08x IRDMOD:",irdid);
00175     }
00176   unsigned char buff[72];
00177   if(rsa.RSA(buff,dt08+1,64,camExp,*irdmod)!=64) return false;
00178   memcpy(buff+64,dt08+1+64,8);
00179   buff[63]|=dt08[0]&0x80;
00180   LDUMP(L_SC_PROC,buff,72,"DT08 after RSA");
00181 
00182   unsigned char key[16];
00183   InitKey(key,boxkey,irdid);
00184   LDUMP(L_SC_PROC,key,16,"DT08 IDEA key");
00185   IdeaKS dks;
00186   idea.SetDecKey(key,&dks);
00187   idea.Decrypt(buff,72,&dks,0);
00188   LDUMP(L_SC_PROC,buff,72,"DT08 after IDEA");
00189 
00190   memcpy(signature,buff,8);
00191   LDUMP(L_SC_PROC,signature,8,"signature");
00192   BYTE4_BE(buff  ,0);
00193   BYTE4_BE(buff+4,fakeid?0xFFFFFFFF:cardid);
00194   Signature(buff,key,buff,72);
00195   LDUMP(L_SC_PROC,buff,8,"check sig");
00196   if(memcmp(signature,buff,8)) {
00197     PRINTF(L_SC_PROC,"DT08 signature failed");
00198     return false;
00199     }
00200   BN_bin2bn(buff+8,64,camMod);
00201   hasMod=true;
00202   return true;
00203 }
00204 
00205 bool cCamCryptNagra::MakeSessionKey(unsigned char *out, const unsigned char *camdata)
00206 {
00207   if(!hasMod) return false;
00208   if(LOG(L_SC_PROC)) {
00209     unsigned char bb[64];
00210     camMod.Put(bb,sizeof(bb));
00211     LDUMP(L_SC_PROC,bb,sizeof(bb),"Sessionkey negotiation CAMMOD:");
00212     }
00213   //decrypt $2A data here and prepare $2B reply
00214   if(rsa.RSA(out,camdata,64,camExp,camMod)!=64) return false;
00215   LDUMP(L_SC_PROC,out,64,"CMD 2A/26 after RSA:");
00216 
00217   unsigned char key[16], sess[16];
00218   InitKey(key,signature,cardid);
00219   LDUMP(L_SC_PROC,key,16,"first IDEA key: ");
00220   Signature(sess,key,out,32);
00221   memcpy(key,sess,8);
00222   memcpy(key+8,sess,8);
00223   LDUMP(L_SC_PROC,key,16,"second IDEA key:");
00224   Signature(sess+8,key,out,32);
00225   LDUMP(L_SC_PROC,sess,16,"SESSION KEY:    ");
00226   idea.SetDecKey(sess,&sessKey);
00227 
00228   if(rsa.RSA(out,out,64,camExp,camMod)!=64) return false;
00229   LDUMP(L_SC_PROC,out,64,"CMD 2B/27 data:");
00230   return true;
00231 }
00232 
00233 void cCamCryptNagra::DecryptCW(unsigned char *cw, const unsigned char *ecw1, const unsigned char *ecw2)
00234 {
00235   memcpy(cw+0,ecw1,8);
00236   idea.Decrypt(cw+0,8,&sessKey,0);
00237   memcpy(cw+8,ecw2,8);
00238   idea.Decrypt(cw+8,8,&sessKey,0);
00239 }
00240 
00241 // -- cSmartCardDataNagra ------------------------------------------------------
00242 
00243 struct SecondaryKey {
00244   unsigned char irdid[4];
00245   unsigned char free[8];
00246   unsigned char exp[2];
00247   unsigned char y1[8];
00248   unsigned char mod[64];
00249   unsigned char y2[8];
00250   unsigned char cs[2];
00251   } __attribute__((packed));
00252 
00253 class cSmartCardDataNagra : public cSmartCardData {
00254 private:
00255   unsigned short CRC16(const unsigned char *mem, int len, bool reverse);
00256 public:
00257   unsigned int cardid;
00258   unsigned char bk[8];
00259   cBN exp, mod;
00260   bool isIrdMod;
00261   //
00262   cSmartCardDataNagra(void);
00263   cSmartCardDataNagra(unsigned int id, bool irdmod);
00264   virtual bool Parse(const char *line);
00265   virtual bool Matches(cSmartCardData *param);
00266   };
00267 
00268 cSmartCardDataNagra::cSmartCardDataNagra(void)
00269 :cSmartCardData(SC_ID) {}
00270 
00271 cSmartCardDataNagra::cSmartCardDataNagra(unsigned int id, bool irdmod)
00272 :cSmartCardData(SC_ID)
00273 {
00274   cardid=id;
00275   isIrdMod=irdmod;
00276 }
00277 
00278 bool cSmartCardDataNagra::Matches(cSmartCardData *param)
00279 {
00280   cSmartCardDataNagra *cd=(cSmartCardDataNagra *)param;
00281   return cd->cardid==cardid && cd->isIrdMod==isIrdMod;
00282 }
00283 
00284 bool cSmartCardDataNagra::Parse(const char *line)
00285 {
00286   bool isSK=false;
00287   int dlen=64;
00288   BN_set_word(exp,3);
00289   line=skipspace(line);
00290   unsigned char id[4];
00291   if(GetHex(line,id,sizeof(id))!=sizeof(id)) {
00292     PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: card id");
00293     return false;
00294     }
00295   cardid=UINT32_BE(id);
00296   line=skipspace(line);
00297   if(!strncasecmp(line,"SK",2)) { isSK=true; dlen=96; line+=2; }
00298   else {
00299     if(GetHex(line,bk,sizeof(bk))!=sizeof(bk)) {
00300       PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: boxkey");
00301       return false;
00302       }
00303     line=skipspace(line);
00304     if(!strncasecmp(line,"IRDMOD",6)) { isIrdMod=true; line+=6; }
00305     else if(!strncasecmp(line,"CARDMOD",7)) { isIrdMod=false; line+=7; }
00306     else {
00307       PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: IRDMOD/CARDMOD");
00308       return false;
00309       }
00310     }
00311   line=skipspace(line);
00312 
00313   unsigned char *buff=AUTOMEM(dlen);
00314   if(GetHex(line,buff,dlen)!=dlen) {
00315     PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: data block");
00316     return false;
00317     }
00318   if(!isSK) {
00319     mod.Get(buff,64);
00320     }
00321   else {
00322     struct SecondaryKey *sk=(struct SecondaryKey *)buff;
00323     if(UINT16_BE(sk->cs)!=CRC16(buff,sizeof(*sk)-sizeof(sk->cs),false)) {
00324       PRINTF(L_CORE_LOAD,"smartcarddatanagra: secondary key CRC failed");
00325       return false;
00326       }
00327     unsigned short e=UINT16_BE(sk->exp);
00328     if(e!=0x0003 && e!=CRC16(buff,12,false)) BN_set_word(exp,e);
00329     xxor(bk,sizeof(bk),sk->y1,sk->y2);
00330     mod.Get(sk->mod,sizeof(sk->mod));
00331     }
00332   return true;
00333 }
00334 
00335 #define CRC_POLY 0x1021 // CRC-16(XMODEM) Polynomial: x16 + x12 + x5 + 1
00336 #define CRC_INIT 0x0000
00337 
00338 unsigned short cSmartCardDataNagra::CRC16(const unsigned char *mem, int len, bool reverse)
00339 {
00340   int index=0, dir=1;
00341   if(reverse) { index=len-1; dir=-1; }
00342   unsigned short crc=CRC_INIT;
00343   for(int i=0; i<len; i++) {
00344     crc^=(unsigned short)(mem[index]<<8);
00345     index+=dir;
00346     for(int j=0; j<8; j++) {
00347       if((crc&0x8000)) crc=(unsigned short)(((crc<<1)&0xFFFF)^CRC_POLY);
00348       else             crc=(unsigned short)( (crc<<1)&0xFFFF);
00349       }
00350     }
00351   return(crc);
00352 }
00353 
00354 // -- cSmartCardNagra -----------------------------------------------------------------
00355 
00356 #define SETIFS      0xC1
00357 
00358 // Datatypes
00359 #define IRDINFO     0x00
00360 #define DT01        0x01
00361 #define DT04        0x04
00362 #define TIERS       0x05
00363 #define DT06        0x06
00364 #define CAMDATA     0x08
00365 
00366 #define MAX_REC     20
00367 
00368 // Card Status checks
00369 #define HAS_CW()           ((state[2]&6)==6)
00370 #define RENEW_SESSIONKEY() (state[0]&224)
00371 #define SENDDATETIME()     (state[0]&16)
00372 
00373 class cSmartCardNagra : public cSmartCard, public cIdSet, private cCamCryptNagra {
00374 private:
00375   unsigned char buff[MAX_LEN+16], state[3], rominfo[15];
00376   unsigned int cardId, irdId;
00377   int caid, provId, block;
00378   bool isTiger, isT14Nagra, isN3, swapCW;
00379   //
00380   bool GetCardStatus(void);
00381   bool GetDataType(unsigned char dt, int len, int shots=MAX_REC);
00382   bool ParseDataType(unsigned char dt);
00383   bool DoCamExchange(void);
00384   bool SendDateTimeCmd(void);
00385   time_t Date(const unsigned char *data, char *buf, int len);
00386   bool DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, int rlen, const unsigned char *data=0);
00387   bool SetIFS(unsigned char len);
00388   void PostProcess(void);
00389 public:
00390   cSmartCardNagra(void);
00391   virtual bool Init(void);
00392   virtual bool Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
00393   virtual bool Update(int pid, int caid, const unsigned char *data);
00394   virtual bool CanHandle(unsigned short CaId);
00395   };
00396 
00397 static const struct StatusMsg msgs[] = {
00398   { { 0x6F,0x00 }, "Instruction not supported", false },
00399   { { 0x90,0x00 }, "Instruction executed without errors", true },
00400   { { 0xFF,0xFF }, 0, false }
00401   };
00402 
00403 static const struct CardConfig cardCfg = {
00404   SM_8O2,500,800
00405   };
00406 
00407 cSmartCardNagra::cSmartCardNagra(void)
00408 :cSmartCard(&cardCfg,msgs)
00409 {}
00410 
00411 bool cSmartCardNagra::SetIFS(unsigned char size)
00412 {
00413   unsigned char buf[5];
00414   // NAD, PCB, LEN
00415   buf[0]=0x21; buf[1]=0xC1; buf[2]=0x01;
00416   // Information Field size
00417   buf[3]=size; buf[4]=XorSum(buf,4);
00418   PRINTF(L_SC_INIT,"Setting IFS to 0x%02X",size);
00419   if(SerWrite(buf,5)!=5) {
00420     PRINTF(L_SC_ERROR,"failed to write IFS command");
00421     return false;
00422     }
00423   if(SerRead(buff,5,cardCfg.workTO)!=5 || XorSum(buff,5)) {
00424     PRINTF(L_SC_ERROR,"setting IFS to %02x failed",size);
00425     return false;
00426     }
00427   return true;
00428 }
00429 
00430 bool cSmartCardNagra::GetCardStatus(void)
00431 {
00432   if(!DoBlkCmd(0xC0,0x02,0xB0,0x06) || !Status()) {
00433     PRINTF(L_SC_ERROR,"failed to read card status");
00434     return false;
00435     }
00436   memcpy(state,buff+6,3);
00437   return true;
00438 }
00439 
00440 bool cSmartCardNagra::CanHandle(unsigned short CaId)
00441 {
00442   return CaId==caid;
00443 }
00444 
00445 bool cSmartCardNagra::Init(void)
00446 {
00447   block=0; isTiger=isT14Nagra=isN3=swapCW=false;
00448   caid=SYSTEM_NAGRA;
00449   ResetIdSet();
00450 
00451   static const unsigned char atrDNASP[] = { 'D','N','A','S','P' };
00452   static const unsigned char atrTIGER[] = { 'T','I','G','E','R' };
00453   static const unsigned char atrNCMED[] = { 'N','C','M','E','D' };
00454   static const unsigned char atrIRDET[] = { 'I','R','D','E','T','O' };
00455   if(!memcmp(atr->hist,atrDNASP,sizeof(atrDNASP))) {
00456     if(atr->hist[5]=='2' && atr->hist[6]=='4') isN3=true;
00457     PRINTF(L_SC_INIT,"detected native T1 nagra card (N%d Mode)",isN3?3:2);
00458     if(!SetIFS(0xFE)) return false;
00459     memcpy(rominfo,atr->hist,sizeof(rominfo));
00460     }
00461   else if(!memcmp(atr->hist,atrTIGER,sizeof(atrTIGER)) || !memcmp(atr->hist,atrNCMED,sizeof(atrNCMED))) {
00462     PRINTF(L_SC_INIT,"detected nagra tiger card");
00463     if(!SetIFS(0xFE)) return false;
00464     memcpy(rominfo,atr->hist,sizeof(rominfo));
00465     cardId=0xFFFFFFFF;
00466     isTiger=true;
00467     }
00468   else if(!memcmp(atr->hist,atrIRDET,sizeof(atrIRDET))) {
00469     PRINTF(L_SC_INIT,"detected tunneled T14 nagra card");
00470     if(!allowT14) {
00471       PRINTF(L_SC_INIT,"Nagra mode for T14 card disabled in setup");
00472       return false;
00473       }
00474     PRINTF(L_SC_INIT,"using nagra mode");
00475     isT14Nagra=true;
00476     if(!DoBlkCmd(0x10,0x02,0x90,0x11)) {
00477       PRINTF(L_SC_ERROR,"get rom version failed");
00478       return false;
00479       }
00480     memcpy(rominfo,&buff[2],15);
00481     }
00482   else {
00483     PRINTF(L_SC_INIT,"doesn't look like a nagra card");
00484     return false;
00485     }
00486 
00487   infoStr.Begin();
00488   infoStr.Strcat("Nagra smartcard\n");
00489   char rom[12], rev[12];
00490   snprintf(rom,sizeof(rom),"%c%c%c%c%c%c%c%c",rominfo[0],rominfo[1],rominfo[2],rominfo[3],rominfo[4],rominfo[5],rominfo[6],rominfo[7]);
00491   snprintf(rev,sizeof(rev),"%c%c%c%c%c%c",rominfo[9],rominfo[10],rominfo[11],rominfo[12],rominfo[13],rominfo[14]);
00492   PRINTF(L_SC_INIT,"rom version: %s revision: %s",rom,rev);
00493   infoStr.Printf("Rom %s Rev %s\n",rom,rev);
00494 
00495   if(!isTiger) {
00496     GetCardStatus();
00497     if(!DoBlkCmd(0x12,0x02,0x92,0x06) || !Status()) return false;
00498     cardId=UINT32_BE(buff+5);
00499     SetCard(new cCardNagra2(buff+5));
00500 
00501     if(!GetDataType(DT01,0x0E)) return false;
00502     GetCardStatus();
00503     if(!GetDataType(IRDINFO,0x39)) return false;
00504     GetCardStatus();
00505     if(!GetDataType(CAMDATA,0x55)) return false;
00506     GetCardStatus();
00507     if(!GetDataType(DT04,0x44)) return false;
00508     GetCardStatus();
00509     if(memcmp(rominfo+5,"181",3)!=0) { // not working on ROM181
00510       infoStr.Printf("Tiers\n");
00511       infoStr.Printf("|id  |chid| dates               |\n");
00512       infoStr.Printf("+----+----+---------------------+\n");
00513       if(!GetDataType(TIERS,0x57)) return false;
00514       GetCardStatus();
00515       }
00516     if(!GetDataType(DT06,0x16)) return false;
00517     GetCardStatus();
00518     }
00519 
00520   if(!HasCamMod()) {
00521     cSmartCardDataNagra cd(cardId,false);
00522     cSmartCardDataNagra *entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd);
00523     if(entry) {
00524       SetCardData(cardId,entry->bk,entry->exp);
00525       SetCamMod(entry->mod);
00526       }
00527     else {
00528       PRINTF(L_SC_ERROR,"can't find CARD modulus");
00529       return false;
00530       }
00531     }
00532   if(!DoCamExchange()) return false;
00533   infoStr.Finish();
00534   return true;
00535 }
00536 
00537 bool cSmartCardNagra::DoCamExchange(void)
00538 {
00539   if(!isTiger) {
00540     // N3 cam session negotiation start
00541     if(isN3 && (!DoBlkCmd(0x29,0x02,0xA9,0x04) || !Status())) return false;
00542 
00543     unsigned char ext[5];
00544     BYTE4_BE(ext,irdId); ext[4]=0; // tuner
00545     if((!isN3 && !DoBlkCmd(0x2A,0x02,0xAA,0x42)) ||
00546        ( isN3 && !DoBlkCmd(0x26,0x07,0xA6,0x42,ext)) ||
00547        !Status()) return false;
00548     unsigned char res[64+5];
00549     if(!MakeSessionKey(res,buff+5)) return false;
00550     memcpy(res+64,ext,5);
00551     cCondWait::SleepMs(500);
00552     if((!isN3 && !DoBlkCmd(0x2B,0x42,0xAB,0x02,res)) ||
00553        ( isN3 && !DoBlkCmd(0x27,0x47,0xA7,0x02,res)) ||
00554        !Status() ||
00555        !GetCardStatus()) return false;
00556     if(SENDDATETIME())
00557        SendDateTimeCmd();
00558     if(RENEW_SESSIONKEY()) {
00559       PRINTF(L_SC_ERROR,"Session key negotiation failed!");
00560       return false;
00561       }
00562     }
00563   else {
00564     static const unsigned char d1[] = { 0xd2 };
00565     if(!DoBlkCmd(0xD1,0x03,0x51,0x42,d1) || !Status()) return false;
00566 
00567     //XXX need implement Tiger session key handling (see oscam)
00568     return false;
00569 
00570     unsigned char res[64];
00571     if(!DoBlkCmd(0xD2,0x42,0x52,0x03,res) || !Status()) return false;
00572     }
00573   return true;
00574 }
00575 
00576 bool cSmartCardNagra::SendDateTimeCmd(void)
00577 {
00578   DoBlkCmd(0xC8,0x02,0xB8,0x06);
00579   return true;
00580 }
00581 
00582 void cSmartCardNagra::PostProcess(void)
00583 {
00584   if(!isTiger) {
00585     GetCardStatus();
00586     cCondWait::SleepMs(10);
00587     if(RENEW_SESSIONKEY()) DoCamExchange();
00588     if(SENDDATETIME()) SendDateTimeCmd();
00589     }
00590 }
00591 
00592 bool cSmartCardNagra::GetDataType(unsigned char dt, int len, int shots)
00593 {
00594   bool isdt8 = (dt==0x08);
00595   for(int i=0; i<shots; i++) {
00596     if(!DoBlkCmd(0x22,0x03,0xA2,len,&dt) || !Status()) {
00597      PRINTF(L_SC_ERROR,"failed to get datatype %02X",dt);
00598      return false;
00599      }
00600     if(buff[5]==0) break;
00601     if(!ParseDataType(dt&0x0F)) return false;
00602     if(isdt8 && buff[14]==0x49) break;
00603     dt|=0x80; // get next item
00604     }
00605   return true;
00606 }
00607 
00608 bool cSmartCardNagra::ParseDataType(unsigned char dt)
00609 {
00610   switch(dt) {
00611     case IRDINFO:
00612       {
00613       provId=(buff[10]*256)|buff[11];
00614       if(provId==0x0401 || provId==0x3411) swapCW=true;
00615       caid=SYSTEM_NAGRA+buff[14];
00616       irdId=UINT32_BE(buff+17);
00617       PRINTF(L_SC_INIT,"CAID: %04x PROV: %04x CARD ID: %08x IRD ID: %08x",caid,provId,cardId,irdId);
00618       infoStr.Printf("CAID: %04x PROV: %04x\nCARD ID: %08x\nIRD ID: %08x\n",caid,provId,cardId,irdId);
00619       break;
00620       }
00621     case TIERS:
00622       {
00623       int chid=(buff[14]*256)|buff[15];
00624       if(chid) {
00625         int id=(buff[10]*256)|buff[11];
00626         char ds[16], de[16];
00627         Date(buff+23,ds,sizeof(ds));
00628         Date(buff+16,de,sizeof(de));
00629         infoStr.Printf("|%04X|%04X|%s-%s|\n",id,chid,ds,de);
00630         PRINTF(L_SC_INIT,"|%04X|%04X|%s-%s|",id,chid,ds,de);
00631         }
00632       break;
00633       }
00634     case CAMDATA:
00635       if(buff[14]==0x49) {
00636         cSmartCardDataNagra cd(cardId,true);
00637         cSmartCardDataNagra *entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd);
00638         if(entry) {
00639           SetCardData(cardId,entry->bk,entry->exp);
00640           return DecryptDT08(buff+15,irdId,&entry->mod,swapCW);
00641           }
00642         else {
00643           PRINTF(L_SC_ERROR,"can't find IRD modulus");
00644           return false;
00645           }
00646         }
00647       break;
00648     }
00649   return true;
00650 }
00651 
00652 time_t cSmartCardNagra::Date(const unsigned char *data, char *buf, int len)
00653 {
00654   int day=((data[0]<<8)|data[1])-0x7f7;
00655   time_t ut=870393600L+day*(24*3600);
00656   if(buf) {
00657     struct tm rt;
00658     struct tm *t=gmtime_r(&ut,&rt);
00659     if(t) snprintf(buf,len,"%04d/%02d/%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday);
00660     else buf[0]=0;
00661     }
00662   return ut;
00663 }
00664 
00665 bool cSmartCardNagra::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
00666 {
00667   if(!isTiger) {
00668     unsigned char pkt[256+16];
00669     memset(pkt,0,sizeof(pkt));
00670     memcpy(pkt,data+3+2,data[4]);
00671     for(int i=1; i>=0; i--) {
00672       if(((!isN3 && DoBlkCmd(data[3],data[4]+2,0x87,0x02,pkt)) ||
00673           ( isN3 && DoBlkCmd(data[3]+1,data[4]+5+2,0x88,0x04,pkt))) &&
00674           Status())
00675         break;
00676       PRINTF(L_SC_ERROR,"ECM cmd failed%s",(i>0)?", retrying":"");
00677       if(i==0) return false;
00678       }
00679     cCondWait::SleepMs(10);
00680     for(int retry=0; !GetCardStatus() && retry<5; retry++) cCondWait::SleepMs(5);
00681     cCondWait::SleepMs(10);
00682     if(HAS_CW() && DoBlkCmd(0x1C,0x02,0x9C,0x36) && Status()) {
00683       DecryptCW(cw,buff+33,buff+7);
00684       PostProcess();
00685       if(swapCW) {
00686         unsigned char tt[8];
00687         memcpy(&tt[0],&cw[0],8);
00688         memcpy(&cw[0],&cw[8],8);
00689         memcpy(&cw[8],&tt[0],8);
00690         }
00691       return true;
00692       }
00693     }
00694   else {
00695     //                  ecm_data: 80 30 89 D3 87 54 11 10 DA A6 0F 4B 92 05 34 00 ...
00696     //serial_data: A0 CA 00 00 8C D3 8A 00 00 00 00 00 10 DA A6 0F .
00697     unsigned char ecm_trim[150];
00698     memset(ecm_trim,0,150);
00699     memcpy(&ecm_trim[5],data+3+2+2,data[4]+2);
00700     if(DoBlkCmd(data[3],data[4]+5,0x53,0x16,ecm_trim) && Status()) {
00701       DecryptCW(cw,buff+17,buff+9);
00702       PostProcess();
00703       return true;
00704       }
00705     }
00706   return false;
00707 }
00708 
00709 bool cSmartCardNagra::Update(int pid, int caid, const unsigned char *data)
00710 {
00711   if(MatchEMM(data)) {
00712     if(DoBlkCmd(data[8],data[9]+2,0x84,0x02,data+8+2) && Status()) {
00713       cCondWait::SleepMs(300);
00714       PostProcess();
00715       }
00716     return true;
00717     }
00718   return false;
00719 }
00720 
00721 bool cSmartCardNagra::DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, int rlen, const unsigned char *data)
00722 {
00723   /*
00724   here we build the command related to the protocol T1 for ROM142 or T14 for ROM181
00725   the only different that i know is the command length byte msg[4], this msg[4]+=1 by a ROM181 smartcard (_nighti_)
00726   one example for the cmd$C0
00727   T14 protocol:       01 A0 CA 00 00 03 C0 00 06 91
00728   T1  protocol: 21 00 08 A0 CA 00 00 02 C0 00 06 87
00729   */
00730   unsigned char msg[MAX_LEN+16];
00731   static char nagra_head[] = { 0xA0,0xCA,0x00,0x00 };
00732 
00733   memset(msg,0,sizeof(msg));
00734   int c=0;
00735   if(!isT14Nagra) {
00736     msg[c++]=0x21;
00737     msg[c++]=block; block^=0x40;
00738     msg[c++]=ilen+6;
00739     }
00740   else {
00741     msg[c++]=0x01;
00742     }
00743   memcpy(msg+c,nagra_head,sizeof(nagra_head)); c+=sizeof(nagra_head);
00744   msg[c]=ilen;
00745   msg[c+1]=cmd;
00746   int dlen=ilen-2;
00747   if(dlen<0) {
00748     PRINTF(L_SC_ERROR,"invalid data length encountered");
00749     return false;
00750     }
00751   msg[c+2]=dlen;
00752   if(isT14Nagra) msg[c]++;
00753   c+=3;
00754   if(data && dlen>0) { memcpy(msg+c,data,dlen); c+=dlen; }
00755   msg[c++]=rlen;
00756   msg[c]=XorSum(msg,c); c++;
00757 
00758   if(SerWrite(msg,c)==c) {
00759     LDUMP(L_CORE_SC,msg,c,"NAGRA: <-");
00760     cCondWait::SleepMs(10);
00761     if(SerRead(buff,3,cardCfg.workTO)!=3) {
00762       PRINTF(L_SC_ERROR,"reading back reply failed");
00763       return false;
00764       }
00765     int xlen=buff[2]+1;
00766     if(SerRead(buff+3,xlen,cardCfg.workTO)!=xlen) {
00767       PRINTF(L_SC_ERROR,"reading back information block failed");
00768       return false;
00769       }
00770     xlen+=3;
00771     if(XorSum(buff,xlen)) {
00772       PRINTF(L_SC_ERROR,"checksum failed");
00773       return false;
00774       }
00775     LDUMP(L_CORE_SC,buff,xlen,"NAGRA: ->");
00776 
00777     if(buff[3]!=res) {
00778       PRINTF(L_SC_ERROR,"result not expected (%02X != %02X)",buff[3],res);
00779       return false;
00780       }
00781     if(buff[2]-2!=rlen) {
00782       PRINTF(L_SC_ERROR,"result length not expected (%d != %d)",buff[2]-2,rlen);
00783       return false;
00784       }
00785     memcpy(sb,&buff[3+rlen],2);
00786     LDUMP(L_CORE_SC,sb,2,"NAGRA: ->");
00787     cCondWait::SleepMs(10);
00788     return true;
00789     }
00790   return false;
00791 }
00792 
00793 // -- cSmartCardLinkNagra -------------------------------------------------------------
00794 
00795 class cSmartCardLinkNagra : public cSmartCardLink {
00796 public:
00797   cSmartCardLinkNagra(void):cSmartCardLink(SC_NAME,SC_ID) {}
00798   virtual cSmartCard *Create(void) { return new cSmartCardNagra(); }
00799   virtual cSmartCardData *CreateData(void) { return new cSmartCardDataNagra; }
00800   };
00801 
00802 static cSmartCardLinkNagra staticScInit;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines