SASC
DVBSoftCAM

cSystemSeca Class Reference

Inheritance diagram for cSystemSeca:

List of all members.

Public Member Functions

 cSystemSeca (void)
virtual ~cSystemSeca ()
virtual bool ProcessECM (const cEcmInfo *ecm, unsigned char *data)
virtual void ProcessEMM (int pid, int caid, const unsigned char *buffer)
 cSystemSeca (void)
virtual ~cSystemSeca ()
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 1164 of file seca.c.


Constructor & Destructor Documentation

cSystemSeca::cSystemSeca ( void  )

Definition at line 1183 of file seca.c.

References cSystem::hasLogger.

:cSystem(SYSTEM_NAME,SYSTEM_PRI),
des(secaPC1,secaPC2)
{
  sp=spL=0; emmLenCnt=0;
  hasLogger=true;
}
cSystemSeca::~cSystemSeca ( ) [virtual]

Definition at line 1191 of file seca.c.

{
  delete sp;
  delete spL;
}
cSystemSeca::cSystemSeca ( void  )
virtual cSystemSeca::~cSystemSeca ( ) [virtual]

Member Function Documentation

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

Implements cSystem.

Definition at line 1206 of file seca.c.

References AUTOMEM, cSeca2Prov::CalcSHASignature(), cSeca::CalcSignature(), cSystem::cw, cSeca::Decrypt(), cSeca2Prov::DecryptSE(), cSystem::doLog, cSeca2Prov::DoSigCheck(), cSeca::Encrypt(), exp, cPlainKeys::FindKey(), cPlainKey::Get(), HEXDUMP, i, KEY2INDEX, cParseSeca::KeyNr(), keys, L_SYS_CRYPTO, L_SYS_ECM, L_SYS_KEY, L_SYS_VERBOSE, LDUMP, MBC, mod, cKeySnoop::OK(), cParseSeca::Payload(), PK, cSeca2Prov::PostCW(), cSeca2Prov::PostSSE(), cSeca2Prov::PreCW(), cSeca2Prov::PreSSE(), PRINTF, cEcmInfo::provId, cRSA::RSA(), SCT_LEN, cSeca2Prov::SignatureMod(), cParseSeca::SysMode(), cSeca2Prov::T1(), cSeca::T1_S1, cSeca2Prov::T2(), and cSeca::T2_S1.

