SASC
DVBSoftCAM

nagra1.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.h"
00024 #include "misc.h"
00025 #include "opts.h"
00026 #include "helper.h"
00027 
00028 #include "nagra.h"
00029 #include "nagra-def.h"
00030 #include "cpu.h"
00031 #include "log-nagra.h"
00032 
00033 #define SYSTEM_NAME          "Nagra"
00034 #define SYSTEM_PRI           -10
00035 
00036 // -- cEmu ---------------------------------------------------------------------
00037 
00038 #define MAX_COUNT 200000
00039 
00040 class cEmu : public c6805 {
00041 protected:
00042   int romNr, id;
00043   char *romName, *romExtName, *eepromName;
00044   //
00045   int InitStart, InitEnd;
00046   int EmmStart, EmmEnd, EmmKey0, EmmKey1;
00047   int FindKeyStart, FindKeyEnd;
00048   int MapAddr;
00049   int Rc1H, Rc1L;
00050   int EnsIrdChk, Cmd83Chk;
00051   int SoftInt, StackHigh;
00052   //
00053   bool AddRom(unsigned short addr, unsigned short size, const char *name);
00054   bool AddEeprom(unsigned short addr, unsigned short size, unsigned short otpSize, const char *name);
00055   //
00056   virtual bool InitSetup(void) { return true; }
00057   virtual bool UpdateSetup(const unsigned char *emm) { return true; }
00058   virtual bool MathMapHandler(void);
00059 public:
00060   cEmu(void);
00061   virtual ~cEmu();
00062   bool Init(int RomNr, int Id);
00063   bool GetOpKeys(const unsigned char *Emm, unsigned char *id, unsigned char *key0, unsigned char *key1);
00064   bool GetPkKeys(const unsigned char *select, unsigned char *pkset);
00065   bool Matches(int RomNr, int Id);
00066   };
00067 
00068 cEmu::cEmu(void)
00069 {
00070   romName=romExtName=eepromName=0;
00071 }
00072 
00073 cEmu::~cEmu()
00074 {
00075   free(romName);
00076   free(romExtName);
00077   free(eepromName);
00078 }
00079 
00080 bool cEmu::AddRom(unsigned short addr, unsigned short size, const char *name)
00081 {
00082   cMap *map=new cMapRom(addr,name);
00083   return AddMapper(map,addr,size);
00084 }
00085 
00086 bool cEmu::AddEeprom(unsigned short addr, unsigned short size, unsigned short otpSize, const char *name)
00087 {
00088   cMap *map=new cMapEeprom(addr,name,otpSize);
00089   return AddMapper(map,addr,size);
00090 }
00091 
00092 bool cEmu::Matches(int RomNr, int Id)
00093 {
00094   return (romNr==RomNr && id==Id);
00095 }
00096 
00097 bool cEmu::Init(int RomNr, int Id)
00098 {
00099   romNr=RomNr; id=Id;
00100   romName=bprintf("ROM%d.bin",romNr);
00101   romExtName=bprintf("ROM%dext.bin",romNr);
00102   eepromName=bprintf("eep%i_%02x.bin",romNr,(id&0xff00)>>8);
00103   if(InitSetup()) {
00104     ForceSet(EnsIrdChk, 0x81,true);
00105     ForceSet(Cmd83Chk+0,0x98,true);
00106     ForceSet(Cmd83Chk+1,0x9d,true);
00107     if(SoftInt) {
00108       Set(0x1ffc,SoftInt>>8);
00109       Set(0x1ffd,SoftInt&0xff);
00110       }
00111     SetSp(StackHigh,0);
00112     SetPc(InitStart);
00113     ClearBreakpoints();
00114     AddBreakpoint(InitEnd);
00115     if(!Run(MAX_COUNT)) return true;
00116     }
00117   return false;
00118 }
00119 
00120 bool cEmu::GetOpKeys(const unsigned char *Emm, unsigned char *id, unsigned char *key0, unsigned char *key1)
00121 {
00122   int keys=0;
00123   if(UpdateSetup(Emm)) {
00124     SetMem(0x0080,&Emm[0],64);
00125     SetMem(0x00F8,&Emm[1],2);
00126     SetPc(EmmStart);
00127     ClearBreakpoints();
00128     AddBreakpoint(EmmEnd);
00129     AddBreakpoint(MapAddr);
00130     AddBreakpoint(EmmKey0);
00131     AddBreakpoint(EmmKey1);
00132     while(!Run(MAX_COUNT)) {
00133       unsigned short pc=GetPc();
00134       if(pc==EmmKey0) {
00135         GetMem(0x82,key0,8);
00136         keys++;
00137         }
00138       if(pc==EmmKey1) {
00139         GetMem(0x82,key1,8);
00140         keys++;
00141         }
00142       if(pc==MapAddr) {
00143         if(!MathMapHandler()) break;
00144         PopPc(); // remove return address from stack
00145         }
00146       if(pc==EmmEnd) {
00147         GetMem(0x00F8,id,2);
00148         break;
00149         }
00150       }
00151     }
00152   return (keys==2);
00153 }
00154 
00155 bool cEmu::GetPkKeys(const unsigned char *select, unsigned char *pkset)
00156 {
00157   Set(0x0081,select[2]<<7);
00158   SetMem(0x00F8,select,3);
00159   SetPc(FindKeyStart);
00160   ClearBreakpoints();
00161   AddBreakpoint(FindKeyEnd);
00162   while(!Run(MAX_COUNT)) {
00163     unsigned short pc=GetPc();
00164     if(pc==FindKeyEnd) {
00165       if(!cc.c) {
00166         PRINTF(L_SYS_EMU,"Updating PK keys");
00167         unsigned short loc=(Get(Rc1H)<<8)+Get(Rc1L);
00168         for(int i=0; i<45; i+=15) GetMem(loc+4+i,pkset+i,15);
00169         return true;
00170         }
00171       else {
00172         PRINTF(L_SYS_EMU,"Updating PK keys failed. Used a correct EEPROM image for provider %04x ?",((select[0]<<8)|select[1]));
00173         break;
00174         }
00175       }
00176     }
00177   return false;
00178 }
00179 
00180 bool cEmu::MathMapHandler(void)
00181 {
00182   PRINTF(L_SYS_EMU,"Unsupported math call $%02x in ROM %d, please report",a,romNr);
00183   return false;
00184 }
00185 
00186 // -- cEmuRom3Core -------------------------------------------------------------
00187 
00188 class cEmuRom3Core : public cEmu {
00189 private:
00190   bool special05;
00191 protected:
00192   virtual void Stepper(void);
00193   virtual void WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op);
00194   virtual void ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op);
00195   bool CoreInitSetup(void);
00196   bool DoMaps(bool hasExt);
00197 public:
00198   cEmuRom3Core(void);
00199   };
00200 
00201 cEmuRom3Core::cEmuRom3Core(void)
00202 {
00203   hasReadHandler=hasWriteHandler=true;
00204   special05=false;
00205 }
00206 
00207 void cEmuRom3Core::WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op)
00208 {
00209   if(ea==0x05) special05=(op&0x40)!=0;
00210 }
00211 
00212 void cEmuRom3Core::ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op)
00213 {
00214   if(special05) {
00215     special05=false; // prevent loop
00216     unsigned short start=Get(0x30C0);
00217     unsigned short end=Get(0x30C1);
00218     if(((ea>>8)>=start) && ((ea>>8)<=end)) op=0x00; // dataspace
00219     else op=0x01;                                   // codespace
00220     special05=true;
00221     }
00222   else
00223     switch(ea) {
00224       case 0x06:
00225       case 0x07:
00226         if(!(Get(0x04)&4)) op=random()&0xFF;
00227         break;
00228       }
00229 }
00230 
00231 void cEmuRom3Core::Stepper(void)
00232 {}
00233 
00234 bool cEmuRom3Core::CoreInitSetup(void)
00235 {
00236   ForceSet(0x0001,1<<3,true);
00237   Set(0x0002,0x03);
00238   Set(0x004e,0x4B);
00239   return true;
00240 }
00241 
00242 bool cEmuRom3Core::DoMaps(bool hasExt)
00243 {
00244   // Eeprom & ROMext are non-fatal also they are required for some providers
00245   if(hasExt) AddRom(0x2000,0x2000,romExtName);
00246   AddEeprom(0xE000,0x1000,0x20,eepromName);
00247   return AddRom(0x4000,0x4000,romName);
00248 }
00249 
00250 // -- cEmuRom3 -----------------------------------------------------------------
00251 
00252 class cEmuRom3 : public cEmuRom3Core {
00253 protected:
00254   virtual bool InitSetup(void);
00255   virtual bool UpdateSetup(const unsigned char *emm);
00256 public:
00257   cEmuRom3(void);
00258   };
00259 
00260 cEmuRom3::cEmuRom3(void)
00261 {
00262   InitStart=0x4000;
00263   InitEnd  =0x734b;
00264   EmmStart =0x5a82;
00265   EmmEnd   =0x67db;
00266   EmmKey0  =0x617c;
00267   EmmKey1  =0x6184;
00268   FindKeyStart=0x6133;
00269   FindKeyEnd  =0x6147;
00270   MapAddr  =0x2800;
00271   Rc1H     =0x0024;
00272   Rc1L     =0x0025;
00273   EnsIrdChk=0x6437;
00274   Cmd83Chk =0x6431;
00275   SoftInt  =0x0000;
00276   StackHigh=0x7f;
00277 }
00278 
00279 bool cEmuRom3::InitSetup(void)
00280 {
00281   return DoMaps(true) && CoreInitSetup();
00282 }
00283 
00284 bool cEmuRom3::UpdateSetup(const unsigned char *emm)
00285 {
00286   return CoreInitSetup();
00287 }
00288 
00289 // -- cEmuRom7 -----------------------------------------------------------------
00290 
00291 class cEmuRom7 : public cEmuRom3Core {
00292 protected:
00293   virtual bool InitSetup(void);
00294   virtual bool UpdateSetup(const unsigned char *emm);
00295 public:
00296   cEmuRom7(void);
00297   };
00298 
00299 cEmuRom7::cEmuRom7(void)
00300 {
00301   InitStart=0x4000;
00302   InitEnd  =0x7b68;
00303   EmmStart =0x482b;
00304   EmmEnd   =0x6146;
00305   EmmKey0  =0x4f2a;
00306   EmmKey1  =0x4f32;
00307   FindKeyStart=0x4ee4;
00308   FindKeyEnd  =0x4ef5;
00309   MapAddr  =0x200f;
00310   Rc1H     =0x0028;
00311   Rc1L     =0x0029;
00312   EnsIrdChk=0x51df;
00313   Cmd83Chk =0x51d9;
00314   SoftInt  =0x4008;
00315   StackHigh=0x7f;
00316 }
00317 
00318 bool cEmuRom7::InitSetup(void)
00319 {
00320   return DoMaps(false) && CoreInitSetup();
00321 }
00322 
00323 bool cEmuRom7::UpdateSetup(const unsigned char *emm)
00324 {
00325   SetMem(0x01A2,&emm[1],2);
00326   return true;
00327 }
00328 
00329 // -- cEmuRom10Core ------------------------------------------------------------
00330 
00331 class cEmuRom10Core : public cEmu {
00332 protected:
00333   struct Map { unsigned char A[64], B[64], C[64], D[4], opSize; } map;
00334   //
00335   virtual void Stepper(void);
00336   virtual void WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op);
00337   virtual void ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op);
00338   bool DoMaps(bool hasExt, int romSize);
00339   bool CoreInitSetup(void);
00340   bool CoreUpdateSetup(const unsigned char *emm);
00341 public:
00342   cEmuRom10Core(void);
00343   };
00344 
00345 cEmuRom10Core::cEmuRom10Core(void)
00346 {
00347   hasReadHandler=hasWriteHandler=true;
00348 }
00349 
00350 void cEmuRom10Core::Stepper(void)
00351 {}
00352 
00353 void cEmuRom10Core::WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op)
00354 {
00355   if(ea==0x02) {
00356     unsigned char old=Get(0x02);
00357     if(!(old&0x80)) op=(op&0xFE) | (old&0x01);
00358     }
00359 }
00360 
00361 void cEmuRom10Core::ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op)
00362 {
00363   switch(ea) {
00364     case 0x05:
00365     case 0x06:
00366       if(cc.i && (Get(0x07)&0x80)) op=random()&0xFF;
00367       break;
00368     case 0x07:
00369       if(cc.i) op&=0xFD; else op|=0x02;
00370       break;
00371     }
00372 }
00373 
00374 bool cEmuRom10Core::DoMaps(bool hasExt, int romSize)
00375 {
00376   // Eeprom & ROMext are non-fatal also they are required for some providers
00377   if(hasExt) AddRom(0x2000,0x2000,romExtName);
00378   AddEeprom(0xC000,0x2000,0x40,eepromName);
00379   return AddRom(0x4000,romSize,romName);
00380 }
00381 
00382 bool cEmuRom10Core::CoreInitSetup(void)
00383 {
00384   ForceSet(0x01,0x13,true);
00385   Set(0x02,0x82); Set(0x02,0x3); // beware of the WriteHandler!
00386   Set(0x07,0xFF);
00387   return true;
00388 }
00389 
00390 bool cEmuRom10Core::CoreUpdateSetup(const unsigned char *emm)
00391 {
00392   SetMem(0x01A2,&emm[1],2);
00393   SetMem(0x0307,&emm[1],2);
00394   Set(0x0300,emm[5]);
00395   Set(0x0301,emm[2]);
00396   return true;
00397 }
00398 
00399 // -- cEmuRom10 ----------------------------------------------------------------
00400 
00401 class cEmuRom10 : public cEmuRom10Core {
00402 protected:
00403   virtual bool InitSetup(void);
00404   virtual bool UpdateSetup(const unsigned char *emm);
00405   virtual bool MathMapHandler(void);
00406 public:
00407   cEmuRom10(void);
00408   };
00409 
00410 cEmuRom10::cEmuRom10(void)
00411 {
00412   InitStart=0x4000;
00413   InitEnd  =0x81ca;
00414   EmmStart =0x6a71;
00415   EmmEnd   =0x81f7;
00416   EmmKey0  =0x7172;
00417   EmmKey1  =0x717a;
00418   FindKeyStart=0x712c;
00419   FindKeyEnd  =0x713d;
00420   MapAddr  =0x2020;
00421   Rc1H     =0x004a;
00422   Rc1L     =0x004b;
00423   EnsIrdChk=0x7427;
00424   Cmd83Chk =0x7421;
00425   SoftInt  =0x4004;
00426   StackHigh=0x3ff;
00427 }
00428 
00429 bool cEmuRom10::InitSetup(void)
00430 {
00431   return DoMaps(false,0x5A00) && CoreInitSetup();
00432 }
00433 
00434 bool cEmuRom10::UpdateSetup(const unsigned char *emm)
00435 {
00436   Set(0x006e,0x4B);
00437   return CoreUpdateSetup(emm);
00438 }
00439 
00440 bool cEmuRom10::MathMapHandler(void)
00441 {
00442   PRINTF(L_SYS_EMU,"math call: $%02x",a);
00443   switch(a) {
00444     case 0x02:
00445       switch(Get(0x41)) {
00446         case 0: map.opSize=0x04; break;
00447         case 1: map.opSize=0x20; break;
00448         case 2: map.opSize=0x24; break;
00449         case 3: map.opSize=0x30; break;
00450         case 4: map.opSize=0x34; break;
00451         case 5:
00452         default: map.opSize=0x40; break;
00453         }
00454       return true;
00455 
00456     case 0x0e:
00457     case 0x0F:
00458     case 0x10:
00459       {
00460       const unsigned short addr=(Get(0x4d)<<8)|Get(0x4e);
00461       unsigned char tmp[64];
00462       GetMem(addr,tmp,map.opSize);
00463       unsigned char *reg;
00464       switch(a) {
00465         case 0x0e: reg=map.A; break;
00466         case 0x0f: reg=map.B; break;
00467         case 0x10: reg=map.C; break;
00468         default: return false;
00469         }
00470       SetMem(addr,reg,map.opSize);
00471       memcpy(reg,tmp,map.opSize);
00472       Set(0x41,map.opSize);
00473       return true;
00474       }
00475 
00476     case 0x29:
00477       Set(0x120,1);
00478       return true;
00479     }
00480   return cEmu::MathMapHandler();
00481 }
00482 
00483 // -- cEmuRom11 ----------------------------------------------------------------
00484 
00485 class cEmuRom11 : public cEmuRom10Core {
00486 protected:
00487   virtual bool InitSetup(void);
00488   virtual bool UpdateSetup(const unsigned char *emm);
00489 public:
00490   cEmuRom11(void);
00491   };
00492 
00493 cEmuRom11::cEmuRom11(void)
00494 {
00495   InitStart=0x4000;
00496   InitEnd  =0x405b;
00497   EmmStart =0x5865;
00498   EmmEnd   =0x9990;
00499   EmmKey0  =0x5f66;
00500   EmmKey1  =0x5f6e;
00501   FindKeyStart=0x5f20;
00502   FindKeyEnd  =0x5f31;
00503   MapAddr  =0x2020;
00504   Rc1H     =0x004a;
00505   Rc1L     =0x004b;
00506   EnsIrdChk=0x621b;
00507   Cmd83Chk =0x6215;
00508   SoftInt  =0x4004;
00509   StackHigh=0x3ff;
00510 }
00511 
00512 bool cEmuRom11::InitSetup(void)
00513 {
00514   return DoMaps(false,0x8000) && CoreInitSetup();
00515 }
00516 
00517 bool cEmuRom11::UpdateSetup(const unsigned char *emm)
00518 {
00519   Set(0x0068,0x4B);
00520   return CoreUpdateSetup(emm);
00521 }
00522 
00523 // -- cNagraDES ----------------------------------------------------------------
00524 
00525 class cNagraDES {
00526 private:
00527   cDes des;
00528 protected:
00529   void Decrypt(const unsigned char *data, const unsigned char *key, unsigned char *out, bool desmod=false);
00530   void Crypt(const unsigned char *data, const unsigned char *key, unsigned char *out);
00531   bool SigCheck(const unsigned char *block, const unsigned char *sig, const unsigned char *vkey, const int rounds);
00532 };
00533 
00534 void cNagraDES::Decrypt(const unsigned char *data, const unsigned char *key, unsigned char *out, bool desmod)
00535 {
00536   unsigned char cardkey[8];
00537   memcpy(cardkey,key,8);
00538   RotateBytes(cardkey,8);
00539   memcpy(out,data,8);
00540   if(!desmod) RotateBytes(out,8);
00541   des.Des(out,cardkey,NAGRA_DES_DECR);
00542   if(!desmod) RotateBytes(out,8);
00543 }
00544 
00545 void cNagraDES::Crypt(const unsigned char *data, const unsigned char *key, unsigned char *out)
00546 {
00547   unsigned char cardkey[8];
00548   memcpy(cardkey,key,8);
00549   RotateBytes(cardkey,8);
00550   memcpy(out,data,8);
00551   RotateBytes(out,8);
00552   des.Des(out,cardkey,NAGRA_DES_ENCR);
00553   RotateBytes(out,8);
00554 }
00555 
00556 bool cNagraDES::SigCheck(const unsigned char *block, const unsigned char *sig, const unsigned char *vkey, const int rounds)
00557 {
00558   unsigned char hash[8];
00559   memcpy(hash,vkey,8);
00560   for(int j=0; j<rounds; j++) {
00561     unsigned char cr[8];
00562     Crypt(block+j*8,hash,cr);
00563     xxor(hash,8,cr,&block[j*8]);
00564     }
00565   return (0==memcmp(hash,sig,8));
00566 }
00567 
00568 // -- cNagra1 ------------------------------------------------------------------
00569 
00570 class cNagra1 : public cNagra, public cNagraDES {
00571 protected:
00572   virtual void CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q);
00573   bool DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2);
00574   bool DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2);
00575   };
00576 
00577 bool cNagra1::DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2)
00578 {
00579   cBN result;
00580   if(rsa.RSA(result,&in[2],len,pubExp,n2)<=0) {
00581     PRINTF(L_SYS_CRYPTO,"error decrypting ECM (round 1)");
00582     return false;;
00583     }
00584   cBN mod;
00585   BN_set_word(mod,in[0]>>4);
00586   BN_lshift(mod,mod,508);
00587   BN_add(result,result,mod);
00588   if(rsa.RSA(out,64,result,e1,n1,false)!=64) {
00589     PRINTF(L_SYS_CRYPTO,"error: result of ECM decryption is not 64 bytes");
00590     return false;
00591     }
00592   if(vkey && !SigCheck(out,&out[56],vkey,7)) {
00593     PRINTF(L_SYS_CRYPTO,"ECM decryption failed");
00594     return false;
00595     }
00596   return true;
00597 }
00598 
00599 bool cNagra1::DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2)
00600 {
00601   cBN result;
00602   if(rsa.RSA(result,&in[9],len,pubExp,n2)<=0) {
00603     PRINTF(L_SYS_CRYPTO,"error decrypting EMM (round 1)");
00604     return false;;
00605     }
00606   cBN mod;
00607   BN_set_word(mod,in[0]>>6);
00608   BN_lshift(mod,mod,510);
00609   BN_add(result,result,mod);
00610   if(rsa.RSA(out,64,result,e1,n1,false)!=64) {
00611     PRINTF(L_SYS_CRYPTO,"error: result of EMM decryption is not 64 bytes");
00612     return false;
00613     }
00614   if(!vkey || SigCheck(out,&in[1],vkey,8))
00615     return true;
00616     
00617   // We need to use signature exchange method (7blocks emm,1 block signature)
00618   PRINTF(L_SYS_CRYPTO,"warning: signature failed,trying signature exchange method");
00619   unsigned char buf[8];
00620   RotateBytes(buf,&in[1],sizeof(buf));
00621   cBN newdata, newsig;
00622   BN_bin2bn(buf,sizeof(buf),newdata);
00623   BN_copy(newsig,result);
00624   BN_mask_bits(newsig,64);
00625   BN_bn2bin(newsig,buf);
00626   RotateBytes(buf,sizeof(buf));
00627 
00628   BN_rshift(result,result,64); // delete the lower 64 bits,we saved it
00629   BN_lshift(result,result,64); // before as the new 64 bit signature
00630   BN_add(result,result,newdata);
00631   
00632   if(rsa.RSA(out,64,result,e1,n1)!=64) {
00633     PRINTF(L_SYS_CRYPTO,"error: result of EMM decryption is not 64 bytes");
00634     return false;
00635     }
00636   if(vkey && !SigCheck(out,buf,vkey,8)) {
00637     PRINTF(L_SYS_CRYPTO,"fatal: signature failed in signature exchange method");
00638     return false;
00639     }
00640   return true;
00641 }
00642 
00643 void cNagra1::CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q)
00644 {
00645   // Make des_key
00646   unsigned char des_data[32];
00647   unsigned char des_key[8], des_tmp[8];
00648   memcpy(des_data,key,8);
00649   RotateBytes(des_tmp,key,8);
00650   des_tmp[7]=0x00;
00651   Decrypt(des_data,des_tmp,des_key,true);
00652   RotateBytes(des_key,8);
00653   des_key[7]=0x00;
00654 
00655   // Calculate P
00656   for(int i=0; i<4; i++) {
00657     const int off=i*8;
00658     memcpy(&des_data[off],&key[4],8);
00659     des_data[off]^=i;
00660     Decrypt(&des_data[off],des_key,des_tmp,true);
00661     memcpy(&des_data[off],des_tmp,8);
00662     }
00663   BN_bin2bn(des_data,32,p);
00664   BN_add_word(p,(key[12]<<4)|((key[13]>>4)&0x0f));
00665   BN_set_bit(p,(BN_num_bytes(p)*8)-1);
00666 
00667   // Calculate Q
00668   for(int i=0; i<4; i++) {
00669     const int off=i*8;
00670     memcpy(&des_data[off],&key[4],8);
00671     des_data[off]^=(i+4);
00672     Decrypt(&des_data[off],des_key,des_tmp,true);
00673     memcpy(&des_data[off],des_tmp,8);
00674     }
00675   BN_bin2bn(des_data,32,q);
00676   BN_add_word(q,((key[13]&0x0f)<<8)|key[14]);
00677   BN_set_bit(q,(BN_num_bytes(q)*8)-1);
00678 }
00679 
00680 #ifndef TESTER
00681 
00682 // -- cSystemNagra -------------------------------------------------------------
00683 
00684 class cSystemNagra : public cSystem, public cNagra1 {
00685 private:
00686   unsigned char mecmTable[256];
00687   cEmu *emu;
00688   //
00689   void WriteTable(unsigned char *from, int off);
00690 public:
00691   cSystemNagra(void);
00692   virtual ~cSystemNagra();
00693   virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data);
00694   virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer);
00695   };
00696 
00697 cSystemNagra::cSystemNagra(void)
00698 :cSystem(SYSTEM_NAME,SYSTEM_PRI)
00699 {
00700   emu=0;
00701   memset(mecmTable,0,sizeof(mecmTable));
00702   hasLogger=true;
00703 }
00704 
00705 cSystemNagra::~cSystemNagra()
00706 {
00707   delete emu;
00708 }
00709 
00710 void cSystemNagra::WriteTable(unsigned char *from, int off)
00711 {
00712   off&=0xFF;
00713   if(off+16<256) memcpy(mecmTable+off,from,16);
00714   else {
00715     int l=256-off;
00716     memcpy(mecmTable+off,from,l);
00717     memcpy(mecmTable,from+l,16-l);
00718     }
00719 }
00720 
00721 bool cSystemNagra::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
00722 {
00723   int cmdLen=data[4];
00724   int id=(data[5]*256)+data[6];
00725   cTimeMs minTime;
00726   if(data[3]!=0x03) {
00727     PRINTF(L_SYS_ECM,"invalid ECM");
00728     return false;
00729     }
00730   data+=7;
00731   if(data[0]!=0x10) {
00732     PRINTF(L_SYS_ECM,"no ECM data available");
00733     return false;
00734     }
00735   const int ecmLen=data[1];
00736   const int verType=(data[2]>>3)&1;
00737   const int keynr=(data[2]>>4)&1;
00738   const int ecmParm=data[2]&7;
00739   bool decrypt;
00740   if(ecmParm==7) decrypt=false;
00741   else if(ecmParm==5) decrypt=true;
00742   else {
00743     PRINTF(L_SYS_ECM,"unknown ecmParm, ignoring ECM");
00744     return false;
00745     }
00746 
00747   cKeySnoop ks(this,'N',id,keynr);
00748   unsigned char sessionKey[8], verifyKey[8];
00749   bool hasVerifyKey=false;
00750   cPlainKey *pk;
00751   if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(0,0,verType)),sizeof(verifyKey)))) {
00752     pk->Get(verifyKey);
00753     hasVerifyKey=true;
00754     }
00755   else if(doLog) PRINTF(L_SYS_KEY,"missing %04X V TYP%d key (non-fatal)",id,verType);
00756   if(!(pk=keys.FindKey('N',id,keynr,sizeof(sessionKey)))) return false;
00757   pk->Get(sessionKey);
00758 
00759   const int desLen=(ecmLen-9) & ~7; // datalen - signature - ks byte
00760   unsigned char *decrypted=AUTOMEM(desLen);
00761   for(int i=(desLen/8)-1; decrypt && i>=0; i--) {
00762     const int off=i*8;
00763     Decrypt(data+11+off,sessionKey,decrypted+off);
00764     }
00765   if(decrypt && hasVerifyKey && !SigCheck(decrypted,data+3,verifyKey,desLen/8)) {
00766     PRINTF(L_SYS_ECM,"signature check failed in DES decrypt");
00767     return false;
00768     }
00769   int cwEvenMecmIndex=-1, cwOddMecmIndex=-1;
00770   switch(decrypted[0]) {
00771     case 0x10:  // Whole CW
00772       cwOddMecmIndex=decrypted[1];
00773       memcpy(cw+8,&decrypted[2],8);
00774       cwEvenMecmIndex=decrypted[10];
00775       memcpy(cw,&decrypted[11],8);
00776       break;
00777     case 0x11: // Odd CW
00778       cwOddMecmIndex=decrypted[1];
00779       memcpy(cw+8, &decrypted[2],8);
00780       break;
00781     case 0x12: // Even CW
00782       cwEvenMecmIndex=decrypted[1];
00783       memcpy(cw,&decrypted[2],8);
00784       break;
00785     default: PRINTF(L_SYS_ECM,"failed to get CW"); return false;
00786     }
00787 
00788   const unsigned char * const mecmData=data+(ecmLen+2);
00789   const int mecmRSALen=mecmData[1]-4;
00790   if((cmdLen-(ecmLen+2))>64 && (*mecmData==0x20 || *mecmData==0x39)) {
00791     if(mecmRSALen!=64) {
00792       if(mecmRSALen>64 && doLog)
00793         PRINTF(L_SYS_ECM,"ECM too big (len: %d)",mecmRSALen);
00794       return false;
00795       }
00796 
00797     const int mecmProvId=mecmData[2]*256+mecmData[3];
00798     const int keyType=(mecmData[4]>>3)&1;
00799     const int pkey=mecmData[4]&3;
00800 
00801     cBN e1, n1, n2;
00802     cPlainKey *pk;
00803     if(!(pk=keys.FindKey('N',mecmProvId,MBC3('E','1',KEYSET(0,pkey,keyType)),-1))) {
00804       if(doLog) PRINTF(L_SYS_KEY,"missing %04x E1 PK%d TYP%d key",mecmProvId,pkey,keyType);
00805       return false;
00806       }
00807     pk->Get(e1);
00808     if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','1',KEYSET(0,pkey,keyType)),-1)))  {
00809       if(doLog) PRINTF(L_SYS_KEY,"missing %04x N1 PK%d TYP%d key",mecmProvId,pkey,keyType);
00810       return false;
00811       }
00812     pk->Get(n1);
00813     if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','2',KEYSET(0,0,keyType)),-1)))  {
00814       if(doLog) PRINTF(L_SYS_KEY,"missing %04x N2 TYP%d key",mecmProvId,keyType);
00815       return false;
00816       }
00817     pk->Get(n2);
00818     hasVerifyKey=false;
00819     if((pk=keys.FindKey('N',mecmProvId,ADDC3('V',KEYSET(0,0,keyType)),sizeof(verifyKey))))  {
00820       pk->Get(verifyKey);
00821       hasVerifyKey=true;
00822       }
00823     else if(doLog) PRINTF(L_SYS_KEY,"missing %04x V TYP%d key (non-fatal)",mecmProvId,keyType);
00824     unsigned char *decrMecmData=AUTOMEM(mecmRSALen);
00825     if(!DecryptECM(&mecmData[4],decrMecmData,hasVerifyKey?verifyKey:0,mecmRSALen,e1,n1,n2))
00826       return false;
00827 
00828     if(*mecmData==0x39 || (*mecmData==0x20 && (mecmProvId&0xFE00)==0x4800)) {
00829       unsigned char xor_table[64];
00830       for(int i=sizeof(xor_table)-1; i>=0; i--) xor_table[i]=63-i;
00831       CreateRSAPair(&decrMecmData[24],xor_table,e1,n1);
00832 
00833       // new XOR table for MECM data
00834       cBNctx ctx;
00835       cBN x;
00836       BN_mod_exp(x,e1,pubExp,n1,ctx);
00837       int l=sizeof(xor_table)-BN_num_bytes(x);
00838       memset(xor_table,0,l);
00839       BN_bn2bin(x,xor_table+l);
00840       RotateBytes(xor_table,sizeof(xor_table));
00841 
00842       // And finally, new MECM table
00843       for(int i=39; i<mecmRSALen; i++) decrMecmData[i]^=xor_table[i-39];
00844       memcpy(&decrMecmData[3],&decrMecmData[39],mecmRSALen-39);
00845       }
00846 
00847     if(decrMecmData[0]==0x2F && decrMecmData[1]==mecmData[2] && decrMecmData[2]==mecmData[3])
00848       WriteTable(decrMecmData+4,decrMecmData[3]*2);
00849     }
00850 
00851   if(cwOddMecmIndex>=0 && cwOddMecmIndex<0x80) {
00852     const int d=cwOddMecmIndex*2;
00853     for(int i=0 ; i<8 ; i++) cw[i+8]^=mecmTable[(d+i)&0xFF]; // odd
00854     }
00855   if(cwEvenMecmIndex>=0 && cwEvenMecmIndex<0x80) {
00856     const int d=cwEvenMecmIndex*2;
00857     for(int i=0 ; i<8 ; i++) cw[i]^=mecmTable[(d+i)&0xFF]; // even
00858     }
00859   ks.OK(pk);
00860   int i=minEcmTime-minTime.Elapsed();
00861   if(i>0) cCondWait::SleepMs(i);
00862 
00863   return true;
00864 }
00865   
00866 void cSystemNagra::ProcessEMM(int pid, int caid, const unsigned char *buffer)
00867 {
00868   const int id=buffer[10]*256+buffer[11];
00869   static const unsigned char tester[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x4B };
00870   if(memcmp(&buffer[3],tester,sizeof(tester)) || SCT_LEN(buffer)<(12+9+64)) {
00871     PRINTF(L_SYS_EMM,"not a valid EMM structure");
00872     return;
00873     }
00874   const int pkey=(buffer[12]&3);
00875   cPlainKey *pk;
00876   cBN e1, n1, n2;
00877   if(!(pk=keys.FindKey('N',id,MBC3('E','1',KEYSET(0,pkey,0)),-1))) return;
00878   pk->Get(e1);
00879   if(!(pk=keys.FindKey('N',id,MBC3('N','1',KEYSET(0,pkey,0)),-1))) return;
00880   pk->Get(n1);
00881   unsigned char v[8];
00882   bool hasVerifyKey=false;
00883   if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(0,0,0)),sizeof(v)))) {
00884     pk->Get(v);
00885     hasVerifyKey=true;
00886     }
00887   int mode=(buffer[12]&8) ? 0:2;
00888   unsigned char emmdata[64];
00889   bool r;
00890   do {
00891     switch(mode) {
00892       case 0: // get the ROM10 specific management key
00893         if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(10,0,1)),-1))) return;
00894         pk->Get(n2);
00895         mode=1; break;
00896       case 1: // get the ROM11 specific management keys
00897         if(!(pk=keys.FindKey('N',id,MBC3('E','1',KEYSET(11,pkey,1)),-1))) return;
00898         pk->Get(e1);
00899         if(!(pk=keys.FindKey('N',id,MBC3('N','1',KEYSET(11,pkey,1)),-1))) return;
00900         pk->Get(n1);
00901         if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(11,0,1)),-1))) return;
00902         pk->Get(n2);
00903         hasVerifyKey=false;
00904         if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(11,0,1)),sizeof(v)))) {
00905           pk->Get(v);
00906           hasVerifyKey=true;
00907           }
00908         mode=-1; break;
00909       case 2: // get the universal management key
00910         if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(0,0,0)),-1))) return;
00911         pk->Get(n2);
00912         mode=-1; break;
00913       }
00914     r=DecryptEMM(&buffer[12],emmdata,hasVerifyKey?v:0,64,e1,n1,n2);
00915     } while(!r && mode>=0);
00916   if(r) {
00917     HEXDUMP(L_SYS_RAWEMM,emmdata,sizeof(emmdata),"Nagra1 RAWEMM");
00918     unsigned int i=0;
00919     bool gotKeys=false;
00920     unsigned char key0[8], key1[8];
00921     int keyId=(emmdata[i+1]<<8)+emmdata[i+2];
00922     switch(emmdata[i]) { // Check filter type
00923       case 0x00: // One card
00924         i+=7; break;
00925       case 0x01: case 0x02: case 0x03: case 0x04: // Group of cards
00926       case 0x05: case 0x06: case 0x07: case 0x08:
00927       case 0x09: case 0x0A: case 0x0B: case 0x0C:
00928       case 0x0D: case 0x0E: case 0x0F: case 0x10:
00929       case 0x11: case 0x12: case 0x13: case 0x14:
00930       case 0x15: case 0x16: case 0x17: case 0x18:
00931       case 0x19: case 0x1A: case 0x1B: case 0x1C:
00932       case 0x1D: case 0x1E: case 0x1F: case 0x20:
00933         i+=emmdata[i]+0x7; break;
00934       case 0x3e:
00935         i+=6; break;
00936       case 0x3d: // All cards with same system ID
00937       case 0x3f:
00938         i+=3; break;
00939       }
00940     int nrKeys=0;
00941     while(i<sizeof(emmdata)) {
00942       if((emmdata[i]&0xF0)==0xF0) { // Update with CPU code
00943         const int romNr=emmdata[i]&0x0F;
00944         if(!emu || !emu->Matches(romNr,id)) {
00945           delete emu; emu=0;
00946           PRINTF(L_SYS_EMM,"setting defaults for ROM %d",romNr);
00947           switch(romNr) {
00948             case 3:  emu=new cEmuRom3;  break;
00949             case 7:  emu=new cEmuRom7;  break;
00950             case 10: emu=new cEmuRom10; break;
00951             case 11: emu=new cEmuRom11; break;
00952             default: PRINTF(L_SYS_EMM,"unsupported ROM"); return;
00953             }
00954           if(!emu || !emu->Init(romNr,id)) {
00955             delete emu; emu=0;
00956             PRINTF(L_SYS_EMM,"initialization failed for ROM %d",romNr);
00957             return;
00958             }
00959           }
00960         unsigned char ki[2];
00961         if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) {
00962           keyId=(ki[0]<<8)+ki[1];
00963           PRINTF(L_SYS_EMM,"got keys for %04X (ROM %d)",keyId,romNr);
00964           }
00965         unsigned char select[3], pkset[3][15];
00966         select[0]=(keyId>>8)|0x01; // always high id for ECM RSA keys
00967         select[1]=keyId&0xFF;
00968         select[2]=0; // type 0
00969         if(emu->GetPkKeys(&select[0],&pkset[0][0])) {
00970           int pkKeyId=((select[0]<<8)+select[1]);
00971           PRINTF(L_SYS_EMM,"got PK keys for %04X (ROM %d)",pkKeyId,romNr);
00972           for(int i=0; i<3; i++) {
00973             CreateRSAPair(pkset[i],0,e1,n1);
00974             FoundKey();
00975             if(keys.NewKey('N',pkKeyId,ADDC3(MBC('N','1'),KEYSET(0,i,0)),n1,64)) NewKey();
00976             FoundKey();
00977             if(keys.NewKey('N',pkKeyId,ADDC3(MBC('E','1'),KEYSET(0,i,0)),e1,64)) NewKey();
00978             }
00979           }
00980         break; // don't process other nanos
00981         }
00982       else if(emmdata[i]==0x60) { // NULL nano
00983         i+=2;
00984         }
00985       else if(emmdata[i]==0x00) {
00986         i++;
00987         }
00988       else if(emmdata[i]==0x81) {
00989         i++;
00990         }
00991       else if(emmdata[i]==0x83) {
00992         keyId=(emmdata[i+1]<<8)+emmdata[i+2];
00993         i+=3;
00994         }
00995       else if(emmdata[i]==0x42) { // plain Key
00996         if(emmdata[i+1]==0x05) memcpy(key0,&emmdata[i+2],sizeof(key0));
00997         else                   memcpy(key1,&emmdata[i+2],sizeof(key1));
00998         i+=10;
00999         if(++nrKeys==2) {
01000           gotKeys=true;
01001           PRINTF(L_SYS_EMM,"got keys for %04X (plain)",keyId);
01002           break;
01003           }
01004         }
01005       else {
01006         PRINTF(L_SYS_EMM,"ignored nano %02x",emmdata[i]);
01007         break;
01008         }
01009       }
01010     if(gotKeys) {
01011       FoundKey();
01012       if(keys.NewKey('N',keyId,00,key0,8)) NewKey();
01013       FoundKey();
01014       if(keys.NewKey('N',keyId,01,key1,8)) NewKey();
01015       }
01016     }
01017 }
01018 
01019 // -- cSystemLinkNagra ---------------------------------------------------------
01020 
01021 class cSystemLinkNagra : public cSystemLink {
01022 public:
01023   cSystemLinkNagra(void);
01024   virtual bool CanHandle(unsigned short SysId);
01025   virtual cSystem *Create(void) { return new cSystemNagra; }
01026   };
01027 
01028 static cSystemLinkNagra staticInitN1;
01029 
01030 cSystemLinkNagra::cSystemLinkNagra(void)
01031 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
01032 {
01033   opts=new cOpts(SYSTEM_NAME,1);
01034   opts->Add(new cOptInt("MinEcmTime",trNOOP("Nagra: min. ECM processing time"),&minEcmTime,0,5000));
01035   Feature.NeedsKeyFile();
01036 }
01037 
01038 bool cSystemLinkNagra::CanHandle(unsigned short SysId)
01039 {
01040   return SysId==SYSTEM_NAGRA; // || SysId==SYSTEM_NAGRA_BEV;
01041 }
01042 
01043 #endif //TESTER
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines