|
SASC-NG
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.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