📄 sc-nagra.c
字号:
#define HAS_CW ((status[1]&1)&&((status[3]&6)==6))class cSmartCardNagra : public cSmartCard, private cCamCryptNagra {private: unsigned char buff[MAX_LEN+1], status[4], cardId[4], irdId[4], block; unsigned short provId[MAX_REC], irdProvId; // bool GetCardStatus(void); bool GetDataType(unsigned char dt, int len, int shots=MAX_REC); bool ParseDataType(unsigned char dt); bool DoCamExchange(const unsigned char *key); void Date(const unsigned char *date, char *dt, char *ti); bool DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, int rlen, const unsigned char *data=0); bool SetIFS(unsigned char len);public: cSmartCardNagra(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); };static const struct StatusMsg msgs[] = { { { 0x6F,0x00 }, "Instruction not supported", false }, { { 0x90,0x00 }, "Instruction executed without errors", true }, { { 0xFF,0xFF }, 0, false } };static const struct CardConfig cardCfg = { SM_8O2,500,800 };cSmartCardNagra::cSmartCardNagra(void):cSmartCard(&cardCfg,msgs){ block=0;}bool cSmartCardNagra::SetIFS(unsigned char size){ unsigned char buf[5]; // NAD, PCB, LEN NAD(buf)=N2_NAD; PCB(buf)=SETIFS; LEN(buf)=1; // Information Field size buf[3]=size; buf[4]=XorSum(buf,4); if(SerWrite(buf,5)!=5) { PRINTF(L_SC_ERROR,"failed to write IFS command"); return false; } if(SerRead(buff,5,cardCfg.workTO)!=5 || XorSum(buff,5)) { PRINTF(L_SC_ERROR,"setting IFS to %02x failed",size); return false; } return true;}bool cSmartCardNagra::GetCardStatus(void){ if(!DoBlkCmd(0xC0,0x02,0xB0,0x06) || !Status()) { PRINTF(L_SC_ERROR,"failed to read card status"); return false; } memcpy(status,buff+5,4); return true;}bool cSmartCardNagra::Init(void){ static const unsigned char verifyBytes[] = { 'D','N','A','S','P','1' }; if(atr->T!=1 || (atr->histLen<8 && memcmp(atr->hist,verifyBytes,sizeof(verifyBytes)))) { PRINTF(L_SC_INIT,"doesn't look like a nagra V2 card"); return false; } infoStr.Begin(); infoStr.Strcat("Nagra smartcard\n"); char rom[12], rev[12]; snprintf(rom,sizeof(rom),"%.3s",(char*)&atr->hist[5]); snprintf(rev,sizeof(rev),"%.3s",(char*)&atr->hist[12]); PRINTF(L_SC_INIT,"card version: %s revision: %s",rom,rev); infoStr.Printf("Card v.%s Rev.%s\n",rom,rev); if(!GetCardStatus() || !SetIFS(0x80)) return false; // get UA/CardID here if(!DoBlkCmd(0x12,0x02,0x92,0x06) || !Status()) return false; memcpy(cardId,buff+5,4); if(!GetDataType(IRDINFO,0x39) || !GetDataType(0x04,0x44)) return false; infoStr.Printf("Tiers\n"); infoStr.Printf("|id |tier low|tier high| dates |\n"); infoStr.Printf("+----+--------+---------+----------+\n"); if(!GetDataType(TIERS,0x57)) PRINTF(L_SC_ERROR,"failed to get tiers"); if(!GetDataType(CAMDATA,0x55,1)) return false; unsigned char key[16]; cSmartCardDataNagra *entry=0; bool sessOk=false; if(buff[5]!=0 && irdProvId==((buff[10]*256)|buff[11])) { // prepare DT08 data cSmartCardDataNagra cd(irdProvId,true); if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find smartcard Nagra IRD modulus"); } else { InitCamKey(key,entry->bk,irdId); if(DecryptCamMod(buff+3,key,cardId,entry->mod)) sessOk=true; } } else { cSmartCardDataNagra cd(irdProvId); if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) { PRINTF(L_GEN_WARN,"didn't find smartcard Nagra CAM modulus"); } else { InitCamKey(key,entry->bk,cardId); SetCamMod(entry->mod); if(GetDataType(0x08,0x03,1)) sessOk=true;; } } if(sessOk) DoCamExchange(key); infoStr.Finish(); return true;}bool cSmartCardNagra::GetDataType(unsigned char dt, int len, int shots){ for(int i=0; i<shots; i++) { if(!DoBlkCmd(0x22,0x03,0xA2,len,&dt) || !Status()) { PRINTF(L_SC_ERROR,"failed to get datatype %02X",dt); return false; } if(buff[5]==0) return true; if(!ParseDataType(dt&0x0F)) return false; dt|=0x80; // get next item } return true;}bool cSmartCardNagra::ParseDataType(unsigned char dt){ switch(dt) { case IRDINFO: { irdProvId=(buff[10]*256)|buff[11]; char id[12]; memcpy(irdId,buff+17,4); LDUMP(L_SC_INIT,irdId,4,"IRD system-ID: %04X, IRD ID:",irdProvId); HexStr(id,irdId,sizeof(irdId)); infoStr.Printf("IRD system-ID: %04X\nIRD ID: %s\n",irdProvId,id); return true; } case TIERS: if(buff[7]==0x88 || buff[7]==0x08 || buff[7]==0x0C) { int id=(buff[10]*256)|buff[11]; int tLowId=(buff[20]*256)|buff[21]; int tHiId=(buff[31]*256)|buff[32]; char date1[12], time1[12], date2[12], time2[12]; Date(buff+23,date1,time1); Date(buff+27,date2,time2); infoStr.Printf("|%04X|%04X |%04X |%s|\n",id,tLowId,tHiId,date1); infoStr.Printf("| | | |%s|\n",date2); PRINTF(L_SC_INIT,"|%04X|%04X|%04X|%s|%s|",id,tLowId,tHiId,date1,time1); PRINTF(L_SC_INIT,"| | | |%s|%s|",date2,time2); } default: return true; } return false;}bool cSmartCardNagra::DoCamExchange(const unsigned char *key){ if(!GetCardStatus()) return false; if(!DoBlkCmd(0x2A,0x02,0xAA,0x42) || !Status()) return false; if(buff[4]!=64) { PRINTF(L_SC_ERROR,"reading CAM 2A data failed"); return false; } unsigned char res[64]; if(!DecryptCamData(res,key,buff+5)) return false; if(!DoBlkCmd(0x2B,0x42,0xAB,0x02,res) || !Status()) return false; return true;}void cSmartCardNagra::Date(const unsigned char *data, char *dt, char *ti){ int date=(data[0]<<8)|data[1]; int time=(data[2]<<8)|data[3]; struct tm t; memset(&t,0,sizeof(struct tm)); t.tm_min =0;//-300; t.tm_year=92; t.tm_mday=date + 1; t.tm_sec =(time - 1) * 2; mktime(&t); snprintf(dt,11,"%.2d.%.2d.%.4d",t.tm_mon+1,t.tm_mday,t.tm_year+1900); snprintf(ti,9,"%.2d:%.2d:%.2d",t.tm_hour,t.tm_min,t.tm_sec);}bool cSmartCardNagra::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw){ if(DoBlkCmd(data[3],data[4]+2,0x87,0x02,data+3+2) && Status()) { cCondWait::SleepMs(100); if(GetCardStatus() && HAS_CW && DoBlkCmd(0x1C,0x02,0x9C,0x36) && Status() && DecryptCW(cw,buff)) return true; } return false;}bool cSmartCardNagra::Update(int pid, int caid, const unsigned char *data){ if(DoBlkCmd(data[8],data[9]+2,0x84,0x02,data+8+2) && Status()) { cCondWait::SleepMs(500); if(GetCardStatus()) return true; } return false;}bool cSmartCardNagra::DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, int rlen, const unsigned char *data){ unsigned char msg[MAX_LEN+3+1]; NAD(msg)=N2_NAD; PCB(msg)=0; PCB(msg)^=block; block^=0x40; LEN(msg)=ilen+6; CLA(msg)=N2_CLA; INS(msg)=N2_INS; P1(msg)=N2_P1; P2(msg)=N2_P2; L(msg)=ilen; int dlen=ilen-2; if(dlen<0) { PRINTF(L_SC_ERROR,"invalid data length encountered"); return false; } N2_CMD(msg)=cmd; N2_CLEN(msg)=dlen; if(data && dlen>0) memcpy(&N2_DATA(msg),data,dlen); int msglen=LEN(msg)+3; msg[msglen-1]=rlen; msg[msglen]=XorSum(msg,msglen); msglen++; if(SerWrite(msg,msglen)==msglen) { LDUMP(L_CORE_SC,msg,msglen,"NAGRA: <-"); cCondWait::SleepMs(10); if(SerRead(buff,3,cardCfg.workTO)!=3) { PRINTF(L_SC_ERROR,"reading back reply failed"); return false; } int reslen=buff[2]+1; if(SerRead(buff+3,reslen,cardCfg.workTO)!=reslen) { PRINTF(L_SC_ERROR,"reading back information block failed"); return false; } if(XorSum(buff,reslen+3)) { PRINTF(L_SC_ERROR,"checksum failed"); return false; } LDUMP(L_CORE_SC,buff,3+reslen,"NAGRA: ->"); if(buff[3]!=res) { PRINTF(L_SC_ERROR,"result not expected (%02X != %02X)",buff[3],res); return false; } memcpy(sb,&buff[3+rlen],2); LDUMP(L_CORE_SC,sb,2,"NAGRA: ->"); cCondWait::SleepMs(10); return true; } return false;}// -- cSmartCardLinkNagra -------------------------------------------------------------class cSmartCardLinkNagra : public cSmartCardLink {public: cSmartCardLinkNagra(void):cSmartCardLink(SC_NAME,SC_ID) {} virtual cSmartCard *Create(void) { return new cSmartCardNagra(); } virtual cSmartCardData *CreateData(void) { return new cSmartCardDataNagra; } };static cSmartCardLinkNagra staticScInit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -