SASC
DVBSoftCAM

cSmartCardIrdeto Class Reference

Inheritance diagram for cSmartCardIrdeto:

List of all members.

Public Member Functions

 cSmartCardIrdeto (void)
virtual bool Init (void)
virtual bool Decode (const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
virtual bool Update (int pid, int caid, const unsigned char *data)
virtual bool CanHandle (unsigned short CaId)
 cSmartCardIrdeto (void)
virtual bool Init (void)
virtual bool Decode (const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
virtual bool Update (int pid, int caid, const unsigned char *data)
virtual bool CanHandle (unsigned short CaId)

Detailed Description

Definition at line 353 of file sc-irdeto.c.


Constructor & Destructor Documentation

cSmartCardIrdeto::cSmartCardIrdeto ( void  )

Definition at line 400 of file sc-irdeto.c.

:cSmartCard(&cardCfg,msgs)
{
  ACS=0; caId=0; numProv=0;
}
cSmartCardIrdeto::cSmartCardIrdeto ( void  )

Member Function Documentation

bool cSmartCardIrdeto::CanHandle ( unsigned short  CaId) [virtual]

Reimplemented from cSmartCard.

Definition at line 612 of file sc-irdeto.c.

{
  return (CaId==caId);
}
virtual bool cSmartCardIrdeto::CanHandle ( unsigned short  CaId) [virtual]

Reimplemented from cSmartCard.

bool cSmartCardIrdeto::Decode ( const cEcmInfo *  ecm,
const unsigned char *  data,
unsigned char *  cw 
) [virtual]

Implements cSmartCard.

Definition at line 617 of file sc-irdeto.c.

References cmd, cCamCrypt::RevCamCrypt(), SCT_LEN, and cSmartCard::Status().

{
  static const unsigned char ecmCmd[] = { 0x01,0x05,0x00,0x00,0x02,0x00 };

  int r=SCT_LEN(data)-6;
  if(r<=255) {
    unsigned char cmd[257+sizeof(ecmCmd)];
    memcpy(cmd,ecmCmd,sizeof(ecmCmd));
    cmd[5]=r;
    memcpy(cmd+sizeof(ecmCmd),&data[6],r);
    if((r=DoCmd(cmd,0x9D00))>0) {
      if(Status() && r>=31) {
        RevCamCrypt(camKey,&buff[14]);
        RevCamCrypt(camKey,&buff[22]);
        memcpy(cw,&buff[14],16);
        return true;
        }
      }
    }
  return false;
}
virtual bool cSmartCardIrdeto::Decode ( const cEcmInfo *  ecm,
const unsigned char *  data,
unsigned char *  cw 
) [virtual]

Implements cSmartCard.

virtual bool cSmartCardIrdeto::Init ( void  ) [virtual]

Implements cSmartCard.

bool cSmartCardIrdeto::Init ( void  ) [virtual]

Implements cSmartCard.

Definition at line 406 of file sc-irdeto.c.

References cProviders::AddProv(), cSmartCard::atr, cInfoStr::Begin(), cSmartCard::CaidsChanged(), cCamCrypt::CamKey(), cCamCrypt::EncryptCamMessage(), cSmartCardDataIrdeto::exp, cSmartCards::FindCardData(), cInfoStr::Finish(), cCamCrypt::HelperKey(), Atr::hist, Atr::histLen, i, cSmartCard::idStr, cSmartCard::infoStr, k, L_GEN_WARN, L_SC_ERROR, L_SC_INIT, LDUMP, cSmartCardDataIrdeto::mod, cSmartCardDataIrdeto::plain, cCamCrypt::PrepareCamMessage(), cLineBuff::Printf(), PRINTF, RECOVER_TIME, cIdSet::ResetIdSet(), cCamCrypt::RevCamCrypt(), SC_NAME, cTimeMs::Set(), cIdSet::SetCard(), cCamCrypt::SetupCardFiles(), smartcards, cSmartCard::Status(), cLineBuff::Strcat(), and strn0cpy().

{
  ResetIdSet();
  recoverTime.Set(-RECOVER_TIME);
  if(atr->histLen<6 || memcmp(atr->hist,"IRDETO",6)) {
    PRINTF(L_SC_INIT,"doesn't looks like a Irdeto/Beta card");
    return false;
    }

  infoStr.Begin();
  infoStr.Strcat("Irdeto smartcard\n");
  int r;
  static unsigned char getCountryCode[] = { 0x01,0x02,0x02,0x03,0x00,0x00,0xCC };
  if((r=DoCmd(getCountryCode,0x0000))<=0 || !Status() || r<16) {
    PRINTF(L_SC_ERROR,"country code error");
    return false;
    }
  ACS=buff[8]*256+buff[9];
  int c=buff[13]*256+buff[14];
  if(c!=caId) CaidsChanged();
  caId=c;
  memcpy(coco,&buff[21],3); coco[3]=0;
  PRINTF(L_SC_INIT,"ACS Version %04x, CAID %04x, CoCo %s",ACS,caId,coco);
  snprintf(idStr,sizeof(idStr),"%s (ACS %x)",SC_NAME,ACS);
  infoStr.Printf("ACS: %04x CAID: %04x CoCo: %s\n",ACS,caId,coco);

  static unsigned char getAsciiSerial[] = { 0x01,0x02,0x00,0x03,0x00,0x00,0xCC };
  if((r=DoCmd(getAsciiSerial,0x0000))<=0 || !Status() || r<10) {
    PRINTF(L_SC_ERROR,"ASCII serial error");
    return false;
    }
  strn0cpy(asciiSerial,(char*)buff+8,sizeof(asciiSerial));
  PRINTF(L_SC_INIT,"ASCII serial %s",asciiSerial);

  static unsigned char getHexSerial[] = { 0x01,0x02,0x01,0x03,0x00,0x00,0xCC };
  if((r=DoCmd(getHexSerial,0x0000))<=0 || !Status() || r<25) {
    PRINTF(L_SC_ERROR,"hex serial error");
    return false;
    }
  int numProv=buff[18];
  SetCard(new cCardIrdeto(buff[23],&buff[20]));
  PRINTF(L_SC_INIT,"Providers: %d HEX Serial: %02X%02X%02X  HEX Base: %02X",numProv,buff[20],buff[21],buff[22],buff[23]);
  infoStr.Printf("HEX: %02X/%02X%02X%02X ASCII: %s\n",buff[23],buff[20],buff[21],buff[22],asciiSerial);

  static unsigned char getCardFile[] = { 0x01,0x02,0x0E,0x02,0x00,0x00,0xCC };
  unsigned char encr[128], plain[64+6+2];
  PrepareCamMessage(plain+6);
  getCardFile[3]=0x02;
  if((r=DoCmd(getCardFile,0x0000))<=0 || !Status() || r<73) {
    PRINTF(L_SC_ERROR,"cardfile2 error");
    return false;
    }
  memcpy(encr,buff+8,64);
  getCardFile[3]=0x03;
  if((r=DoCmd(getCardFile,0x0000))<=0 || !Status() || r<73) {
    PRINTF(L_SC_ERROR,"cardfile3 error");
    return false;
    }
  memcpy(encr+64,buff+8,64);

  bool doPlain=false;
  if((ACS==0x0383 || ACS==0x0384) && atr->histLen>=12 && atr->hist[12]==0x95)
    doPlain=true;
  cSmartCardDataIrdeto *entry=0;
  if(!doPlain) {
    cSmartCardDataIrdeto cd(ACS,caId);
    if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) {
      PRINTF(L_GEN_WARN,"didn't find Irdeto card specific certificate, falling back to default");
      cSmartCardDataIrdeto cd(-1,-1);
      if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) {
        PRINTF(L_GEN_WARN,"didn't find default Irdeto certificate, please add one");
        if(ACS!=0x0384) return false;
        PRINTF(L_GEN_WARN,"trying pre-coded ACS 384 challenge. This mode is DEPRECATED. There ARE valid certificates for these cards available!");
        }
      }
    else doPlain=entry->plain;
    }
  static unsigned char doCamKeyExchange[] = { 0x01,0x02,0x09,0x03,0x00,0x40 };
  if(doPlain) {
    // plain challenge
    memcpy(plain,doCamKeyExchange,sizeof(doCamKeyExchange));
    plain[4]=1; // set block counter
    r=DoCmd(plain,0x5500,0x0000);
    }
  else {
    // RSA challenge
    if(entry) {
      if(!SetupCardFiles(encr,sizeof(encr),entry->exp,entry->mod)) {
        PRINTF(L_SC_ERROR,"decrypting cardfiles failed. Probably bad certificate.");
        return false;
        }
      if(!EncryptCamMessage(encr+6,plain+6)) {
        PRINTF(L_SC_ERROR,"encrypting CAM message failed. Probably bad certificate.");
        return false;
        }

      static unsigned char doRSACheck[] = { 0x01,0x02,0x11,0x00,0x00,0x40 };
      memcpy(plain,doRSACheck,sizeof(doRSACheck));
      if((r=DoCmd(plain,0x5800,0x0000))<=0 || !Status() || r<73) {
        PRINTF(L_SC_ERROR,"card didn't give a proper reply (buggy RSA unit?), trying to continue...");
        // non-fatal
        }
      if(r==73 && memcmp(encr+6,buff+8,64)) {
        PRINTF(L_SC_ERROR,"card failed on RSA check, trying to continue...");
        // non-fatal
        }
      }
    else {
      static const unsigned char enc384cz[] = {
        0x18,0xD7,0x55,0x14,0xC0,0x83,0xF1,0x38,  0x39,0x6F,0xF2,0xEC,0x4F,0xE3,0xF1,0x85,
        0x01,0x46,0x06,0xCE,0x7D,0x08,0x2C,0x74,  0x46,0x8F,0x72,0xC4,0xEA,0xD7,0x9C,0xE0,
        0xE1,0xFF,0x58,0xE7,0x70,0x0C,0x92,0x45,  0x26,0x18,0x4F,0xA0,0xE2,0xF5,0x9E,0x46,
        0x6F,0xAE,0x95,0x35,0xB0,0x49,0xB2,0x0E,  0xA4,0x1F,0x8E,0x47,0xD0,0x24,0x11,0xD0
        };
      static const unsigned char enc384dz[] = {
        0x27,0xF2,0xD6,0xCD,0xE6,0x88,0x62,0x46,  0x81,0xB0,0xF5,0x3E,0x6F,0x13,0x4D,0xCC,
        0xFE,0xD0,0x67,0xB1,0x93,0xDD,0xF4,0xDE,  0xEF,0xF5,0x3B,0x04,0x1D,0xE5,0xC3,0xB2,
        0x54,0x38,0x57,0x7E,0xC8,0x39,0x07,0x2E,  0xD2,0xF4,0x05,0xAA,0x15,0xB5,0x55,0x24,
        0x90,0xBB,0x9B,0x00,0x96,0xF0,0xCB,0xF1,  0x8A,0x08,0x7F,0x0B,0xB8,0x79,0xC3,0x5D
        };
      static const unsigned char ck[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 };
      static const unsigned char hk[] = { 0x12,0x34,0x56,0x78,0x90,0xAB,0xCD,0xEF };

      if(caId==0x1702) memcpy(encr+6,enc384cz,sizeof(enc384cz));
      else if(caId==0x1722) memcpy(encr+6,enc384dz,sizeof(enc384dz));
      else {
        PRINTF(L_GEN_WARN,"no pre-coded Irdeto camkey challenge for caid %04x",caId);
        return false;
        }
      memcpy((void *)CamKey(plain+6),ck,sizeof(ck));
      memcpy((void *)HelperKey(plain+6),hk,sizeof(hk));
      }

    memcpy(encr,doCamKeyExchange,sizeof(doCamKeyExchange));
    r=DoCmd(encr,0x5500,0x0000);
    }

  if(r>0 && Status() && r>=9) {
    memcpy(camKey,CamKey(plain+6),8);
    if(r>=17) {
      RevCamCrypt(camKey,buff+8);
      if(memcmp(HelperKey(plain+6),buff+8,8)) {
        PRINTF(L_SC_ERROR,"camkey challenge failed");
        return false;
        }
      }
    LDUMP(L_SC_INIT,camKey,sizeof(camKey),"camkey");
    }
  else {
    PRINTF(L_SC_ERROR,"camkey error");
    return false;
    }

  static unsigned char getProvider[]  = { 0x01,0x02,0x03,0x03,0x00,0x00,0xCC };
  static unsigned char getChanelIds[] = { 0x01,0x02,0x04,0x00,0x00,0x01,0x00,0xCC };
  for(int i=0; i<numProv; i++) {
    getProvider[4]=i;
    if((r=DoCmd(getProvider,0x0000))>0 && Status() && r>=33) {
      AddProv(new cProviderIrdeto(buff[8]&0x0f,&buff[9]));
      PRINTF(L_SC_INIT,"provider %d with ProvBase 0x%02x ProvId 0x%02x%02x%02x",i,buff[8]&0x0f,buff[9],buff[10],buff[11]);
      infoStr.Printf("Provider %d Id: %02X/%02X%02X%02X\n",i,buff[8]&0x0f,buff[9],buff[10],buff[11]);

      getChanelIds[4]=i;
      for(int l=0; l<10; l++) {
        getChanelIds[6]=l;
        if((r=DoCmd(getChanelIds,0x0000,0x5400))<=0 || !Status() || r<69) break;
        for(int k=0; k<buff[7]; k+=6) {
          int chanId=buff[k+8+0]*256+buff[k+8+1];
          int date  =buff[k+8+2]*256+buff[k+8+3];
          int durr  =buff[k+8+4];
          if(chanId!=0x0000 && chanId!=0xFFFF) {
            char sdate[16], edate[16];
            Date(date,sdate,sizeof(sdate));
            Date(date+durr,edate,sizeof(edate));
            PRINTF(L_SC_INIT,"ChanId 0x%04x Date 0x%04x %s Duration 0x%02x %s",chanId,date,sdate,durr,edate);
            infoStr.Printf("ChanId: %04X Date: %s-%s\n",chanId,sdate,edate);
            }
          }
        }
      }
    }

#if 0
  static unsigned char getCountryCode2[] = { 0x01,0x02,0x0B,0x00,0x00,0x00,0xCC };
  if((r=DoCmd(getCountryCode2,0x0000))>0 && Status() && r>=32) {
    PRINTF(L_SC_INIT,"max ChID's %d,%d,%d,%d",buff[14],buff[15],buff[16],buff[17]);
    }
#endif

  infoStr.Finish();
  return true;
}
bool cSmartCardIrdeto::Update ( int  pid,
int  caid,
const unsigned char *  data 
) [virtual]

