SASC
DVBSoftCAM

nagra2.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 #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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines