SASC
DVBSoftCAM

cSystemNagra2 Class Reference

Inheritance diagram for cSystemNagra2:

List of all members.

Public Member Functions

 cSystemNagra2 (void)
 ~cSystemNagra2 ()
virtual bool ProcessECM (const cEcmInfo *ecm, unsigned char *data)
virtual void ProcessEMM (int pid, int caid, const unsigned char *buffer)
 cSystemNagra2 (void)
 ~cSystemNagra2 ()
virtual bool ProcessECM (const cEcmInfo *ecm, unsigned char *data)
virtual void ProcessEMM (int pid, int caid, const unsigned char *buffer)

Detailed Description

Definition at line 1259 of file nagra2.c.


Constructor & Destructor Documentation

cSystemNagra2::cSystemNagra2 ( void  )

Definition at line 1270 of file nagra2.c.

References cSystem::hasLogger.

:cSystem(SYSTEM_NAME,SYSTEM_PRI)
{
  hasLogger=true;
  lastEcmId=lastEmmId=0; ecmP=emmP=0;
}
cSystemNagra2::~cSystemNagra2 ( )

Definition at line 1277 of file nagra2.c.

{
  delete ecmP;
  delete emmP;
}
cSystemNagra2::cSystemNagra2 ( void  )
cSystemNagra2::~cSystemNagra2 ( )

Member Function Documentation

bool cSystemNagra2::ProcessECM ( const cEcmInfo *  ecm,
unsigned char *  data 
) [virtual]

Implements cSystem.

Definition at line 1283 of file nagra2.c.

References cEcmInfo::caId, cN2Prov::CanHandle(), cSystem::cw, cNagra2::DecryptECM(), cSystem::doLog, cTimeMs::Elapsed(), cPlainKeys::FindKey(), cPlainKeys::FindKeyNoTrig(), cPlainKey::Get(), cN2Providers::GetProv(), cN2Prov::HasFlags(), HEXDUMP, i, id, keys, L_SYS_ECM, L_SYS_KEY, L_SYS_RAWECM, LBEND, LBFLUSH, LBPUT, LBSTARTF, MBC, cN2Prov::MECM(), minEcmTime, N2FLAG_MECM, N2FLAG_NONE, NA_SOURCE_END, NA_SOURCE_START, cKeySnoop::OK(), cN2Prov::PostDecrypt(), cN2Prov::PrintCaps(), PRINTF, SCT_LEN, cCondWait::SleepMs(), cEcmInfo::source, cSystem::StartLog(), and cN2Prov::SwapCW().

