|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <string.h> 00022 #include <math.h> 00023 00024 #include "system.h" 00025 #include "opts.h" 00026 #include "log-core.h" 00027 00028 #include "nagra.h" 00029 #include "nagra2.h" 00030 00031 #define SYSTEM_NAME "Nagra2" 00032 #define SYSTEM_PRI -10 00033 00034 // -- cN2Timer ----------------------------------------------------------------- 00035 00036 cN2Timer::cN2Timer(void) 00037 { 00038 cycles=intrCycles=delayInterrupt=0; ctrl=0; val=0; divisor=0; invDivisor=0; latch=0xFF; 00039 timerBugged=false; 00040 } 00041 00042 bool cN2Timer::AddCycles(unsigned int count) 00043 { 00044 if(Running()) { 00045 cycles+=count; 00046 if(!delayInterrupt && InterruptSet() && cycles>=intrCycles) { 00047 delayInterrupt=intrCycles-cycles+3; 00048 if(delayInterrupt<0) delayInterrupt=count; else delayInterrupt+=count; 00049 intrCycles=0; 00050 if((ctrl&tmCONTINUOUS)) Update(); 00051 } 00052 } 00053 if(delayInterrupt) { 00054 delayInterrupt-=count; 00055 if(delayInterrupt<0) delayInterrupt=0; 00056 if(!delayInterrupt) { 00057 Update(); 00058 return true; 00059 } 00060 } 00061 return false; 00062 } 00063 00064 double cN2Timer::GetDivisor(void) 00065 { 00066 int prescalar=((ctrl&0x38)>>3)+1; 00067 double divisor=pow(4.0,prescalar); 00068 double multiplier; 00069 // multipliers for 0 and 2 aren't correct yet 00070 switch((ctrl&0xc0)>>6) { 00071 case 0: multiplier=10.3f; break; 00072 case 1: multiplier= 1.0f; break; 00073 case 2: multiplier=6.375f; break; 00074 default:multiplier=0; 00075 } 00076 return divisor*multiplier; 00077 } 00078 00079 void cN2Timer::Update(void) 00080 { 00081 int rlatch=latch; 00082 if(divisor) { 00083 if(timerBugged && cycles>=0x100*divisor) { 00084 timerBugged=false; 00085 cycles-=(unsigned int)(0x101*divisor); 00086 } 00087 if(timerBugged) rlatch=0x100; 00088 00089 int v=(int)(cycles*invDivisor); 00090 if(ctrl&tmCONTINUOUS) { 00091 val=rlatch-(v % (rlatch+1)); 00092 if(InterruptSet() && val==0) 00093 intrCycles = cycles + (unsigned int)((val?val:latch)*divisor); 00094 } 00095 else { 00096 // one-shot 00097 if(v>=rlatch) { 00098 val=0; 00099 if(Running() && ((cycles-2)*invDivisor)>=rlatch) Stop(); 00100 } 00101 else 00102 val=rlatch-v; 00103 } 00104 } 00105 else val=0; 00106 } 00107 00108 unsigned int cN2Timer::Cycles(void) 00109 { 00110 if(Running()) Update(); 00111 PRINTF(L_SYS_EMU,"n2timer %d: read %u %02x %02x = %02x",nr,cycles,ctrl&0xff,latch&0xff,val); 00112 return val; 00113 } 00114 00115 unsigned char cN2Timer::Ctrl(void) 00116 { 00117 if(Running()) Update(); 00118 return ctrl; 00119 } 00120 00121 void cN2Timer::Latch(unsigned char val) 00122 { 00123 if(!Running()) { 00124 latch=val; if(latch==0) latch=0x100; 00125 cycles=0; 00126 ctrl|=tmLATCHED; 00127 timerBugged=false; 00128 } 00129 } 00130 00131 void cN2Timer::Ctrl(unsigned char val) 00132 { 00133 if(Running()) { 00134 ctrl=(ctrl&~tmRUNNING) | (val&tmRUNNING); 00135 if(!Running()) { 00136 Stop(); 00137 --cycles; 00138 Update(); 00139 PRINTF(L_SYS_EMU,"n2timer %d: stopped cycles=%d (%02x) ctrl=%02x latch=%02x\n",nr,cycles,val,ctrl,latch&0xff); 00140 } 00141 } 00142 else { 00143 ctrl=(ctrl&~tmMASK) | (val&tmMASK); 00144 divisor=GetDivisor(); 00145 if(divisor) invDivisor=1.0/divisor; 00146 if(Running()) { 00147 if(!(ctrl&tmLATCHED) && divisor>0) { 00148 if(this->val==0) { 00149 timerBugged=true; 00150 cycles=(unsigned int)divisor; 00151 } 00152 else { 00153 cycles=(unsigned int)(((timerBugged?0x100:latch)-this->val+1) * divisor); 00154 } 00155 } 00156 if((ctrl&tmINTERRUPT)) { 00157 intrCycles=cycles+(unsigned int)((timerBugged?0x101:this->val?this->val:latch)*divisor); 00158 if(nr==2) PRINTF(L_SYS_EMU,"n2timer %d: set for %u cycles (%02x %02x)",nr,intrCycles-cycles,Latch(),ctrl&0xff); 00159 } 00160 ctrl&=~tmLATCHED; 00161 } 00162 } 00163 } 00164 00165 void cN2Timer::Stop(void) 00166 { 00167 ctrl&=~(tmRUNNING|tmLATCHED); 00168 if(delayInterrupt>=3) delayInterrupt=0; 00169 } 00170 00171 // -- cN2CRC ------------------------------------------------------------------- 00172 00173 #define CRC_POLY 0x8408 // ccitt poly 00174 00175 cN2CRC::cN2CRC(void) 00176 { 00177 cycles=0; CRCpos=0; CRCtime=0; CRCin=0; 00178 CRCvalue=0xffff; CRCit=CRCCALC_DELAY+1; ctrl=CRC_DISABLED; 00179 GenTable(); 00180 } 00181 00182 void cN2CRC::AddCycles(unsigned int num) 00183 { 00184 cycles+=num; 00185 } 00186 00187 void cN2CRC::GenTable(void) 00188 { 00189 for(int i=0; i<256; i++) { 00190 unsigned short c=i; 00191 for(int j=0; j<8; j++) c=(c>>1)^((c&1)?CRC_POLY:0); 00192 table[i]=c; 00193 } 00194 } 00195 00196 void cN2CRC::Update(void) 00197 { 00198 if(!(ctrl&CRC_DISABLED) && CRCit<=CRCCALC_DELAY) { 00199 unsigned int it=CRCit; 00200 CRCit+=cycles-CRCtime; 00201 if(CRCit>CRCCALC_DELAY) // > instead of >= because of CRC_BUSY lockout 00202 CRCit=CRCCALC_DELAY+1; 00203 if(it==0 && CRCit>=CRCCALC_DELAY) 00204 CRCvalue=(CRCvalue>>8)^table[(CRCvalue^CRCin)&0xff]; 00205 else 00206 for(; it<CRCit && it<CRCCALC_DELAY; it++) 00207 CRCvalue=(CRCvalue>>1) ^ (((CRCvalue^(CRCin>>it))&1) ? CRC_POLY : 0); 00208 CRCtime=cycles; 00209 } 00210 } 00211 00212 unsigned char cN2CRC::Ctrl(void) 00213 { 00214 Update(); 00215 unsigned char r=ctrl; 00216 if(CRCit<CRCCALC_DELAY) r|=CRC_BUSY; else r&=~CRC_BUSY; 00217 return r|0x80; 00218 } 00219 00220 void cN2CRC::Ctrl(unsigned char c) 00221 { 00222 if(ctrl&CRC_DISABLED) { 00223 if(!(c&CRC_DISABLED)) { 00224 CRCvalue=0xffff; CRCpos=0; CRCtime=cycles; 00225 if(CRCit<=CRCCALC_DELAY) { CRCtime++; CRCit++; } 00226 } 00227 } 00228 else if(c&CRC_DISABLED) Update(); 00229 ctrl=c; 00230 } 00231 00232 unsigned char cN2CRC::Data(void) 00233 { 00234 Update(); 00235 return (CRCvalue^0xffff)>>((CRCpos++&1)<<3); 00236 } 00237 00238 void cN2CRC::Data(unsigned char d) 00239 { 00240 Update(); 00241 if(CRCit>CRCCALC_DELAY && !(ctrl&CRC_DISABLED)) { 00242 CRCin=d; 00243 CRCit=0; CRCtime=cycles; 00244 } 00245 } 00246 00247 // -- cMapMemHW ---------------------------------------------------------------- 00248 00249 cMapMemHW::cMapMemHW(void) 00250 :cMapMem(HW_OFFSET,HW_REGS) 00251 { 00252 for(int i=0; i<MAX_TIMERS; i++) timer[i].SetNumber(HW_NUM(i)); 00253 PRINTF(L_SYS_EMU,"mapmemhw: new HW map off=%04x size=%04x",offset,size); 00254 } 00255 00256 int cMapMemHW::AddCycles(unsigned int num) 00257 { 00258 crc.AddCycles(num); 00259 int mask=0; 00260 for(int i=0; i<MAX_TIMERS; i++) 00261 if(timer[i].AddCycles(num)) mask|=1<<timer[i].Number(); 00262 return mask; 00263 } 00264 00265 unsigned char cMapMemHW::Get(unsigned short ea) 00266 { 00267 if(ea<offset || ea>=offset+size) return 0; 00268 ea-=offset; 00269 switch(ea) { 00270 case HW_SECURITY: 00271 return (mem[ea]&0x70)|0x0F; 00272 case HW_TIMER0_CONTROL: 00273 case HW_TIMER1_CONTROL: 00274 case HW_TIMER2_CONTROL: 00275 return timer[TIMER_NUM(ea)].Ctrl(); 00276 case HW_TIMER0_DATA: 00277 case HW_TIMER1_DATA: 00278 case HW_TIMER2_DATA: 00279 return timer[TIMER_NUM(ea)].Cycles(); 00280 case HW_TIMER0_LATCH: 00281 case HW_TIMER1_LATCH: 00282 case HW_TIMER2_LATCH: 00283 return timer[TIMER_NUM(ea)].Latch(); 00284 case HW_CRC_CONTROL: 00285 return crc.Ctrl(); 00286 case HW_CRC_DATA: 00287 return crc.Data(); 00288 default: 00289 return mem[ea]; 00290 } 00291 } 00292 00293 void cMapMemHW::Set(unsigned short ea, unsigned char val) 00294 { 00295 if(ea<offset || ea>=offset+size) return; 00296 ea-=offset; 00297 switch(ea) { 00298 case HW_TIMER0_CONTROL: 00299 case HW_TIMER1_CONTROL: 00300 case HW_TIMER2_CONTROL: 00301 timer[TIMER_NUM(ea)].Ctrl(val); 00302 break; 00303 case HW_TIMER0_LATCH: 00304 case HW_TIMER1_LATCH: 00305 case HW_TIMER2_LATCH: 00306 timer[TIMER_NUM(ea)].Latch(val); 00307 break; 00308 case HW_CRC_CONTROL: 00309 crc.Ctrl(val); 00310 break; 00311 case HW_CRC_DATA: 00312 crc.Data(val); 00313 break; 00314 default: 00315 mem[ea]=val; 00316 break; 00317 } 00318 } 00319 00320 // -- cN2Emu ------------------------------------------------------------------- 00321 00322 cN2Emu::cN2Emu(void) 00323 { 00324 initDone=false; 00325 } 00326 00327 bool cN2Emu::Init(int id, int romv) 00328 { 00329 if(!initDone) { 00330 ResetMapper(); 00331 char buff[256]; 00332 snprintf(buff,sizeof(buff),"ROM%d.bin",romv); 00333 // UROM 0x00:0x4000-0x7fff 00334 if(!AddMapper(new cMapRom(0x4000,buff,0x00000),0x4000,0x4000,0x00)) return false; 00335 // ROM00 0x00:0x8000-0xffff 00336 if(!AddMapper(new cMapRom(0x8000,buff,0x04000),0x8000,0x8000,0x00)) return false; 00337 // ROM01 0x01:0x8000-0xffff 00338 if(!AddMapper(new cMapRom(0x8000,buff,0x0C000),0x8000,0x8000,0x01)) return false; 00339 // ROM02 0x02:0x8000-0xbfff 00340 if(!AddMapper(new cMapRom(0x8000,buff,0x14000),0x8000,romv>=110?0x8000:0x4000,0x02)) return false; 00341 00342 snprintf(buff,sizeof(buff),"EEP%02X_%d.bin",((id>>8)&0xFF)|0x01,romv); 00343 // Eeprom00 0x00:0x3000-0x37ff OTP 0x80 00344 //XXX if(!AddMapper(new cMapRom(0x3000,buff,0x0000),0x3000,0x0800,0x00)) return false; 00345 if(!AddMapper(new cMapEeprom(0x3000,buff,128,0x0000),0x3000,0x0800,0x00)) return false; 00346 // Eeprom80 0x80:0x8000-0xbfff 00347 //XXX if(!AddMapper(new cMapRom(0x8000,buff,0x0800),0x8000,0x4000,0x80)) return false; 00348 if(!AddMapper(new cMapEeprom(0x8000,buff, 0,0x0800),0x8000,0x4000,0x80)) return false; 00349 initDone=RomInit(); 00350 } 00351 return initDone; 00352 } 00353 00354 // -- cMapReg ------------------------------------------------------------------ 00355 00356 cMapReg::cMapReg(int &_pos, int *_defwordsize, int _maxwordsize) 00357 :pos(_pos) 00358 { 00359 SetDefWordSize(_defwordsize); 00360 SetMaxWordSize(_maxwordsize); 00361 wordsize=DEF_WORDSIZE; 00362 } 00363 00364 BIGNUM *cMapReg::Value(int wsize, bool mask) 00365 { 00366 wsize=OpWordSize(wsize); 00367 if(wordsize!=wsize) { 00368 Commit(); 00369 Reload(); 00370 } 00371 else if(mask) 00372 BN_mask_bits(reg,wsize*64); 00373 return reg; 00374 } 00375 00376 void cMapReg::ClearReg(int wsize) 00377 { 00378 BN_rshift(reg,reg,wsize*64); 00379 BN_lshift(reg,reg,wsize*64); 00380 } 00381 00382 void cMapReg::ClearFullReg(int wsize) 00383 { 00384 BN_rshift(fullreg,fullreg,wsize*64); 00385 BN_lshift(fullreg,fullreg,wsize*64); 00386 } 00387 00388 void cMapReg::PrepTmp(BIGNUM *val, int wsize) 00389 { 00390 if(val->neg) { 00391 BN_clear(tmp); 00392 BN_set_bit(tmp,wsize*64); 00393 BN_add(tmp,tmp,val); 00394 } 00395 else 00396 BN_copy(tmp,val); 00397 BN_mask_bits(tmp,wsize*64); 00398 } 00399 00400 void cMapReg::Commit(int wsize, int resync) 00401 { 00402 if(resync<0 && wsize<0) resync=1; 00403 wsize=OpWordSize(wsize>=0?wsize:wordsize); 00404 ClearFullReg(wsize); 00405 PrepTmp(reg,wsize); 00406 BN_add(fullreg,fullreg,tmp); 00407 if(resync) { 00408 if(wordsize==wsize) BN_mask_bits(reg,wsize*64); 00409 else wordsize=wsize; 00410 } 00411 } 00412 00413 void cMapReg::Reload(int wsize) 00414 { 00415 wsize=OpWordSize(wsize>=0?wsize:wordsize); 00416 wordsize=wsize; 00417 BN_copy(reg,fullreg); 00418 BN_mask_bits(reg,64*wsize); 00419 } 00420 00421 void cMapReg::GetLE(const unsigned char *in, int n) 00422 { 00423 int wsize=OpWordSize(n<=0?n:(n+7)/8); 00424 if(wordsize>wsize) Commit(); 00425 reg.GetLE(in,wsize*8); 00426 Commit(wsize); 00427 pos=0; 00428 } 00429 00430 void cMapReg::PutLE(unsigned char *out, int n) 00431 { 00432 int wsize=OpWordSize(n<=0?n:(n+7)/8); 00433 Commit(); 00434 fullreg.PutLE(out,wsize*8); 00435 if(pos&7) { 00436 int s=pos/8*8; 00437 for(int i=0; i<(pos&7); i++) { 00438 unsigned char c=out[s]; 00439 memmove(out+s,out+s+1,7); 00440 out[s+7]=c; 00441 } 00442 } 00443 } 00444 00445 void cMapReg::Set(BIGNUM *val, int wsize) 00446 { 00447 wsize=OpWordSize(wsize); 00448 if(wordsize!=wsize) Commit(); 00449 ClearReg(wsize); 00450 PrepTmp(val,wsize); 00451 if(wordsize!=wsize) { 00452 ClearFullReg(wsize); 00453 BN_add(fullreg,fullreg,tmp); 00454 } 00455 BN_add(reg,reg,tmp); 00456 } 00457 00458 void cMapReg::Clear(int wsize) 00459 { 00460 wsize=OpWordSize(wsize); 00461 if(wordsize!=wsize) { 00462 Commit(); 00463 ClearFullReg(wsize); 00464 } 00465 ClearReg(wsize); 00466 } 00467 00468 // -- cMapMath ----------------------------------------------------------------- 00469 00470 cMapMath::cMapMath(void) 00471 :A(regpos,&wordsize),B(regpos,&wordsize),C(regpos,&wordsize),D(regpos,&wordsize),J(regpos,0,1),I(regpos,&wordsize) 00472 { 00473 wordsize=DEF_WORDSIZE; words=-1; 00474 regpos=0; 00475 } 00476 00477 bool cMapMath::ModAdd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *d) 00478 { 00479 BN_add(r,a,b); 00480 bool ret=false; 00481 if(BN_cmp(r,d)>=0) { 00482 BN_sub(r,r,d); 00483 ret=true; 00484 } 00485 BN_mask_bits(r,wordsize<<6); 00486 return ret; 00487 } 00488 00489 bool cMapMath::ModSub(BIGNUM *r, BIGNUM *d, BIGNUM *b) 00490 { 00491 cBN p; 00492 bool ret=BN_cmp(d,b)<0; 00493 BN_set_bit(p,wordsize<<6); 00494 BN_mod_sub(r,d,b,p,ctx); 00495 BN_mask_bits(r,wordsize<<6); 00496 return ret; 00497 } 00498 00499 void cMapMath::MakeJ0(BIGNUM *j, BIGNUM *d, BIGNUM *c, int bits) 00500 { 00501 #if OPENSSL_VERSION_NUMBER < 0x0090700fL 00502 #error BN_mod_inverse is probably buggy in your openssl version 00503 #endif 00504 BN_zero(x); 00505 BN_sub(j,x,d); j->neg=1; 00506 BN_set_bit(j,0); 00507 BN_set_bit(x,bits); 00508 BN_mod_inverse(j,j,x,ctx); 00509 if(c) { 00510 BN_copy(c,d); 00511 BN_mask_bits(c,bits); 00512 BN_mul(c,j,c,ctx); 00513 BN_rshift(c,c,bits); 00514 BN_mask_bits(c,bits); 00515 } 00516 } 00517 00518 void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b) 00519 { 00520 MonMul(o,a,b,C,D,J,0); 00521 } 00522 00523 void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b, int w) 00524 { 00525 MonMul(o,a,b,C,D,J,w); 00526 } 00527 00528 void cMapMath::MonMul(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j, int w) 00529 { 00530 MonMul0(o,a,b,c,d,j,w); 00531 MonFin(o,d); 00532 } 00533 00534 void cMapMath::MonMul0(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j, int w) 00535 { 00536 if(!w) w=wordsize; 00537 MonStart(w); 00538 int i=0; 00539 while(words>0) { 00540 BN_rshift(x,a,(i++)<<6); 00541 MonLoop(o,x,b,c,d,j); 00542 } 00543 } 00544 00545 void cMapMath::MonStart(int w) 00546 { 00547 if(words<=0) { 00548 words=w; 00549 BN_zero(s); 00550 } 00551 } 00552 00553 // modifies a, but pointing a to x is allowed !! 00554 void cMapMath::MonLoop(BIGNUM *o, BIGNUM *a, BIGNUM *b, BIGNUM *c, BIGNUM *d, BIGNUM *j) 00555 { 00556 words--; 00557 BN_mask_bits(a,64); 00558 BN_mul(a,a,b,ctx); 00559 BN_add(s,s,a); 00560 00561 BN_copy(x,s); 00562 BN_mask_bits(x,64); 00563 BN_mul(x,x,j,ctx); 00564 if(!words) { 00565 BN_lshift(y,x,64); 00566 BN_add(y,y,x); 00567 // Low 00568 BN_rshift(c,y,2); 00569 BN_add(c,c,s); 00570 BN_rshift(c,c,52); 00571 BN_mask_bits(c,12); 00572 } 00573 00574 BN_mask_bits(x,64); 00575 BN_mul(x,x,d,ctx); 00576 BN_add(s,s,x); 00577 if(!words) { 00578 // High 00579 BN_lshift(y,s,12); 00580 BN_add(c,c,y); 00581 BN_mask_bits(c,wordsize<<6); 00582 } 00583 00584 BN_rshift(s,s,64); 00585 if(words) MonFin(s,d); 00586 if(!words) BN_copy(o,s); 00587 } 00588 00589 void cMapMath::MonFin(BIGNUM *s, BIGNUM *d) 00590 { 00591 if(BN_cmp(s,d)>=0) 00592 BN_sub(s,s,d); 00593 } 00594 00595 // -- cMapCore ----------------------------------------------------------------- 00596 00597 cMapCore::cMapCore(void) 00598 { 00599 last=1; mapid=0; 00600 regs[0]=&J; regs[1]=&A; regs[2]=&B; regs[3]=&C; regs[4]=&D; 00601 interruptible=false; 00602 } 00603 00604 void cMapCore::IMakeJ(void) 00605 { 00606 AddMapCycles(19); 00607 WS_START(1); 00608 AddMapCycles(102); 00609 MakeJ0(J,D,C); 00610 AddMapCycles(303); 00611 BN_zero(C); 00612 AddMapCycles(34); 00613 WS_END(); 00614 AddMapCycles(10); 00615 } 00616 00617 void cMapCore::IMonInit0(int bits) 00618 { 00619 AddMapCycles(114+(wordsize*8+3)/5*5); 00620 D.SetPos(2); 00621 AddMapCycles(18); 00622 if(BN_num_bits(D)>1) 00623 for(int i=3; i<=8; i++) { 00624 D.SetPos(i); 00625 AddMapCycles(9); 00626 } 00627 D.SetPos(0); 00628 if(!BN_is_zero(D)) { 00629 AddMapCycles(54); 00630 BN_zero(I); 00631 BN_set_bit(I,bits ? bits : 68*wordsize); 00632 BN_zero(B); 00633 AddMapCycles(157+(wordsize*8+3)/5*5+72*(wordsize-1)); 00634 BN_set_bit(B,64*(wordsize-1)); 00635 B.SetPos(8*(wordsize-1)+1); 00636 AddMapCycles(17); 00637 for(int i=8*(wordsize-1)+2; i<=8*wordsize; i++) { 00638 B.SetPos(i); 00639 AddMapCycles(9); 00640 } 00641 B.SetPos(0); 00642 AddMapCycles(68); 00643 BN_mod(B,I,D,ctx); 00644 AddMapCycles(639); 00645 } 00646 AddMapCycles(52); 00647 for(int i=0; i<4; i++) { 00648 MonMul0(B,B,B,C,D,J,0); 00649 AddMapCycles(96+6*(i>0)); 00650 MonFin(B,D); 00651 } 00652 } 00653 00654 void cMapCore::IMonInit(int bits) 00655 { 00656 IMakeJ(); 00657 IMonInit0(bits); 00658 } 00659 00660 void cMapCore::MonInit(int bits) 00661 { 00662 // Calculate J0 & H montgomery elements in J and B 00663 MakeJ0(J,D,C); 00664 if(!BN_is_zero(D)) { 00665 BN_zero(I); 00666 BN_set_bit(I,bits ? bits : 68*wordsize); 00667 BN_mod(B,I,D,ctx); 00668 } 00669 for(int i=0; i<4; i++) MonMul(B,B,B); 00670 } 00671 00672 void cMapCore::MonExp(BIGNUM *scalar) 00673 { 00674 if(BN_is_zero(D)) { BN_one(A); return; } 00675 BN_copy(A,B); 00676 for(int i=BN_num_bits(scalar)-2; i>-1; i--) { 00677 MonMul(B,B,B); 00678 if(BN_is_bit_set(scalar,i)) MonMul(B,A,B); 00679 } 00680 BN_one(A); 00681 MonMul(B,A,B); 00682 } 00683 00684 void cMapCore::MonExpNeg(void) 00685 { 00686 if(BN_is_zero(D) || BN_is_word(D,2)) { 00687 BN_one(A); 00688 if(!BN_is_zero(D)) BN_zero(B); 00689 return; 00690 } 00691 int bits=0; 00692 for(int i=BN_num_bits(D)-1; i>=0; i--) if(BN_is_bit_set(D,i)) bits++; 00693 BN_copy(e,D); 00694 BN_mask_bits(e,8); // check LSB 00695 unsigned int n=BN_get_word(e); 00696 BN_copy(e,D); 00697 if(n) BN_sub_word(e,0x02); // N -2 00698 else BN_add_word(e,0xFE); // N + 254 ('carryless' -2) 00699 BN_copy(A,B); 00700 for(int i=BN_num_bits(e)-2+(bits==1 && BN_num_bits(D)<=8); i>-1; i--) { 00701 MonMul(B,B,B); 00702 if(BN_is_bit_set(e,i)) MonMul(B,A,B); 00703 } 00704 if(bits==2 && BN_is_bit_set(D,0)) { 00705 MonMul(B,B,B); 00706 MonMul(B,A,B); 00707 } 00708 BN_one(A); 00709 MonMul(B,A,B); 00710 } 00711 00712 void cMapCore::DoubleP(int temp) 00713 { 00714 ModAdd(B,Py,Py,D); 00715 MonMul(sC0,Pz,B); 00716 MonMul(B,B,B); 00717 MonMul(B,Px,B); 00718 ModSub(sA0,D,B); 00719 MonMul(B,Px,Px); 00720 BN_copy(A,B); 00721 ModAdd(B,B,B,D); 00722 ModAdd(A,B,A,D); 00723 MonMul(B,Pz,Pz); 00724 MonMul(B,B,B); 00725 MonMul(B,s160,B); 00726 ModAdd(B,B,A,D); 00727 BN_copy(A,B); 00728 MonMul(B,B,B); 00729 BN_copy(C,sA0); 00730 ModAdd(B,C,B,D); 00731 ModAdd(B,C,B,D); 00732 if(temp==0) BN_copy(Px,B); else BN_copy(sA0,B); 00733 ModAdd(B,C,B,D); 00734 MonMul(B,A,B); 00735 BN_copy(A,B); 00736 MonMul(B,Py,Py); 00737 ModAdd(B,B,B,D); 00738 MonMul(B,B,B); 00739 ModAdd(B,B,B,D); 00740 ModAdd(B,B,A,D); 00741 ModSub(B,D,B); 00742 if(temp==0) { BN_copy(Py,B); BN_copy(Pz,sC0); } 00743 else BN_copy(sA0,sC0); 00744 } 00745 00746 void cMapCore::AddP(int temp) 00747 { 00748 MonMul(B,Pz,Pz); 00749 MonMul(sA0,Pz,B); 00750 MonMul(B,Qx,B); 00751 BN_copy(A,B); 00752 ModSub(B,D,B); 00753 ModAdd(B,Px,B,D); 00754 BN_copy(sC0,B); 00755 MonMul(I,Pz,B); 00756 if(temp==0) BN_copy(Pz,I); else BN_copy(sA0,I); 00757 MonMul(B,B,B); 00758 BN_copy(sE0,B); 00759 ModAdd(A,Px,A,D); 00760 MonMul(A,A,B); 00761 BN_copy(s100,A); 00762 MonMul(B,sA0,Qy); 00763 BN_copy(sA0,B); 00764 ModSub(B,D,B); 00765 ModAdd(B,Py,B,D); 00766 BN_copy(s120,B); 00767 MonMul(B,B,B); 00768 BN_swap(A,B); 00769 ModSub(B,D,B); 00770 ModAdd(B,A,B,D); 00771 if(temp==0) BN_copy(Px,B); else BN_copy(sA0,B); 00772 ModAdd(B,B,B,D); 00773 ModSub(B,D,B); 00774 ModAdd(B,B,s100,D); 00775 ModAdd(A,sA0,Py,D); 00776 MonMul(sA0,s120,B); 00777 MonMul(B,sE0,sC0); 00778 MonMul(B,A,B); 00779 ModSub(B,D,B); 00780 ModAdd(B,B,sA0,D); 00781 MonMul(B,s140,B); 00782 if(temp==0) BN_copy(Py,B); else BN_copy(sA0,B); 00783 } 00784 00785 void cMapCore::ToProjective(int set, BIGNUM *x, BIGNUM *y) 00786 { 00787 if(set==0) { 00788 BN_set_word(I,1); MonMul(Pz,I,B); 00789 BN_copy(Qz,Pz); 00790 MonMul(Px,x,B); 00791 MonMul(Py,y,B); 00792 } 00793 else { 00794 MonMul(Qx,x,B); 00795 MonMul(Qy,y,B); 00796 } 00797 } 00798 00799 void cMapCore::ToAffine(void) 00800 { 00801 BN_set_word(I,1); 00802 MonMul(B,Pz,Pz); MonMul(B,Pz,B); MonMul(B,I,B); 00803 MonExpNeg(); 00804 BN_set_word(I,1); 00805 MonMul(A,Py,B); MonMul(Py,I,A); 00806 MonMul(B,Pz,B); MonMul(B,Px,B); MonMul(Px,I,B); 00807 } 00808 00809 void cMapCore::CurveInit(BIGNUM *a) 00810 { 00811 BN_zero(Px); BN_zero(Py); BN_zero(Pz); BN_zero(Qx); BN_zero(Qy); BN_zero(Qz); 00812 BN_zero(sA0); BN_zero(sC0); BN_zero(sE0); BN_zero(s100); 00813 BN_zero(s120); BN_zero(s140); BN_zero(s160); 00814 MonInit(); 00815 BN_copy(A,B); 00816 BN_copy(I,D); 00817 BN_add_word(I,1); 00818 BN_mask_bits(I,wordsize<<6); 00819 BN_rshift(I,I,1); 00820 MonMul(s140,I,B); 00821 MonMul(s160,B,a); 00822 } 00823 00824 void cMapCore::PostDecryptSetup(bool ecm) 00825 { 00826 if(ecm) wordsize=0x8; 00827 else wordsize=0xC; 00828 } 00829 00830 int cMapCore::GetOpSize(int l) 00831 { 00832 return l!=0 ? l : wordsize; 00833 } 00834 00835 void cMapCore::DoMap(int f, unsigned char *data, int l) 00836 { 00837 PRINTF(L_SYS_MAP,"%04x: calling function %02X",mapid,f); 00838 cycles=0; 00839 unsigned int startcycles=CpuCycles(); 00840 interrupted=false; interruptible=true; 00841 try { 00842 if(!Map(f,data,l) && !MapGeneric(f,data,l)) 00843 PRINTF(L_SYS_MAP,"%04x: unsupported map call %02x",mapid,f); 00844 if(cycles) { 00845 unsigned int elapsed=CpuCycles()-startcycles; 00846 if(cycles>elapsed) AddMapCycles(cycles-elapsed); 00847 } 00848 } 00849 catch(int) { 00850 interrupted=true; 00851 PRINTF(L_SYS_MAP,"%04x: call %02x interrupted (%d cycles)",mapid,f,CpuCycles()-startcycles); 00852 } 00853 interruptible=false; 00854 cycles=CpuCycles()-startcycles; 00855 } 00856 00857 bool cMapCore::MapGeneric(int f, unsigned char *data, int l) 00858 { 00859 const int l1=GetOpSize(l); 00860 const int dl=l1<<3; 00861 switch(f) { 00862 case SETSIZE: 00863 cycles=(l>17 ? 459 : (l ? 475 : 454))-6; 00864 if(l>=1 && l<=17) wordsize=l; 00865 break; 00866 00867 case IMPORT_J: 00868 cycles=890-6; 00869 last=0; 00870 regs[0]->GetLE(data,8); 00871 break; 00872 case IMPORT_A: 00873 case IMPORT_B: 00874 case IMPORT_C: 00875 case IMPORT_D: 00876 if(l>17) { l=17; cycles+=5; } 00877 else if(l<=0) { l=wordsize; cycles+=4; } 00878 cycles+=771+160*l-6; 00879 last=f-IMPORT_J; 00880 regs[last]->GetLE(data,l<<3); 00881 break; 00882 case IMPORT_LAST: 00883 if(l>16) { l=1; cycles+=5; } 00884 else if(l<=0) l=1; 00885 cycles+=656+160*l-6; 00886 regs[last]->GetLE(data,(last==0?1:l)<<3); 00887 break; 00888 00889 case EXPORT_J: 00890 cycles=897-6; 00891 last=0; 00892 regs[0]->PutLE(data,8); 00893 break; 00894 case EXPORT_A: 00895 case EXPORT_B: 00896 case EXPORT_C: 00897 case EXPORT_D: 00898 if(l>17) { l=17; cycles+=5; } 00899 else if(l<=0) { l=wordsize; cycles+=4; } 00900 cycles+=778+160*l-6; 00901 last=f-EXPORT_J; 00902 regs[last]->PutLE(data,l<<3); 00903 break; 00904 case EXPORT_LAST: 00905 if(l>16) { l=1; cycles+=5; } 00906 else if(l<=0) l=1; 00907 cycles+=668+160*l-6; 00908 regs[last]->PutLE(data,(last==0?1:l)<<3); 00909 break; 00910 00911 case SWAP_A: 00912 case SWAP_B: 00913 case SWAP_C: 00914 case SWAP_D: 00915 cycles=776+248*l1-6; 00916 last=f-SWAP_A+1; 00917 e.GetLE(data,dl); 00918 regs[last]->PutLE(data,dl); 00919 regs[last]->Set(e,l1); 00920 break; 00921 00922 case CLEAR_A: 00923 case CLEAR_B: 00924 case CLEAR_C: 00925 case CLEAR_D: 00926 cycles=462+(8*l1+3)/5*5-6; 00927 last=f-CLEAR_A+1; 00928 regs[last]->Clear(l1); 00929 break; 00930 00931 case COPY_A_B: 00932 last=2; B.Set(A,l1); cycles=462+(8*l1+3)/5*5-6; break; 00933 case COPY_B_A: 00934 last=1; A.Set(B,l1); cycles=462+(8*l1+3)/5*5-6; break; 00935 case COPY_A_C: 00936 last=3; C.Set(A,l1); cycles=462+(8*l1+3)/5*5-6; break; 00937 case COPY_C_A: 00938 last=1; A.Set(C,l1); cycles=462+(8*l1+3)/5*5-6; break; 00939 case COPY_C_D: 00940 last=4; D.Set(C,l1); cycles=462+(8*l1+3)/5*5-6; break; 00941 case COPY_D_C: 00942 last=3; C.Set(D,l1); cycles=462+(8*l1+3)/5*5-6; break; 00943 00944 case 0x39: 00945 case 0x3a: 00946 AddMapCycles(f==0x39?433:192); 00947 IMonInit(); 00948 if(f==0x39) { 00949 scalar.GetLE(data,wordsize<<3); 00950 MonMul(B,scalar,B); 00951 } 00952 else 00953 MonMul(B,A,B); 00954 AddMapCycles(137); 00955 MonMul(B,A,B); 00956 break; 00957 case 0x43: // init SHA1 00958 case 0x44: // add 64 bytes to SHA1 buffer 00959 if(f==0x43) { 00960 l=0; 00961 SHA1_Init(&sctx); 00962 cycles=885; 00963 } 00964 else { 00965 l=64; 00966 RotateBytes(data,l); 00967 sctx.h4=UINT32_LE(data+l+0x00); 00968 sctx.h3=UINT32_LE(data+l+0x04); 00969 sctx.h2=UINT32_LE(data+l+0x08); 00970 sctx.h1=UINT32_LE(data+l+0x0c); 00971 sctx.h0=UINT32_LE(data+l+0x10); 00972 sctx.Nl=UINT32_LE(data+l+0x14); 00973 sctx.Nh=UINT32_LE(data+l+0x18); 00974 sctx.num=0; 00975 SHA1_Update(&sctx,data,l); 00976 memset(data,0,l); 00977 cycles=65309; 00978 } 00979 if(data) { 00980 BYTE4_LE(data+l+0x00,sctx.h4); 00981 BYTE4_LE(data+l+0x04,sctx.h3); 00982 BYTE4_LE(data+l+0x08,sctx.h2); 00983 BYTE4_LE(data+l+0x0c,sctx.h1); 00984 BYTE4_LE(data+l+0x10,sctx.h0); 00985 BYTE4_LE(data+l+0x14,sctx.Nl); 00986 BYTE4_LE(data+l+0x18,sctx.Nh); 00987 } 00988 break; 00989 case 0x45: // add l bytes to SHA1 buffer and finalize SHA result 00990 if(l<=0 || l>64) 00991 cycles=465+5*(l>64); 00992 else { 00993 sctx.h4=UINT32_LE(data+0x40); 00994 sctx.h3=UINT32_LE(data+0x44); 00995 sctx.h2=UINT32_LE(data+0x48); 00996 sctx.h1=UINT32_LE(data+0x4c); 00997 sctx.h0=UINT32_LE(data+0x50); 00998 sctx.Nl=UINT32_LE(data+0x54); 00999 sctx.Nh=UINT32_LE(data+0x58); 01000 sctx.Nl&=~0xff; 01001 sctx.num=0; 01002 if(l>1) RotateBytes(data,l); 01003 SHA1_Update(&sctx,data,l); 01004 SHA1_Final(data+0x40,&sctx); 01005 RotateBytes(data+0x40,20); 01006 BYTE4_LE(data+0x54,sctx.Nl); 01007 BYTE4_LE(data+0x58,sctx.Nh); 01008 memset(data,0,64); 01009 cycles=65519+(64-l)*12+(l>=56)*64681-16*(l==64); 01010 } 01011 break; 01012 default: 01013 return false; 01014 } 01015 return true; 01016 } 01017 01018 // -- cN2Prov ------------------------------------------------------------------ 01019 01020 cN2Prov::cN2Prov(int Id, int Flags) 01021 { 01022 keyValid=false; id=Id|0x100; flags=Flags; seedSize=5; 01023 } 01024 01025 void cN2Prov::PrintCaps(int c) 01026 { 01027 PRINTF(c,"provider %04x capabilities%s%s%s%s%s",id, 01028 HasFlags(N2FLAG_MECM) ?" MECM":"", 01029 HasFlags(N2FLAG_Bx) ?" Bx":"", 01030 HasFlags(N2FLAG_Ex) ?" Ex":"", 01031 HasFlags(N2FLAG_POSTAU) ?" POSTPROCAU":"", 01032 HasFlags(N2FLAG_INV) ?" INVCW":""); 01033 } 01034 01035 void cN2Prov::ExpandInput(unsigned char *hw) 01036 { 01037 hw[0]^=(0xDE +(0xDE<<1)) & 0xFF; 01038 hw[1]^=(hw[0]+(0xDE<<1)) & 0xFF; 01039 for(int i=2; i<128; i++) hw[i]^=hw[i-2]+hw[i-1]; 01040 IdeaKS ks; 01041 idea.SetEncKey((unsigned char *)"NagraVision S.A.",&ks); 01042 unsigned char buf[8]; 01043 memset(buf,0,8); 01044 for(int i=0; i<128; i+=8) { 01045 xxor(buf,8,buf,&hw[i]); 01046 idea.Encrypt(buf,8,buf,&ks,0); 01047 xxor(buf,8,buf,&hw[i]); 01048 memcpy(&hw[i],buf,8); 01049 } 01050 } 01051 01052 bool cN2Prov::MECM(unsigned char in15, int algo, const unsigned char *ed, unsigned char *cw) 01053 { 01054 unsigned char hd[32], hw[128+64], buf[20]; 01055 hd[0]=in15&0x7F; 01056 hd[1]=cw[14]; 01057 hd[2]=cw[15]; 01058 hd[3]=cw[6]; 01059 hd[4]=cw[7]; 01060 DynamicHD(hd,ed); 01061 01062 if(keyValid && !memcmp(seed,hd,seedSize)) { // key cached 01063 memcpy(buf,cwkey,8); 01064 } 01065 else { // key not cached 01066 memset(hw,0,sizeof(hw)); 01067 if(!Algo(algo,hd,hw)) return false; 01068 memcpy(&hw[128],hw,64); 01069 RotateBytes(&hw[64],128); 01070 SHA1(&hw[64],128,buf); 01071 RotateBytes(buf,20); 01072 01073 memcpy(seed,hd,seedSize); 01074 memcpy(cwkey,buf,8); 01075 keyValid=true; 01076 } 01077 01078 memcpy(&buf[8],buf,8); 01079 IdeaKS ks; 01080 idea.SetEncKey(buf,&ks); 01081 memcpy(&buf[0],&cw[8],6); 01082 memcpy(&buf[6],&cw[0],6); 01083 idea.Encrypt(&buf[4],8,&buf[4],&ks,0); 01084 idea.Encrypt(buf,8,buf,&ks,0); 01085 01086 memcpy(&cw[ 0],&buf[6],3); 01087 memcpy(&cw[ 4],&buf[9],3); 01088 memcpy(&cw[ 8],&buf[0],3); 01089 memcpy(&cw[12],&buf[3],3); 01090 for(int i=0; i<16; i+=4) cw[i+3]=cw[i]+cw[i+1]+cw[i+2]; 01091 return true; 01092 } 01093 01094 void cN2Prov::SwapCW(unsigned char *cw) 01095 { 01096 if(NeedsCwSwap()) { 01097 unsigned char tt[8]; 01098 memcpy(&tt[0],&cw[0],8); 01099 memcpy(&cw[0],&cw[8],8); 01100 memcpy(&cw[8],&tt[0],8); 01101 } 01102 } 01103 01104 // -- cN2Providers ------------------------------------------------------------- 01105 01106 cN2ProvLink *cN2Providers::first=0; 01107 01108 void cN2Providers::Register(cN2ProvLink *plink) 01109 { 01110 PRINTF(L_CORE_DYN,"n2providers: registering prov %04X with flags %d",plink->id,plink->flags); 01111 plink->next=first; 01112 first=plink; 01113 } 01114 01115 cN2Prov *cN2Providers::GetProv(int Id, int Flags) 01116 { 01117 cN2ProvLink *pl=first; 01118 while(pl) { 01119 if(pl->CanHandle(Id) && pl->HasFlags(Flags)) return pl->Create(); 01120 pl=pl->next; 01121 } 01122 return 0; 01123 } 01124 01125 // -- cN2ProvLink -------------------------------------------------------------- 01126 01127 cN2ProvLink::cN2ProvLink(int Id, int Flags) 01128 { 01129 id=Id; flags=Flags; 01130 cN2Providers::Register(this); 01131 } 01132 01133 // -- cNagra2 ------------------------------------------------------------------ 01134 01135 class cNagra2 : public cNagra { 01136 private: 01137 bool Signature(const unsigned char *vkey, const unsigned char *sig, const unsigned char *msg, int len); 01138 protected: 01139 cIDEA idea; 01140 // 01141 virtual void CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q); 01142 bool DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m); 01143 bool DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m); 01144 }; 01145 01146 void cNagra2::CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q) 01147 { 01148 // Calculate P and Q from PK 01149 IdeaKS ks; 01150 idea.SetEncKey(key,&ks); 01151 // expand IDEA-G key 01152 unsigned char idata[96]; 01153 for(int i=11; i>=0; i--) { 01154 unsigned char *d=&idata[i*8]; 01155 memcpy(d,&key[13],8); 01156 *d^=i; 01157 idea.Decrypt(d,8,&ks,0); 01158 xxor(d,8,d,&key[13]); 01159 *d^=i; 01160 } 01161 // Calculate P 01162 idata[0] |= 0x80; 01163 idata[47] |= 1; 01164 BN_bin2bn(idata,48,p); 01165 BN_add_word(p,(key[21] << 5 ) | ((key[22] & 0xf0) >> 3)); 01166 // Calculate Q 01167 idata[48] |= 0x80; 01168 idata[95] |= 1; 01169 BN_bin2bn(idata+48,48,q); 01170 BN_add_word(q,((key[22]&0xf)<<9) | (key[23]<<1)); 01171 } 01172 01173 bool cNagra2::Signature(const unsigned char *vkey, const unsigned char *sig, const unsigned char *msg, int len) 01174 { 01175 unsigned char buff[16]; 01176 memcpy(buff,vkey,sizeof(buff)); 01177 for(int i=0; i<len; i+=8) { 01178 IdeaKS ks; 01179 idea.SetEncKey(buff,&ks); 01180 memcpy(buff,buff+8,8); 01181 idea.Encrypt(msg+i,8,buff+8,&ks,0); 01182 xxor(&buff[8],8,&buff[8],msg+i); 01183 } 01184 buff[8]&=0x7F; 01185 return (memcmp(sig,buff+8,8)==0); 01186 } 01187 01188 bool cNagra2::DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m) 01189 { 01190 int sign=in[0] & 0x80; 01191 if(rsa.RSA(out,in+1,64,pubExp,m)<=0) { 01192 PRINTF(L_SYS_CRYPTO,"first RSA failed (ECM)"); 01193 return false; 01194 } 01195 out[63]|=sign; // sign adjustment 01196 if(len>64) memcpy(out+64,in+65,len-64); 01197 01198 if(in[0]&0x04) { 01199 unsigned char tmp[8]; 01200 DES_key_schedule ks1, ks2; 01201 RotateBytes(tmp,&key[0],8); 01202 DES_key_sched((DES_cblock *)tmp,&ks1); 01203 RotateBytes(tmp,&key[8],8); 01204 DES_key_sched((DES_cblock *)tmp,&ks2); 01205 memset(tmp,0,sizeof(tmp)); 01206 for(int i=7; i>=0; i--) RotateBytes(out+8*i,8); 01207 DES_ede2_cbc_encrypt(out,out,len,&ks1,&ks2,(DES_cblock *)tmp,DES_DECRYPT); 01208 for(int i=7; i>=0; i--) RotateBytes(out+8*i,8); 01209 } 01210 else idea.Decrypt(out,len,key,0); 01211 01212 RotateBytes(out,64); 01213 if(rsa.RSA(out,out,64,pubExp,m,false)<=0) { 01214 PRINTF(L_SYS_CRYPTO,"second RSA failed (ECM)"); 01215 return false; 01216 } 01217 if(vkey && !Signature(vkey,out,out+8,len-8)) { 01218 PRINTF(L_SYS_CRYPTO,"signature failed (ECM)"); 01219 return false; 01220 } 01221 return true; 01222 } 01223 01224 bool cNagra2::DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m) 01225 { 01226 int sign=in[0]&0x80; 01227 if(rsa.RSA(out,in+1,96,pubExp,m)<=0) { 01228 PRINTF(L_SYS_CRYPTO,"first RSA failed (EMM)"); 01229 return false; 01230 } 01231 out[95]|=sign; // sign adjustment 01232 cBN exp; 01233 if(in[0]&0x08) { 01234 // standard IDEA decrypt 01235 if(len>96) memcpy(out+96,in+97,len-96); 01236 idea.Decrypt(out,len,key,0); 01237 BN_set_word(exp,3); 01238 } 01239 else { 01240 // private RSA key expansion 01241 CreateRSAPair(key,0,exp,m); 01242 } 01243 RotateBytes(out,96); 01244 if(rsa.RSA(out,out,96,exp,m,false)<=0) { 01245 PRINTF(L_SYS_CRYPTO,"second RSA failed (EMM)"); 01246 return false; 01247 } 01248 if(vkey && !Signature(vkey,out,out+8,len-8)) { 01249 PRINTF(L_SYS_CRYPTO,"signature failed (EMM)"); 01250 return false; 01251 } 01252 return true; 01253 } 01254 01255 // -- cSystemNagra2 ------------------------------------------------------------ 01256 01257 static int dropEMMs=1; 01258 01259 class cSystemNagra2 : public cSystem, protected cNagra2 { 01260 private: 01261 int lastEcmId, lastEmmId; 01262 cN2Prov *ecmP, *emmP; 01263 public: 01264 cSystemNagra2(void); 01265 ~cSystemNagra2(); 01266 virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data); 01267 virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer); 01268 }; 01269 01270 cSystemNagra2::cSystemNagra2(void) 01271 :cSystem(SYSTEM_NAME,SYSTEM_PRI) 01272 { 01273 hasLogger=true; 01274 lastEcmId=lastEmmId=0; ecmP=emmP=0; 01275 } 01276 01277 cSystemNagra2::~cSystemNagra2() 01278 { 01279 delete ecmP; 01280 delete emmP; 01281 } 01282 01283 bool cSystemNagra2::ProcessECM(const cEcmInfo *ecm, unsigned char *data) 01284 { 01285 #define NA_SOURCE_START 0x8267 // cSource::FromString("S61.5W"); 01286 #define NA_SOURCE_END 0x85c8 // cSource::FromString("S148W"); 01287 unsigned char odata[15]; 01288 memcpy(odata,data,sizeof(odata)); 01289 if(ecm->source>=NA_SOURCE_START && ecm->source<=NA_SOURCE_END) { 01290 if(ecm->caId==0x1234) data[5]=0x09; // NA rev 248 morph 01291 else { 01292 if(ecm->source==0x83ca) data[5]=0xC1; // 97W 01293 else if(ecm->source==0x8334 || ecm->source==0x838e) data[5]=0x09; // 82W 91W 01294 else data[5]=0x01; 01295 } 01296 data[6]&=0x1F; 01297 data[7]=(data[7]&0x10)|0x86; 01298 data[8]=0; 01299 data[9]=(data[9]&0x80)|0x08; 01300 } 01301 01302 int cmdLen=data[4]-5; 01303 int id=(data[5]*256)+data[6]; 01304 cTimeMs minTime; 01305 01306 if(id==0x4101) StartLog(ecm,0x1881); // D+ AU 01307 if(id==0x0505 || id==0x0503 || id==0x0511) id=0x0501; // PremStar ugly again :( 01308 01309 if(cmdLen<64 || SCT_LEN(data)<cmdLen+10) { 01310 if(doLog) PRINTF(L_SYS_ECM,"bad ECM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(data)); 01311 return false; 01312 } 01313 01314 int keyNr=(data[7]&0x10)>>4; 01315 cKeySnoop ks(this,'N',id,keyNr); 01316 cPlainKey *pk; 01317 cBN m1; 01318 unsigned char ideaKey[16], vKey[16]; 01319 bool hasVerifyKey=false; 01320 if(!(pk=keys.FindKey('N',id,MBC('M','1'),-1))) { 01321 if(doLog) PRINTF(L_SYS_KEY,"missing %04x M1 key",id); 01322 return false; 01323 } 01324 pk->Get(m1); 01325 if((pk=keys.FindKeyNoTrig('N',id,'V',sizeof(vKey)))) { 01326 pk->Get(vKey); 01327 hasVerifyKey=true; 01328 } 01329 else if(doLog && id!=lastEcmId) PRINTF(L_SYS_KEY,"missing %04x V key (non-fatal)",id); 01330 if(!(pk=keys.FindKey('N',id,keyNr,sizeof(ideaKey)))) return false; 01331 pk->Get(ideaKey); 01332 01333 unsigned char buff[256]; 01334 if(!DecryptECM(data+9,buff,ideaKey,cmdLen,hasVerifyKey?vKey:0,m1)) { 01335 if(doLog) PRINTF(L_SYS_ECM,"decrypt of ECM failed (%04x)",id); 01336 return false; 01337 } 01338 01339 if((!ecmP && id!=lastEcmId) || (ecmP && !ecmP->CanHandle(id))) { 01340 delete ecmP; 01341 ecmP=cN2Providers::GetProv(id,N2FLAG_NONE); 01342 if(ecmP) ecmP->PrintCaps(L_SYS_ECM); 01343 } 01344 lastEcmId=id; 01345 if(ecmP) ecmP->PostDecrypt(true); 01346 01347 HEXDUMP(L_SYS_RAWECM,buff,cmdLen,"Nagra2 RAWECM"); 01348 int l=0, mecmAlgo=0; 01349 LBSTARTF(L_SYS_ECM); 01350 bool contFail=false; 01351 for(int i=(buff[14]&0x10)?16:20; i<cmdLen-10 && l!=3; ) { 01352 switch(buff[i]) { 01353 case 0x10: 01354 case 0x11: 01355 if(buff[i+1]==0x09) { 01356 int s=(~buff[i])&1; 01357 mecmAlgo=buff[i+2]&0x60; 01358 memcpy(cw+(s<<3),&buff[i+3],8); 01359 i+=11; l|=(s+1); 01360 } 01361 else { 01362 PRINTF(L_SYS_ECM,"bad length %d in CW nano %02x",buff[i+1],buff[i]); 01363 i++; 01364 } 01365 break; 01366 case 0x00: 01367 i+=2; break; 01368 case 0x30: 01369 case 0x31: 01370 case 0x32: 01371 case 0x33: 01372 case 0x34: 01373 case 0x35: 01374 case 0x36: 01375 case 0xB0: 01376 i+=buff[i+1]+2; 01377 break; 01378 default: 01379 if(!contFail) LBPUT("unknown ECM nano"); 01380 LBPUT(" %02x",buff[i]); 01381 contFail=true; 01382 i++; 01383 continue; 01384 } 01385 LBFLUSH(); contFail=false; 01386 } 01387 LBEND(); 01388 if(l!=3) return false; 01389 if(mecmAlgo>0) { 01390 if(ecmP && ecmP->HasFlags(N2FLAG_MECM)) { 01391 if(!ecmP->MECM(buff[15],mecmAlgo,odata,cw)) return false; 01392 } 01393 else { PRINTF(L_SYS_ECM,"MECM for provider %04x not supported",id); return false; } 01394 } 01395 if(ecmP) ecmP->SwapCW(cw); 01396 ks.OK(pk); 01397 01398 int i=minEcmTime-minTime.Elapsed(); 01399 if(i>0) cCondWait::SleepMs(i); 01400 return true; 01401 } 01402 01403 void cSystemNagra2::ProcessEMM(int pid, int caid, const unsigned char *buffer) 01404 { 01405 int cmdLen=buffer[9]-5; 01406 int id=buffer[10]*256+buffer[11]; 01407 01408 if(buffer[0]==0x83 && dropEMMs) return; // skip EMM-S if disabled 01409 if(cmdLen<96 || SCT_LEN(buffer)<cmdLen+15) { 01410 PRINTF(L_SYS_EMM,"bad EMM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(buffer)); 01411 return; 01412 } 01413 01414 int keyset=(buffer[12]&0x03); 01415 int sel=(buffer[12]&0x10)<<2; 01416 int rsasel=(MATCH_ID(id,0x4101) || MATCH_ID(id,0x7101)) ? 0:sel; // D+ hack 01417 int sigsel=(buffer[13]&0x80)>>1; 01418 cPlainKey *pk; 01419 cBN n; 01420 unsigned char ideaKey[24], vKey[16]; 01421 bool hasVerifyKey=false; 01422 if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset+0x10+rsasel),96))) { 01423 PRINTF(L_SYS_EMM,"missing %04x NN %.02X RSA key (96 bytes)",id,keyset+0x10+rsasel); 01424 return; 01425 } 01426 pk->Get(n); 01427 if((pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,0x03+sigsel),sizeof(vKey)))) { 01428 pk->Get(vKey); 01429 hasVerifyKey=true; 01430 } 01431 else if(id!=lastEmmId) PRINTF(L_SYS_EMM,"missing %04x NN %.02X signature key (non-fatal)",id,0x03+sigsel); 01432 if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset),24))) { 01433 if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset+sel),16))) { 01434 PRINTF(L_SYS_EMM,"missing %04x NN %.02x IDEA key (24 or 16 bytes)",id,keyset+sel); 01435 return; 01436 } 01437 memset(ideaKey+16,0,8); 01438 } 01439 pk->Get(ideaKey); 01440 01441 unsigned char emmdata[256]; 01442 if(!DecryptEMM(buffer+14,emmdata,ideaKey,cmdLen,hasVerifyKey?vKey:0,n)) { 01443 PRINTF(L_SYS_EMM,"decrypt of EMM failed (%04x)",id); 01444 return; 01445 } 01446 if((!emmP && id!=lastEmmId) || (emmP && !emmP->CanHandle(id))) { 01447 delete emmP; 01448 emmP=cN2Providers::GetProv(id,N2FLAG_NONE); 01449 if(emmP) emmP->PrintCaps(L_SYS_EMM); 01450 } 01451 lastEmmId=id; 01452 if(emmP) emmP->PostDecrypt(false); 01453 01454 HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM"); 01455 if(buffer[0]==0x82) id=(emmdata[8]<<8)+emmdata[9]; 01456 LBSTARTF(L_SYS_EMM); 01457 bool contFail=false; 01458 for(int i=8+2+4+4; i<cmdLen-22; ) { 01459 switch(emmdata[i]) { 01460 case 0x42: // plain Key update 01461 if((((emmdata[i+3]|0xF3)+1)&0xFF) != 0) { 01462 int len=emmdata[i+2]; 01463 int off=emmdata[i+5]; 01464 int ulen=emmdata[i+6]; 01465 if(len>0 && ulen>0 && off+ulen<=len) { 01466 int ks=emmdata[i+3], kn; 01467 if(ks==0x06 || ks==0x46) kn=(ks>>6)&1; else kn=MBC(N2_MAGIC,ks); 01468 unsigned char key[256]; 01469 memset(key,0,sizeof(key)); 01470 if((pk=keys.FindKeyNoTrig('N',id,kn,len))) { 01471 if(cPlainKeyNagra::IsBNKey(kn)) { pk->Get(n); n.PutLE(key,len); } 01472 else pk->Get(key); 01473 } 01474 bool ok=false; 01475 if((emmdata[i+1]&0x7F)==0) ok=true; 01476 else { 01477 if(emmP && emmP->HasFlags(N2FLAG_POSTAU)) { 01478 if(emmP->PostProcAU(id,&emmdata[i])) ok=true; 01479 } 01480 else PRINTF(L_SYS_EMM,"POSTAU for provider %04x not supported",id); 01481 } 01482 if(ok) { 01483 memcpy(&key[off],&emmdata[i+7],ulen); 01484 FoundKey(); 01485 if(cPlainKeyNagra::IsBNKey(kn)) { 01486 n.GetLE(key,len); 01487 if(keys.NewKey('N',id,kn,n,len)) NewKey(); 01488 } 01489 else { 01490 if(keys.NewKey('N',id,kn,key,len)) NewKey(); 01491 } 01492 } 01493 i+=ulen; 01494 } 01495 else PRINTF(L_SYS_EMM,"nano42 key size mismatch len=%d off=%d ulen=%d",len,off,ulen); 01496 } 01497 else PRINTF(L_SYS_EMM,"nano42 0xf3 status exceeded"); 01498 i+=7; 01499 break; 01500 case 0xE0: // DN key update 01501 if(emmdata[i+1]==0x25) { 01502 FoundKey(); 01503 if(keys.NewKey('N',id,(emmdata[i+16]&0x40)>>6,&emmdata[i+23],16)) NewKey(); 01504 } 01505 i+=emmdata[i+1]+2; 01506 break; 01507 case 0x83: // change data prov. id 01508 id=(emmdata[i+1]<<8)|emmdata[i+2]; 01509 i+=3; 01510 break; 01511 case 0xB0: case 0xB1: case 0xB2: case 0xB3: // Update with ROM CPU code 01512 case 0xB4: case 0xB5: case 0xB6: case 0xB7: 01513 case 0xB8: case 0xB9: case 0xBA: case 0xBB: 01514 case 0xBC: case 0xBD: case 0xBE: case 0xBF: 01515 { 01516 int bx=emmdata[i]&15; 01517 if(!emmP || !emmP->HasFlags(N2FLAG_Bx)) { 01518 PRINTF(L_SYS_EMM,"B%X for provider %04x not supported",bx,id); 01519 i=cmdLen; 01520 break; 01521 } 01522 int r; 01523 if((r=emmP->ProcessBx(emmdata,cmdLen,i+1))>0) 01524 i+=r; 01525 else { 01526 PRINTF(L_SYS_EMM,"B%X executing failed for %04x",bx,id); 01527 i=cmdLen; 01528 } 01529 break; 01530 } 01531 case 0xA0: i+=5; break; // CamID target update 01532 case 0xA3: i+=4; break; // Cam group target update 01533 case 0xA4: i+=emmdata[i+1]+2+4; break; // conditional (always no match assumed for now) 01534 case 0xA6: // updates tier/blackout 01535 if(emmdata[i+4]==0xFD && emmdata[i+5]==0x98) i+=(emmdata[i+1]+emmdata[i+3]+4); 01536 else i+=15; 01537 break; 01538 case 0xAA: i+=emmdata[i+1]+5; break; 01539 case 0xAD: i+=emmdata[i+1]+2; break; 01540 case 0xA2: 01541 case 0xAE: i+=11; break; 01542 case 0x01: i+=3; break; 01543 case 0x10: i+=18; break; 01544 case 0x12: i+=emmdata[i+1]+2; break; // create tier 01545 case 0x20: i+=19; break; // modify tier 01546 case 0x9F: i+=6; break; 01547 case 0xE3: // Eeprom update 01548 { 01549 int ex=emmdata[i]&15; 01550 if(!emmP || !emmP->HasFlags(N2FLAG_Ex)) { 01551 i+=emmdata[i+4]+5; 01552 PRINTF(L_SYS_EMM,"E%X for provider %04x not supported",ex,id); 01553 break; 01554 } 01555 int r; 01556 if((r=emmP->ProcessEx(emmdata,cmdLen,i+1))>0) 01557 i+=r; 01558 else { 01559 PRINTF(L_SYS_EMM,"E%X executing failed for %04x",ex,id); 01560 i=cmdLen; 01561 } 01562 break; 01563 } 01564 case 0x13: 01565 case 0x14: 01566 case 0x15: 01567 case 0x85: 01568 case 0xE1: 01569 case 0xE2: 01570 case 0x00: i=cmdLen; break; // end of processing 01571 default: 01572 if(!contFail) LBPUT("unknown EMM nano"); 01573 LBPUT(" %02x",emmdata[i]); 01574 contFail=true; 01575 i++; 01576 continue; 01577 } 01578 LBFLUSH(); contFail=false; 01579 } 01580 LBEND(); 01581 } 01582 01583 // -- cSystemLinkNagra2 -------------------------------------------------------- 01584 01585 class cSystemLinkNagra2 : public cSystemLink { 01586 public: 01587 cSystemLinkNagra2(void); 01588 virtual bool CanHandle(unsigned short SysId); 01589 virtual cSystem *Create(void) { return new cSystemNagra2; } 01590 }; 01591 01592 static cSystemLinkNagra2 staticInitN2; 01593 01594 cSystemLinkNagra2::cSystemLinkNagra2(void) 01595 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI) 01596 { 01597 opts=new cOpts(SYSTEM_NAME,5); 01598 opts->Add(new cOptBool("DropEMMS",trNOOP("Nagra2: drop EMM-S packets"),&dropEMMs)); 01599 #ifdef HAS_AUXSRV 01600 static const char allowed_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz-."; 01601 opts->Add(new cOptBool("AuxServerEnable",trNOOP("Nagra2: Enable AUXserver"),&auxEnabled)); 01602 opts->Add(new cOptStr("AuxServerAddr",trNOOP("Nagra2: AUXserver hostname"),auxAddr,sizeof(auxAddr),allowed_chars)); 01603 opts->Add(new cOptInt("AuxServerPort",trNOOP("Nagra2: AUXserver port"),&auxPort,0,65535)); 01604 opts->Add(new cOptStr("AuxServerPass",trNOOP("Nagra2: AUXserver password"),auxPassword,sizeof(auxPassword),allowed_chars)); 01605 #endif 01606 Feature.NeedsKeyFile(); 01607 } 01608 01609 bool cSystemLinkNagra2::CanHandle(unsigned short SysId) 01610 { 01611 return ((SysId&SYSTEM_MASK)==SYSTEM_NAGRA && (SysId&0xFF)>0) || 01612 SysId==SYSTEM_NAGRA_BEV; 01613 }