{
  bool SE=false;
  unsigned char *ecm;
  const int msgLen=cParseSeca::Payload(data,(const unsigned char **)&ecm);
  const int keyNr=cParseSeca::KeyNr(data);

  if(keyNr&0x80) {
    PRINTF(L_SYS_VERBOSE,"Super Encryption enabled");
    SE=true;
    if(!GetSeca2Prov(ecmD->provId,sp)) {
      if(doLog) PRINTF(L_SYS_ECM,"Seca2 provider %04x not supported",ecmD->provId);
      return false;
      }
    }
  HEXDUMP(L_SYS_VERBOSE,data,SCT_LEN(data),"ECM:");
  if(ecm[0]==0x10) {
    if(msgLen<0x5c) {
      if(doLog) PRINTF(L_SYS_ECM,"ECM length too small (%d)",msgLen);
      return false;
      }

    if(SE) {
      HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before SSE data modification :");
      sp->PreSSE(ecm,msgLen-0x5a);
      HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after SSE data modification :");
      }

    const int rsaKeynr=(ecm[1]&0x0F)+'0';
    cBN exp, mod;
    cPlainKey *rsaKey;
    if(!(rsaKey=keys.FindKey('S',ecmD->provId,MBC('E',rsaKeynr),-1))) {
      if(doLog) PRINTF(L_SYS_KEY,"missing %04x E%c key",ecmD->provId,rsaKeynr);
      return false;
      }
    rsaKey->Get(exp);
    if(!(rsaKey=keys.FindKey('S',ecmD->provId,MBC('M',rsaKeynr),-1))) {
      if(doLog) PRINTF(L_SYS_KEY,"missing %04x M%c key",ecmD->provId,rsaKeynr);
      return false;
      }
    rsaKey->Get(mod);
    HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before RSA decrypt :");
    if(rsa.RSA(ecm+(msgLen-0x5a),ecm+(msgLen-0x5a),0x5a,exp,mod)!=0x5a) {
      PRINTF(L_SYS_CRYPTO,"RSA decrypt failed (ECM)");
      return false;
      }
    HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after RSA decrypt :");

    if(SE) { // PostSSE needed
      const int hashPtr=msgLen-ecm[msgLen-1]-9;
      if(hashPtr>=msgLen-9 || ecm[hashPtr]!=0x82) {
        PRINTF(L_SYS_CRYPTO,"RSA decrypt failed, signature pointer not found");
        return false;
        }
      HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before SSE result modification :");
      sp->PostSSE(ecm,hashPtr);
      HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after SSE result modification :");
      }
    }

  const unsigned char *T1=T1_S1, *T2=T2_S1;
  int decrLen=msgLen;
  if(SE) {
    if(!(T1=sp->T1(KEY2INDEX(keyNr))) ||
       !(T2=sp->T2(KEY2INDEX(keyNr)))) return false;
    decrLen-=ecm[msgLen-1]; if(decrLen<8) return false;
    }

  bool key8=!(cParseSeca::SysMode(data)&0x10);
  cPlainKey *pk=0;
  cKeySnoop ks(this,'S',ecmD->provId,keyNr&0x0F);
  unsigned char *buff=AUTOMEM(msgLen);
  while((pk=keys.FindKey('S',ecmD->provId,keyNr&0x0F,key8?8:16,pk))) {
    memcpy(buff,ecm,msgLen); // if decoding fails we need the original data
    
    unsigned char PK[16], signature[20];
    pk->Get(PK);
    if(key8) memcpy(&PK[8],&PK[0],8); // duplicate key

    if(SE) {
      sp->CalcSHASignature(buff,decrLen-8,signature);
      LDUMP(L_SYS_VERBOSE,signature,8,"signature before encrypt :");
      sp->SignatureMod(signature,PK);
      Encrypt(signature,PK,T1,T2);
      LDUMP(L_SYS_VERBOSE,signature,8,"signature after encrypt :");

      if(sp->DoSigCheck() && memcmp(signature,&buff[decrLen-8],8)) {
        PRINTF(L_SYS_VERBOSE,"signature check failed before SE decrypt");
        continue;
        }
      HEXDUMP(L_SYS_VERBOSE,buff+2,msgLen-2,"ECM before SE decrypt :");
      if(!sp->DecryptSE(buff+2,PK,msgLen-2,8,T1,T2)) {
        PRINTF(L_SYS_VERBOSE,"SE decrypt failed");
        continue;
        }
      HEXDUMP(L_SYS_VERBOSE,buff+2,msgLen-2,"ECM after SE decrypt :");
      }
    else {
      CalcSignature(buff,decrLen-8,signature,PK,T1,T2);
      }
    unsigned char hashDW[28]; // actually 16 bytes used for processing, but SHA needs more
    unsigned char *cCW=0;
    const unsigned char *nano51Data=0;
    int nr0F=0;

    for(int i=0 ; i<decrLen; ) {
      int param=buff[i++];
      int extra=(param >> 4) & 0x0f;
      switch(extra) {
        case 0x0d: extra=0x10; break;
        case 0x0e: extra=0x18; break;
        case 0x0f: extra=0x20; break;
        }
      switch(param) {
        case 0x0f:
          if(SE) nr0F++;
          break;
        case 0x51:
          if(SE) nano51Data=&buff[i];
          break;
        case 0xd1:
          cCW=&buff[i];
          if(SE) {
            sp->CalcSHASignature(buff,i,hashDW,false);
            memcpy(&hashDW[20],hashDW,8);
            Decrypt(&hashDW[20],PK,sp->T1(0),sp->T2(0));
            sp->CalcSHASignature(hashDW,28,hashDW,false);
            }
          break;
        case 0x82:
          if((!SE || sp->DoSigCheck()) && memcmp(&buff[i],signature,8)) { 
            PRINTF(L_SYS_VERBOSE,"signature check failed after decrypt");
            cCW=0; i=decrLen;
            }
          break;
        }
      i+=extra;
      }
    if(cCW) {
      if(!nr0F || Process0FNano(nr0F,hashDW,PK,T1,T2)) {
        if(SE) sp->PreCW(cCW);
        if(!nano51Data || Process51Nano(cCW,nano51Data,hashDW,T1,T2,ecmD->provId)) {
          LDUMP(L_SYS_VERBOSE,cCW,16,"crypted CW :");
          Decrypt(&cCW[0],PK,T1,T2); Decrypt(&cCW[8],PK,T1,T2);
          LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW :");
          if(SE) {
            LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW before modification :");
            sp->PostCW(cCW);
            LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW after modification :");
            }
          memcpy(cw,cCW,16);
          ks.OK(pk);
          return true;
          }
        }
      }
    }
  return false;
}
virtual bool cSystemSeca::ProcessECM ( const cEcmInfo *  ecm,
unsigned char *  data 
) [virtual]

Implements cSystem.

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

Reimplemented from cSystem.

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

Reimplemented from cSystem.

Definition at line 1564 of file seca.c.

References AUTOMEM, cSeca2Prov::CalcSHASignature(), cSeca::CalcSignature(), CheckNull(), cmd, cParseSeca::CmdLen(), cSeca::Decrypt(), cSeca2Prov::DecryptSE(), EMM_MAGIC, cSeca::Encrypt(), exp, cPlainKeys::FindKeyNoTrig(), cStructList< T >::First(), cSystem::FoundKey(), cPlainKey::Get(), HexStr(), KEY2INDEX, cParseSeca::KeyNr(), keys, L_SYS_EMM, LBEND, LBPUT, LBSTARTF, MBC3, mod, cSystem::NewKey(), cPlainKeys::NewKey(), cStructList< T >::Next(), cParseSeca::Payload(), PRINTF, cParseSeca::ProvId(), cRSA::RSA(), SA, SID, cParseSeca::SysMode(), cSeca2Prov::T1(), cSeca::T1_S1, cSeca2Prov::T2(), and cSeca::T2_S1.