{
#define NA_SOURCE_START 0x8267 // cSource::FromString("S61.5W");
#define NA_SOURCE_END   0x85c8 // cSource::FromString("S148W");
  unsigned char odata[15];
  memcpy(odata,data,sizeof(odata));
  if(ecm->source>=NA_SOURCE_START && ecm->source<=NA_SOURCE_END) {
    if(ecm->caId==0x1234) data[5]=0x09;         // NA rev 248 morph
    else {
      if(ecm->source==0x83ca) data[5]=0xC1;     // 97W
      else if(ecm->source==0x8334 || ecm->source==0x838e) data[5]=0x09; // 82W 91W
      else data[5]=0x01;
      }
    data[6]&=0x1F;
    data[7]=(data[7]&0x10)|0x86;
    data[8]=0;
    data[9]=(data[9]&0x80)|0x08;
    }

  int cmdLen=data[4]-5;
  int id=(data[5]*256)+data[6];
  cTimeMs minTime;

  if(id==0x4101) StartLog(ecm,0x1881); // D+ AU
  if(id==0x0505 || id==0x0503 || id==0x0511) id=0x0501; // PremStar  ugly again :(

  if(cmdLen<64 || SCT_LEN(data)<cmdLen+10) {
    if(doLog) PRINTF(L_SYS_ECM,"bad ECM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(data));
    return false;
    }

  int keyNr=(data[7]&0x10)>>4;
  cKeySnoop ks(this,'N',id,keyNr);
  cPlainKey *pk;
  cBN m1;
  unsigned char ideaKey[16], vKey[16];
  bool hasVerifyKey=false;
  if(!(pk=keys.FindKey('N',id,MBC('M','1'),-1)))  {
    if(doLog) PRINTF(L_SYS_KEY,"missing %04x M1 key",id);
    return false;
    }
  pk->Get(m1);
  if((pk=keys.FindKeyNoTrig('N',id,'V',sizeof(vKey)))) {
    pk->Get(vKey);
    hasVerifyKey=true;
    }
  else if(doLog && id!=lastEcmId) PRINTF(L_SYS_KEY,"missing %04x V key (non-fatal)",id);
  if(!(pk=keys.FindKey('N',id,keyNr,sizeof(ideaKey)))) return false;
  pk->Get(ideaKey);

  unsigned char buff[256];
  if(!DecryptECM(data+9,buff,ideaKey,cmdLen,hasVerifyKey?vKey:0,m1)) {
    if(doLog) PRINTF(L_SYS_ECM,"decrypt of ECM failed (%04x)",id);
    return false;
    }

  if((!ecmP && id!=lastEcmId) || (ecmP && !ecmP->CanHandle(id))) {
    delete ecmP;
    ecmP=cN2Providers::GetProv(id,N2FLAG_NONE);
    if(ecmP) ecmP->PrintCaps(L_SYS_ECM);
    }
  lastEcmId=id;
  if(ecmP) ecmP->PostDecrypt(true);

  HEXDUMP(L_SYS_RAWECM,buff,cmdLen,"Nagra2 RAWECM");
  int l=0, mecmAlgo=0;
  LBSTARTF(L_SYS_ECM);
  bool contFail=false;
  for(int i=(buff[14]&0x10)?16:20; i<cmdLen-10 && l!=3; ) {
    switch(buff[i]) {
      case 0x10:
      case 0x11:
        if(buff[i+1]==0x09) {
          int s=(~buff[i])&1;
          mecmAlgo=buff[i+2]&0x60;
          memcpy(cw+(s<<3),&buff[i+3],8);
          i+=11; l|=(s+1);
          }
        else {
          PRINTF(L_SYS_ECM,"bad length %d in CW nano %02x",buff[i+1],buff[i]);
          i++;
          }
        break;
      case 0x00:
        i+=2; break;
      case 0x30:
      case 0x31:
      case 0x32:
      case 0x33:
      case 0x34:
      case 0x35:
      case 0x36:
      case 0xB0:
        i+=buff[i+1]+2;
        break;
      default:
        if(!contFail) LBPUT("unknown ECM nano");
        LBPUT(" %02x",buff[i]);
        contFail=true;
        i++;
        continue;
      }
    LBFLUSH(); contFail=false;
    }
  LBEND();
  if(l!=3) return false;
  if(mecmAlgo>0) {
    if(ecmP && ecmP->HasFlags(N2FLAG_MECM)) {
      if(!ecmP->MECM(buff[15],mecmAlgo,odata,cw)) return false;
      }
    else { PRINTF(L_SYS_ECM,"MECM for provider %04x not supported",id); return false; }
    }
  if(ecmP) ecmP->SwapCW(cw);
  ks.OK(pk);

  int i=minEcmTime-minTime.Elapsed();
  if(i>0) cCondWait::SleepMs(i);
  return true;
}
virtual bool cSystemNagra2::ProcessECM ( const cEcmInfo *  ecm,
unsigned char *  data 
) [virtual]

Implements cSystem.

virtual void cSystemNagra2::ProcessEMM ( int  pid,
int  caid,
const unsigned char *  buffer 
) [virtual]

Reimplemented from cSystem.

void cSystemNagra2::ProcessEMM ( int  pid,
int  caid,
const unsigned char *  buffer 
) [virtual]

Reimplemented from cSystem.

Definition at line 1403 of file nagra2.c.

References cN2Prov::CanHandle(), cNagra2::DecryptEMM(), cPlainKeys::FindKeyNoTrig(), cSystem::FoundKey(), cPlainKey::Get(), cBN::GetLE(), cN2Providers::GetProv(), cN2Prov::HasFlags(), HEXDUMP, i, id, cPlainKeyNagra::IsBNKey(), keys, L_SYS_EMM, L_SYS_RAWEMM, LBEND, LBFLUSH, LBPUT, LBSTARTF, MATCH_ID, MBC, N2_MAGIC, N2FLAG_Bx, N2FLAG_Ex, N2FLAG_NONE, N2FLAG_POSTAU, cSystem::NewKey(), cPlainKeys::NewKey(), cN2Prov::PostDecrypt(), cN2Prov::PostProcAU(), cN2Prov::PrintCaps(), PRINTF, cN2Prov::ProcessBx(), cN2Prov::ProcessEx(), cBN::PutLE(), and SCT_LEN.

{
  int cmdLen=buffer[9]-5;
  int id=buffer[10]*256+buffer[11];

  if(buffer[0]==0x83 && dropEMMs) return; // skip EMM-S if disabled
  if(cmdLen<96 || SCT_LEN(buffer)<cmdLen+15) {
    PRINTF(L_SYS_EMM,"bad EMM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(buffer));
    return;
    }

  int keyset=(buffer[12]&0x03);
  int sel=(buffer[12]&0x10)<<2;
  int rsasel=(MATCH_ID(id,0x4101) || MATCH_ID(id,0x7101)) ? 0:sel; // D+ hack
  int sigsel=(buffer[13]&0x80)>>1;
  cPlainKey *pk;
  cBN n;
  unsigned char ideaKey[24], vKey[16];
  bool hasVerifyKey=false;
  if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset+0x10+rsasel),96)))  {
    PRINTF(L_SYS_EMM,"missing %04x NN %.02X RSA key (96 bytes)",id,keyset+0x10+rsasel);
    return;
    }
  pk->Get(n);
  if((pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,0x03+sigsel),sizeof(vKey)))) {
    pk->Get(vKey);
    hasVerifyKey=true;
    }
  else if(id!=lastEmmId) PRINTF(L_SYS_EMM,"missing %04x NN %.02X signature key (non-fatal)",id,0x03+sigsel);
  if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset),24))) {
    if(!(pk=keys.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset+sel),16))) {
      PRINTF(L_SYS_EMM,"missing %04x NN %.02x IDEA key (24 or 16 bytes)",id,keyset+sel);
      return;
      }
    memset(ideaKey+16,0,8);
    }
  pk->Get(ideaKey);

  unsigned char emmdata[256];
  if(!DecryptEMM(buffer+14,emmdata,ideaKey,cmdLen,hasVerifyKey?vKey:0,n)) {
    PRINTF(L_SYS_EMM,"decrypt of EMM failed (%04x)",id);
    return;
    }
  if((!emmP && id!=lastEmmId) || (emmP && !emmP->CanHandle(id))) {
    delete emmP;
    emmP=cN2Providers::GetProv(id,N2FLAG_NONE);
    if(emmP) emmP->PrintCaps(L_SYS_EMM);
    }
  lastEmmId=id;
  if(emmP) emmP->PostDecrypt(false);

  HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM");
  if(buffer[0]==0x82) id=(emmdata[8]<<8)+emmdata[9];
  LBSTARTF(L_SYS_EMM);
  bool contFail=false;
  for(int i=8+2+4+4; i<cmdLen-22; ) {
    switch(emmdata[i]) {
      case 0x42: // plain Key update
        if((((emmdata[i+3]|0xF3)+1)&0xFF) != 0) {
          int len=emmdata[i+2];
          int off=emmdata[i+5];
          int ulen=emmdata[i+6];
          if(len>0 && ulen>0 && off+ulen<=len) {
            int ks=emmdata[i+3], kn;
            if(ks==0x06 || ks==0x46) kn=(ks>>6)&1; else kn=MBC(N2_MAGIC,ks);
            unsigned char key[256];
            memset(key,0,sizeof(key));
            if((pk=keys.FindKeyNoTrig('N',id,kn,len))) {
              if(cPlainKeyNagra::IsBNKey(kn)) { pk->Get(n); n.PutLE(key,len); }
              else pk->Get(key);
              }
            bool ok=false;
            if((emmdata[i+1]&0x7F)==0) ok=true;
            else {
              if(emmP && emmP->HasFlags(N2FLAG_POSTAU)) {
                if(emmP->PostProcAU(id,&emmdata[i])) ok=true;
                }
              else PRINTF(L_SYS_EMM,"POSTAU for provider %04x not supported",id);
              }
            if(ok) {
              memcpy(&key[off],&emmdata[i+7],ulen);
              FoundKey();
              if(cPlainKeyNagra::IsBNKey(kn)) {
                n.GetLE(key,len);
                if(keys.NewKey('N',id,kn,n,len)) NewKey();
                }
              else {
                if(keys.NewKey('N',id,kn,key,len)) NewKey();
                }
              }
            i+=ulen;
            }
          else PRINTF(L_SYS_EMM,"nano42 key size mismatch len=%d off=%d ulen=%d",len,off,ulen);
          }
        else PRINTF(L_SYS_EMM,"nano42 0xf3 status exceeded");
        i+=7;
        break;
      case 0xE0: // DN key update
        if(emmdata[i+1]==0x25) {
          FoundKey();
          if(keys.NewKey('N',id,(emmdata[i+16]&0x40)>>6,&emmdata[i+23],16)) NewKey();
          }
        i+=emmdata[i+1]+2;
        break;
      case 0x83: // change data prov. id
        id=(emmdata[i+1]<<8)|emmdata[i+2];
        i+=3;
        break;
      case 0xB0: case 0xB1: case 0xB2: case 0xB3: // Update with ROM CPU code
      case 0xB4: case 0xB5: case 0xB6: case 0xB7:
      case 0xB8: case 0xB9: case 0xBA: case 0xBB:
      case 0xBC: case 0xBD: case 0xBE: case 0xBF:
        {
        int bx=emmdata[i]&15;
        if(!emmP || !emmP->HasFlags(N2FLAG_Bx)) {
          PRINTF(L_SYS_EMM,"B%X for provider %04x not supported",bx,id);
          i=cmdLen;
          break;
          }
        int r;
        if((r=emmP->ProcessBx(emmdata,cmdLen,i+1))>0)
          i+=r;
        else {
          PRINTF(L_SYS_EMM,"B%X executing failed for %04x",bx,id);
          i=cmdLen;
          }
        break;
        }
      case 0xA0: i+=5; break;                   // CamID target update
      case 0xA3: i+=4; break;                   // Cam group target update
      case 0xA4: i+=emmdata[i+1]+2+4; break;    // conditional (always no match assumed for now)
      case 0xA6:                                // updates tier/blackout
        if(emmdata[i+4]==0xFD && emmdata[i+5]==0x98) i+=(emmdata[i+1]+emmdata[i+3]+4);
        else i+=15;
        break;
      case 0xAA: i+=emmdata[i+1]+5; break;
      case 0xAD: i+=emmdata[i+1]+2; break;
      case 0xA2:
      case 0xAE: i+=11; break;
      case 0x01: i+=3; break;
      case 0x10: i+=18; break;
      case 0x12: i+=emmdata[i+1]+2; break;      // create tier
      case 0x20: i+=19; break;                  // modify tier
      case 0x9F: i+=6; break;
      case 0xE3:                                // Eeprom update
        {
        int ex=emmdata[i]&15;
        if(!emmP || !emmP->HasFlags(N2FLAG_Ex)) {
          i+=emmdata[i+4]+5;
          PRINTF(L_SYS_EMM,"E%X for provider %04x not supported",ex,id);
          break;
          }
        int r;
        if((r=emmP->ProcessEx(emmdata,cmdLen,i+1))>0)
          i+=r;
        else {
          PRINTF(L_SYS_EMM,"E%X executing failed for %04x",ex,id);
          i=cmdLen;
          }
        break;
        }
      case 0x13:
      case 0x14:
      case 0x15:
      case 0x85:
      case 0xE1:
      case 0xE2:
      case 0x00: i=cmdLen; break;               // end of processing
      default:
        if(!contFail) LBPUT("unknown EMM nano");
        LBPUT(" %02x",emmdata[i]);
        contFail=true;
        i++;
        continue;
      }
    LBFLUSH(); contFail=false;
    }
  LBEND();
}

The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines