nagra2-0101.c

来自「VDR softcam plugin 0.9.1」· C语言 代码 · 共 969 行 · 第 1/2 页

C
969
字号
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "nagra2.h"// -- cAuxSrv ------------------------------------------------------------------#ifdef HAS_AUXSRV#include "network.h"#define AUX_PROTOCOL_VERSION 2int auxEnabled=0;int auxPort=7777;char auxAddr[80]="localhost";char auxPassword[250]="auxserver";class cAuxSrv : public cMutex {private:  cNetSocket so;  //  bool Login(void);public:  cAuxSrv(void);  int Map(int map, unsigned char *data, int len, int outlen);  };cAuxSrv::cAuxSrv(void):so(DEFAULT_CONNECT_TIMEOUT,7,DEFAULT_IDLE_TIMEOUT){}bool cAuxSrv::Login(){  unsigned char buff[256];  PRINTF(L_SYS_MAP,"auxsrv: connecting to %s:%d",auxAddr,auxPort);  if(so.Connect(auxAddr,auxPort)) {    buff[0]=0xA7;    buff[1]=0x7A;    buff[2]=0;    int l=strlen(auxPassword);    buff[3]=l;    memcpy(&buff[4],auxPassword,l);    buff[4+l]=0xFF;    if(so.Write(buff,l+5)==l+5 &&       so.Read(buff,sizeof(buff))>=9 &&       buff[0]==0x7A && buff[1]==0xA7 && buff[2]==0x00 && buff[3]==0x04 && buff[8]==0xff &&       ((buff[4]<<8)|buff[5])==AUX_PROTOCOL_VERSION) return true;    PRINTF(L_SYS_MAP,"auxsrv: login write failed");    }  so.Disconnect();  return false;}int cAuxSrv::Map(int map, unsigned char *data, int len, int outlen){  if(!auxEnabled) {    PRINTF(L_SYS_MAP,"auxsrv: AUXserver is disabled!");    return -1;    }  if(len>500 || outlen>500) return -1;  cMutexLock lock(this);  if(!so.Connected() && !Login()) return false;  PRINTF(L_SYS_MAP,"auxsrv: calling map%02x",map);  unsigned char buff[512];  buff[0]=0xA7;  buff[1]=0x7A;  buff[2]=((len+1)>>8) & 0xff;  buff[3]=(len+1)&0xff;  buff[4]=map;  memcpy(&buff[5],data,len);  buff[len+5]=0xFF;  if(so.Write(buff,len+6)==len+6) {    if((len=so.Read(buff,sizeof(buff)))>0) {      if(buff[0]==0x7A && buff[1]==0xA7) {        if(buff[4]==0x00) {          int cycles=(buff[5]<<16)|(buff[6]<<8)|buff[7];          int l=buff[2]*256+buff[3];          if(len>=l+5 && l==outlen+4) {            if(buff[l+4]==0xFF) {              memcpy(data,buff+8,outlen);              return cycles;              }            else PRINTF(L_SYS_MAP,"auxsrv: bad footer in map%02x response",map);            }          else PRINTF(L_SYS_MAP,"auxsrv: bad length in map%02x response (got=%d,%d want=%d,%d)",map,l-4,len,outlen,l+8);          }        else PRINTF(L_SYS_MAP,"auxsrv: map%02x not successfull (unsupported?)",map);        }      else PRINTF(L_SYS_MAP,"auxsrv: bad response to map%02x",map);      }    else PRINTF(L_SYS_MAP,"auxsrv: map%02x read failed",map);    }  else  PRINTF(L_SYS_MAP,"auxsrv: map%02x write failed",map);  so.Disconnect();  return -1;}#endif //HAS_AUXSRV// -- cMap0101 ----------------------------------------------------------------class cMap0101 : public cMapCore {private:  static const unsigned char primes[];  static const int tim3b[][17];  static const unsigned short msb3e[];#ifdef HAS_AUXSRV  cAuxSrv aux;#endif  //  void MakePrime(BIGNUM *n, unsigned char *residues);protected:  virtual bool Map(int f, unsigned char *data, int l);  };const unsigned char cMap0101::primes[] = {  0x03,0x05,0x07,0x0B,0x0D,0x11,0x13,0x17,0x1D,0x1F,0x25,0x29,0x2B,0x2F,0x35,0x3B,  0x3D,0x43,0x47,0x49,0x4F,0x53,0x59,0x61,0x65,0x67,0x6B,0x6D,0x71,0x7F,0x83,0x89,  0x8B,0x95,0x97,0x9D,0xA3,0xA7,0xAD,0xB3,0xB5,0xBF,0xC1,0xC5,0xC7,0xD3,0xDF,0xE3,  0xE5,0xE9,0xEF,0xF1,0xFB  };const int cMap0101::tim3b[][17] = {  { 2666,2804,2957,3105,3258,3406,3554,3707,3855,4008,4156,4304,4457,4605,4758,4906,5054 },  { 3163,3316,3484,3652,3815,3983,4146,4314,4482,4645,4813,4976,5144,5312,5475,5643,5806 },  { 3715,3888,4071,4254,4432,4615,4798,4981,5164,5342,5525,5708,5891,6074,6252,6435,6618 },  { 4302,4490,4688,4886,5084,5282,5480,5678,5876,6074,6272,6470,6668,6866,7064,7262,7460 },  { 4899,5107,5320,5533,5751,5964,6177,6390,6603,6821,7034,7247,7460,7673,7891,8104,8317 },  { 5541,5759,5992,6220,6453,6681,6909,7142,7370,7603,7831,8059,8292,8520,8753,8981,9209 },  { 6198,6431,6679,6927,7170,7418,7661,7909,8157,8400,8648,8891,9139,9387,9630,9878,10121 },  { 6910,7163,7426,7689,7947,8210,8473,8736,8999,9257,9520,9783,10046,10309,10567,10830,11093 },  { 7637,7905,8183,8461,8739,9017,9295,9573,9851,10129,10407,10685,10963,11241,11519,11797,12075 },  { 8394,8682,8975,9268,9566,9859,10152,10445,10738,11036,11329,11622,11915,12208,12506,12799,13092 },  { 9196,9494,9807,10115,10428,10736,11044,11357,11665,11978,12286,12594,12907,13215,13528,13836,14144 },  { 10003,10346,10674,11002,11325,11653,11976,12304,12632,12955,13283,13606,13934,14262,14585,14913,15236 },  { 10885,11218,11561,11904,12242,12585,12928,13271,13614,13952,14295,14638,14981,15324,15662,16005,16348 },  { 11792,12145,12498,12856,13214,13572,13930,14288,14646,15004,15362,15720,16078,16436,16794,17152,17510 },  { 12709,13087,13465,13843,14226,14604,14982,15360,15738,16121,16499,16877,17255,17633,18016,18394,18772 },  { 13671,14069,14477,14880,15283,15686,16084,16492,16890,17298,17696,18099,18507,18905,19313,19711,20114 },  { 14668,15091,15519,15947,16370,16798,17221,17654,18082,18505,18933,19356,19784,20212,20640,21068,21491 },  };void cMap0101::MakePrime(BIGNUM *n, unsigned char *residues){  bool isPrime;  cycles+=1290;  do {    cycles+=1465;    BN_add_word(n,2);    isPrime=true;    for(int i=0; i<53; i++) {      residues[i]+=2;      unsigned char num=residues[i];      unsigned char denom=primes[i];      if(num>denom) {        unsigned char r=0;        while(denom>=r) { cycles+=1; r=(r<<1)|((num&0x80)>>7); num<<=1; }        }      residues[i]%=primes[i];      if(residues[i]==0) { cycles+=13; isPrime=false; }      }    } while(!isPrime);}bool cMap0101::Map(int f, unsigned char *data, int l){  int sl=l;  l=GetOpSize(l);  switch(f) {    case 0x21:      AddMapCycles(169-6);      IMakeJ();      cycles=898;      break;    case 0x22:      if(BN_is_zero(D)) { cycles=639-6; break; }      l&=0x1fff;      BN_one(B);      BN_mod_lshift(B,B,l,D,ctx);      if(l<64)        cycles=927+(l&7)*9;      else {        div_t val=div(l-64,2046);        int j=16*((val.rem+1)/2) + (val.rem>4?val.rem-7:val.rem-12)/4;        cycles=1086 + j - ((j-2)%5) + 16923*val.quot - ((4*val.quot-2)%5);        }      break;    case 0x23:      AddMapCycles(169);      IMonInit0();      break;    case 0x25:      AddMapCycles(254);      MakeJ0(B,D,C,wordsize<<6);      // valid for wordsize 1 and 2      AddMapCycles(795*wordsize-492);      BN_zero(C);      cycles=49+800*wordsize;      break;    case 0x29:      {      BN_add(B,B,C);      bool b=BN_is_bit_set(B,wordsize<<6);      if(data) data[0]=b;      if(b) BN_mask_bits(B,wordsize<<6);      cycles=501+(8*wordsize+3)/5*5-6;      break;       }    case 0x2a:      {      bool b=ModSub(B,B,D);      if(data) data[0]=b;      BN_zero(C);      break;      }    case 0x30:    case 0x31:      BN_sqr(D,B,ctx);      BN_rshift(J,B,((wordsize+1)/2)*128-64);      BN_mask_bits(J,64);      if((f&1)) BN_add(D,D,C);      BN_rshift(C,D,wordsize<<6);      BN_mask_bits(C,wordsize<<6);      BN_mask_bits(D,wordsize<<6);      break;    case 0x32:      l=min(34,l);      if(!BN_is_zero(D)) {        A.GetLE(data,l<<3);        BN_div(C,B,A,D,ctx);        BN_rshift(A,C,17*64);        BN_mask_bits(C,17*64);        A.Commit(17);        C.Commit(17);        }      BN_zero(J);      break;    case 0x36:    case 0x38:      AddMapCycles(230);      MonMul0(B,f==0x36?A:B,B,C,D,J,wordsize);      AddMapCycles(102);      MonFin(B,D);      break;    case 0x3b:      AddMapCycles(441);      IMakeJ();      AddMapCycles(46);      IMonInit0(wordsize*60+4*l);      I.GetLE(data,l<<3);      MonMul(B,I,B,l);      cycles=tim3b[wordsize-1][l-1]-6;      break;    case 0x3c:    case 0x3e:      {      if(sl==0) cycles+=4;      if(l>wordsize) { l=wordsize; cycles+=l>17 ? 9:4; }      cBN scalar;      scalar.GetLE(data,l<<3);      AddMapCycles(441);      if(BN_is_zero(scalar) || BN_num_bits(D)<=1) {        IMakeJ();        if(BN_num_bits(D)==1 || !BN_is_zero(scalar)) BN_zero(B);        else BN_one(B);        BN_one(A);        }      else {        IMonInit();        MonMul0(B,A,B,C,D,J,0);        if(f==0x3c) AddMapCycles(2200+(rand()%(wordsize*2000)));        MonFin(B,D);        MonExp(scalar);        }      BN_zero(C);      int sbits=BN_num_bits(scalar);      cycles+=3848+((sbits-1)/8)*650 - 11;      int msb=data[(sbits-1)/8];      for(int i=7; i>=1; --i) if(msb&(1<<i)) { cycles+=i*75-15; break; }      for(int i=0; i<sbits; ++i) if(BN_is_bit_set(scalar,i)) cycles+=88;      break;      }    case 0x4d:      if(-0x018000==l)        BN_mask_bits(B,64);      else {        BN_set_bit(B,(wordsize<<6)-1);        if(-0x028000==l) BN_set_bit(B,(wordsize<<6)-2);        }      BN_set_bit(B,0);      for(int i=0; i<53; i++) data[i]=BN_mod_word(B,primes[i]);      break;    case 0x4e:      MakePrime(B,data);      break;    case 0x57:#ifdef HAS_AUXSRV      {      int c=aux.Map(0x57,data,0x60,0x40);      if(c>0) { cycles=c-6; break; }      }#endif      {      cBN a, b, x, y, scalar;      if(l<2 || l>4) l=4;      WS_START(l);      l<<=3;      D.GetLE(data+0*l,l);      x.GetLE(data+1*l,l);      y.GetLE(data+2*l,l);      b.GetLE(data+3*l,l);      a.GetLE(data+4*l,l);      scalar.GetLE(data+5*l,l);      bool doz=false;      int scalarbits=BN_num_bits(scalar);      if(scalarbits>=2) {        if(BN_is_zero(x) && (BN_is_zero(y) || (BN_is_zero(b) && BN_num_bits(y)==1))) {          BN_zero(Px);          BN_copy(Py,y);          BN_zero(Qz);          }        else {          CurveInit(a);          ToProjective(0,x,y);          BN_copy(Qx,Px);          BN_copy(Qy,Py);          for(int i=scalarbits-2; i>=0; i--) {            DoubleP(0);            if(BN_is_bit_set(scalar,i)) {              BN_copy(A,Pz);              if(BN_is_zero(Pz) || BN_is_zero(D)) {                BN_copy(Px,Qx);                BN_copy(Py,Qy);                BN_copy(Pz,Qz);                AddP(1);                }              else {                doz=true;                if(wordsize==4) {                  BN_rshift(Py,Py,32);                  BN_lshift(Py,Py,32);                  BN_rshift(b,Qz,224);                  BN_add(Py,Py,b);                  }                BN_mask_bits(Px,32);                BN_lshift(b,Qz,32);                BN_add(Px,Px,b);                BN_mask_bits(Px,128);                AddP(0);                }              }            }          ToAffine();          }        }      else {        BN_copy(Px,x);        BN_copy(Py,y);        BN_zero(Qz);        }      memset(data,0,0x40);      Px.PutLE(&data[0x00],l);      if(l<0x20 && doz) {        unsigned char tmp[0x20];        Qz.PutLE(tmp,l);        memcpy(&data[l],&tmp[l-4],4);        }      Py.PutLE(&data[0x20],l);      BN_zero(A);      BN_zero(B);      BN_zero(C);      WS_END();      break;      }    default:      return false;    }  return true;}// -- cN2Prov0101 --------------------------------------------------------------class cN2Prov0101 : public cN2Prov, public cN2Emu, private cMap0101 {private:  int desSize;  DES_key_schedule desks1, desks2;  unsigned char desblock[8];  IdeaKS ks;  cMapMemHW *hwMapper;  // Randomiser  unsigned int rnd, rndtime;  //  void AddRomCallbacks(void);  bool RomCallbacks(void);  bool ProcessMap(int f);  bool ProcessDESMap(int f);protected:  int mecmAddr[2];  int mecmKeyId;  //  virtual bool Algo(int algo, const unsigned char *hd, unsigned char *hw);  virtual void DynamicHD(unsigned char *hd, const unsigned char *ed);  virtual bool RomInit(void);  virtual void Stepper(void);  virtual void ReadHandler(unsigned char seg, unsigned short ea, unsigned char &op);  virtual void TimerHandler(unsigned int num);  virtual void AddMapCycles(unsigned int num) { AddCycles(num); }  virtual unsigned int CpuCycles(void) { return Cycles(); }public:  cN2Prov0101(int Id, int Flags);  virtual bool PostProcAU(int id, unsigned char *data);  virtual int ProcessBx(unsigned char *data, int len, int pos);  virtual int ProcessEx(unsigned char *data, int len, int pos);  virtual int RunEmu(unsigned char *data, int len, unsigned short load, unsigned short run, unsigned short stop, unsigned short fetch, int fetch_len);  virtual void PostDecrypt(bool ecm) { PostDecryptSetup(ecm); }  };static cN2ProvLinkReg<cN2Prov0101,0x0101,(N2FLAG_MECM|N2FLAG_POSTAU|N2FLAG_Bx|N2FLAG_Ex)> staticPL0101;cN2Prov0101::cN2Prov0101(int Id, int Flags):cN2Prov(Id,Flags){  mecmAddr[0]=0x91d7; mecmAddr[1]=0x92d7; mecmKeyId=0x106;  seedSize=10;  desSize=16; hwMapper=0;  SetMapIdent(Id);  hasReadHandler=true;}void cN2Prov0101::DynamicHD(unsigned char *hd, const unsigned char *ed){  hd[5]=ed[5];  hd[6]=(ed[7]&0xEF) | ((ed[6]&0x40)>>2);  hd[7]=ed[8];  hd[8]=(ed[9]&0x7F) | ((ed[6]&0x20)<<2);  hd[9]=ed[6]&0x80;}bool cN2Prov0101::Algo(int algo, const unsigned char *hd, unsigned char *hw){  if(algo!=0x40 && algo!=0x60) {    PRINTF(L_SYS_ECM,"%04X: unknown MECM algo %02x",id,algo);    return false;    }  if(!Init(id,102)) {    PRINTF(L_SYS_ECM,"%04X: failed to initialize ROM",id);    return false;    }  unsigned char keyNr=(algo>>5)&0x01;  unsigned char mecmCode[256];  GetMem(mecmAddr[keyNr],mecmCode,256,0x80);  cPlainKey *pk;  unsigned char ideaKey[16];  if(!(pk=keys.FindKey('N',mecmKeyId,keyNr,sizeof(ideaKey)))) {    PRINTF(L_SYS_KEY,"missing %04x %02x MECM key",mecmKeyId,keyNr);    return false;    }  pk->Get(ideaKey);  idea.SetEncKey(ideaKey,&ks);  for(int i=0x100-8; i>=8; i-=8) {    idea.Encrypt(mecmCode+i,8,mecmCode+i,&ks,0);    xxor(mecmCode+i,8,mecmCode+i,mecmCode+i-8);    }  idea.Encrypt(mecmCode,8,mecmCode,&ks,0);  HEXDUMP(L_SYS_RAWECM,mecmCode,sizeof(mecmCode),"decrypted MECM code");  // check signature  unsigned char data[256];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?