{
  if(buffer[0]!=0x84) return; // we only support shared updates

  int msgLen=cParseSeca::CmdLen(buffer);
  if(msgLen!=0x55 && msgLen!=0x63) {
    if(++emmLenCnt<=5)
      PRINTF(L_SYS_EMM,"length of EMM does not match (%02x <> 55/63)%s",msgLen,emmLenCnt==5 ? " ....":"");
    return;
    }
  emmLenCnt=0;
  unsigned char *emm;
  msgLen=cParseSeca::Payload(buffer,(const unsigned char **)&emm);
  int provId=cParseSeca::ProvId(buffer);
  bool SE=false;
  const unsigned char *T1=T1_S1, *T2=T2_S1;
  int decrLen=msgLen;
  if(emm[0]==0x10) { // de-SSE
    const int rsaKeynr = emm[1]+'0';
    cPlainKey *pk;
    cBN exp, mod;
    
    if(!(pk=keys.FindKeyNoTrig('S',provId,MBC3('E',rsaKeynr,EMM_MAGIC),-1))) return;
    pk->Get(exp);
    if(!(pk=keys.FindKeyNoTrig('S',provId,MBC3('M',rsaKeynr,EMM_MAGIC),-1))) return;
    pk->Get(mod);
 
    if(rsa.RSA(emm+2,emm+2,msgLen-2,exp,mod)!=msgLen-2) return;
    const int keyNr=cParseSeca::KeyNr(buffer);
    if(keyNr&0x80) {
      SE=true;
      decrLen-=emm[msgLen-1]; 
      if(!GetSeca2Prov(provId,spL) ||
         !(T1=spL->T1(KEY2INDEX(keyNr))) ||
         !(T2=spL->T2(KEY2INDEX(keyNr))) ||
         decrLen<8) return;
      }
    }

  unsigned char *buff=AUTOMEM(msgLen);
  for(cSecaCardInfo *ci=Scards.First(); ci; ci=Scards.Next(ci)) {
    if(ci->MatchEMM(buffer) || (CheckNull(ci->sa,sizeof(ci->sa)) && ci->MatchID(buffer))) {
      unsigned char MK[16];
      if(cParseSeca::SysMode(buffer)&0x10) {
        if(ci->KeySize()!=16) continue; // don't bother
        memcpy(&MK[0],ci->key,16);
        }
      else {
        memcpy(&MK[0],ci->key,8);
        memcpy(&MK[8],ci->key,8);
        }

      unsigned char signature[20];
      memcpy(buff,emm,msgLen); // if decoding fails we need the original de-sse'd data

      if(!SE) {
        for(int i=0 ; i<=64 && i<msgLen-8; i+=8) Decrypt(&buff[i],MK,T1,T2);
        CalcSignature(buff,decrLen-8,signature,MK,T1,T2);
        }
      else {
        spL->CalcSHASignature(buff,decrLen-8,signature);
        Encrypt(signature,MK,T1,T2);
        if(memcmp(signature,&buff[decrLen-8],8) ||
           !spL->DecryptSE(buff+2,MK,msgLen-2,0,T1,T2)) continue;
        }

      unsigned char keyN[4], *key[4];
      int pos, len;
      unsigned int numKeys=0;
      bool sigOk=false;
      for(pos=0 ; pos<decrLen ; pos+=len) {
        int cmd=buff[pos++];
        len=(cmd>>4)&0x0f;
        switch(len) {
          case 0x0b: len=0x0e; break;
          case 0x0d: len=0x10; break;
          case 0x0e: len=0x18; break;
          case 0x0f: len=0x20; break;
          }
        switch(cmd) {
          case 0x82: // signature
            if(!memcmp(signature,&buff[pos],8)) sigOk=true;
            pos=decrLen;
            break;
          case 0x90: // new primary key
            if(numKeys<sizeof(keyN)) {
              keyN[numKeys]=buff[pos] & 0x0f;
              key[numKeys]=&buff[pos+1];
              numKeys++;
              }
            break;
          }
        }
      char str[20],str2[20],str3[20];
      if(sigOk) {
        LBSTARTF(L_SYS_EMM);
        LBPUT("ID %s SA %s",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3));
        LBPUT(" - OK (CI ID %s SA %s KEY01 %s)",HexStr(str,ci->provId,2),HexStr(str2,ci->sa,3),HexStr(str3,ci->key,8));
        for(unsigned int i=0 ; i<numKeys ; i++) {
          Decrypt(key[i],MK,T1,T2);
          LBPUT(" KEY %02x %s",keyN[i],HexStr(str,key[i],8));
          FoundKey();
          if(keys.NewKey('S',provId,keyN[i],key[i],8)) NewKey();
         }
        LBEND();
        break;
        }
      else if(!CheckNull(ci->sa,sizeof(ci->sa)))
        PRINTF(L_SYS_EMM,"ID %s SA %s - FAIL",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3));
      }
    }
  return;
}

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