Reimplemented from cSmartCard.

Definition at line 639 of file sc-irdeto.c.

References ADDRLEN, cParseIrdeto::AddrLen(), cmd, L_SC_ERROR, cIdSet::MatchEMM(), PRINTF, SCT_LEN, and cSmartCard::Status().

{
  static const unsigned char emmCmd[] = { 0x01,0x01,0x00,0x00,0x00,0x00 };

  if(MatchEMM(data)) {
    int len=cParseIrdeto::AddrLen(data)+1;
    if(len<=ADDRLEN) {
      const int dataLen=SCT_LEN(data)-5-len; // sizeof of data bytes (nanos)
      if(dataLen<=255-ADDRLEN) {
        unsigned char cmd[257+sizeof(emmCmd)];
        memcpy(cmd,emmCmd,sizeof(emmCmd));
        cmd[5]=dataLen+ADDRLEN;
        memset(cmd+sizeof(emmCmd),0,ADDRLEN);
        memcpy(cmd+sizeof(emmCmd),&data[3],len);
        memcpy(cmd+sizeof(emmCmd)+ADDRLEN,&data[len+5],dataLen);
        if(DoCmd(cmd,0x0000)>0 && Status()) return true;
        }
      }
    else PRINTF(L_SC_ERROR,"addrlen %d > %d",len,ADDRLEN);
    }
  return false;
}
virtual bool cSmartCardIrdeto::Update ( int  pid,
int  caid,
const unsigned char *  data 
) [virtual]

Reimplemented from cSmartCard.


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