#include "system-common.h"
#include "smartcard.h"
+#include "parse.h"
#include "crypto.h"
#include "helper.h"
+#include "opts.h"
#include "log-sc.h"
#include "log-core.h"
#include "version.h"
};
ADD_MODULE(L_SC,lm_sc)
+static int allowT14=0;
+
// -- cSystemScNagra ---------------------------------------------------------------------
class cSystemScNagra : public cSystemScCore {
cSystemLinkScNagra::cSystemLinkScNagra(void)
:cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
{
+ opts=new cOpts(SYSTEM_NAME,1);
+ opts->Add(new cOptBool("AllowT14",trNOOP("SC-Nagra: use T14 Nagra mode"),&allowT14));
Feature.NeedsSmartCard();
}
bool cSystemLinkScNagra::CanHandle(unsigned short SysId)
{
- return smartcards.HaveCard(SC_ID) && ((SysId&SYSTEM_MASK)==SYSTEM_NAGRA && (SysId&0xFF)>0);
+ bool res=false;
+ cSmartCard *card=smartcards.LockCard(SC_ID);
+ if(card) {
+ res=card->CanHandle(SysId);
+ smartcards.ReleaseCard(card);
+ }
+ return res;
}
// -- cCamCryptNagra ------------------------------------------------------------------
cIDEA idea;
cRSA rsa;
cBN camMod, camExp;
+ IdeaKS sessKey;
+ unsigned char cardid[4], boxkey[8], signature[8];
bool hasMod;
- unsigned char sk[16];
//
+ void InitKey(unsigned char *key, const unsigned char *bk, const unsigned char *data);
void Signature(unsigned char *sig, const unsigned char *key, const unsigned char *msg, int len);
public:
cCamCryptNagra(void);
- void InitCamKey(unsigned char *key, const unsigned char *bk, const unsigned char *data);
+ void SetCardData(const unsigned char *id, const unsigned char *bk);
void SetCamMod(BIGNUM *m);
- bool DecryptCamMod(const unsigned char *dt08, const unsigned char *key, const unsigned char *key2, BIGNUM *m);
- bool DecryptCamData(unsigned char *out, const unsigned char *key, const unsigned char *in);
- bool DecryptCW(unsigned char *dcw, const unsigned char *in);
+ bool HasCamMod(void) { return hasMod; }
+ bool DecryptDT08(const unsigned char *dt08, const unsigned char *irdid, BIGNUM *irdmod);
+ bool MakeSessionKey(unsigned char *out, const unsigned char *in);
+ void DecryptCW(unsigned char *cw, const unsigned char *ecw1, const unsigned char *ecw2);
};
cCamCryptNagra::cCamCryptNagra(void)
BN_set_word(camExp,3);
}
-void cCamCryptNagra::Signature(unsigned char *sig, const unsigned char *key, const unsigned char *msg, int len)
+void cCamCryptNagra::SetCardData(const unsigned char *id, const unsigned char *bk)
{
- unsigned char buff[16];
- memcpy(buff,key,16);
- for(int i=0; i<len; i+=8) {
- IdeaKS ks;
- idea.SetEncKey(buff,&ks);
- idea.Encrypt(msg+i,8,buff,&ks,0);
- xxor(buff,8,buff,&msg[i]);
- //for(int j=7; j>=0; j--) buff[j]^=msg[i+j];
- memcpy(&buff[8],buff,8);
- }
- memcpy(sig,buff,8);
+ memcpy(cardid,id,sizeof(cardid));
+ memcpy(boxkey,bk,sizeof(boxkey));
}
-void cCamCryptNagra::InitCamKey(unsigned char *key, const unsigned char *bk, const unsigned char *data)
+void cCamCryptNagra::SetCamMod(BIGNUM *m)
+{
+ BN_copy(camMod,m);
+ memcpy(signature,boxkey,sizeof(signature));
+ hasMod=true;
+}
+
+void cCamCryptNagra::InitKey(unsigned char *key, const unsigned char *bk, const unsigned char *data)
{
memcpy(key,bk,8);
int d=UINT32_LE(data);
//for(int i=0; i<4; i++) key[i+12]=~data[i];
}
-void cCamCryptNagra::SetCamMod(BIGNUM *m)
+void cCamCryptNagra::Signature(unsigned char *sig, const unsigned char *key, const unsigned char *msg, int len)
{
- BN_copy(camMod,m);
- hasMod=true;
+ unsigned char buff[16];
+ memcpy(buff,key,16);
+ for(int i=0; i<len; i+=8) {
+ idea.Decrypt(msg+i,8,buff,buff,0);
+ xxor(buff,8,buff,&msg[i]);
+ memcpy(&buff[8],buff,8);
+ }
+ memcpy(sig,buff,8);
}
-bool cCamCryptNagra::DecryptCamMod(const unsigned char *dt08, const unsigned char *key, const unsigned char *cardid, BIGNUM *m)
+bool cCamCryptNagra::DecryptDT08(const unsigned char *dt08, const unsigned char *irdid, BIGNUM *irdmod)
{
unsigned char buff[72];
- if(rsa.RSA(buff,dt08+13,64,camExp,m)!=64) return false;
- memcpy(buff+64,dt08+13+64,8);
- buff[63]|=dt08[12]&0x80;
+ if(rsa.RSA(buff,dt08+1,64,camExp,irdmod)!=64) return false;
+ memcpy(buff+64,dt08+1+64,8);
+ buff[63]|=dt08[0]&0x80;
+ LDUMP(L_SC_PROC,buff,72,"DT08 after RSA");
+
+ unsigned char key[16];
+ InitKey(key,boxkey,irdid);
+ LDUMP(L_SC_PROC,key,16,"DT08 IDEA key");
IdeaKS dks;
idea.SetDecKey(key,&dks);
idea.Decrypt(buff,72,&dks,0);
- unsigned char sig[8];
- memcpy(sig,buff,8);
+ LDUMP(L_SC_PROC,buff,72,"DT08 after IDEA");
+ memcpy(signature,buff,8);
+ LDUMP(L_SC_PROC,signature,8,"signature");
memset(buff+0,0,4);
memcpy(buff+4,cardid,4);
Signature(buff,key,buff,72);
- BN_bin2bn(buff+8,64,camMod);
- if(memcmp(sig,buff,8)) {
- PRINTF(L_SC_PROC,"DT08 signature failed. Check boxkey/IRD modulus");
+ LDUMP(L_SC_PROC,buff,8,"check sig");
+ if(memcmp(signature,buff,8)) {
+ PRINTF(L_SC_PROC,"DT08 signature failed");
return false;
}
+ BN_bin2bn(buff+8,64,camMod);
hasMod=true;
return true;
}
-bool cCamCryptNagra::DecryptCamData(unsigned char *out, const unsigned char *key, const unsigned char *camdata)
+bool cCamCryptNagra::MakeSessionKey(unsigned char *out, const unsigned char *camdata)
{
if(!hasMod) return false;
//decrypt $2A data here and prepare $2B reply
if(rsa.RSA(out,camdata,64,camExp,camMod)!=64) return false;
- Signature(sk,key,out,32);
- memcpy(sk+8,sk,8);
- Signature(sk+8,sk,out,32);;
+ LDUMP(L_SC_PROC,out,64,"CMD 2A after RSA");
+
+ unsigned char key[16], sess[16];
+ InitKey(key,signature,cardid);
+ LDUMP(L_SC_PROC,key,16,"first IDEA key");
+ Signature(sess,key,out,32);
+ memcpy(key,sess,8);
+ memcpy(key+8,sess,8);
+ LDUMP(L_SC_PROC,key,16,"second IDEA key");
+ Signature(sess+8,key,out,32);
+ LDUMP(L_SC_PROC,sess,16,"SESSION KEY");
+ idea.SetDecKey(sess,&sessKey);
+
if(rsa.RSA(out,out,64,camExp,camMod)!=64) return false;
- LDUMP(L_SC_PROC,sk,16,"established session key ->");
+ LDUMP(L_SC_PROC,out,64,"CMD 2B data");
return true;
}
-bool cCamCryptNagra::DecryptCW(unsigned char *dcw, const unsigned char *ecw)
+void cCamCryptNagra::DecryptCW(unsigned char *cw, const unsigned char *ecw1, const unsigned char *ecw2)
{
- const int nCw=ecw[4]/2;
- if(nCw<10) return false;
- IdeaKS ks;
- ecw+=5;
- idea.SetDecKey(sk,&ks);
- memcpy(dcw+8,ecw +2,8);
- memcpy(dcw+0,ecw+nCw+2,8);
- idea.Decrypt(dcw+0,8,&ks,0);
- idea.Decrypt(dcw+8,8,&ks,0);
- return true;
+ memcpy(cw+0,ecw1,8);
+ idea.Decrypt(cw+0,8,&sessKey,0);
+ memcpy(cw+8,ecw2,8);
+ idea.Decrypt(cw+8,8,&sessKey,0);
}
// -- cSmartCardDataNagra ------------------------------------------------------
class cSmartCardDataNagra : public cSmartCardData {
public:
- bool global;
- int provId;
- unsigned char bk[8];
+ unsigned char cardid[4], bk[8];
cBN mod;
+ bool isIrdMod;
//
cSmartCardDataNagra(void);
- cSmartCardDataNagra(int ProvId, bool Global);
+ cSmartCardDataNagra(const unsigned char *id, bool irdmod);
virtual bool Parse(const char *line);
virtual bool Matches(cSmartCardData *param);
};
cSmartCardDataNagra::cSmartCardDataNagra(void)
:cSmartCardData(SC_ID) {}
-cSmartCardDataNagra::cSmartCardDataNagra(int ProvId, bool Global=false)
+cSmartCardDataNagra::cSmartCardDataNagra(const unsigned char *id, bool irdmod)
:cSmartCardData(SC_ID)
{
- provId=ProvId; global=Global;
+ memcpy(cardid,id,sizeof(cardid));
+ isIrdMod=irdmod;
}
bool cSmartCardDataNagra::Matches(cSmartCardData *param)
{
cSmartCardDataNagra *cd=(cSmartCardDataNagra *)param;
- return (cd->provId==provId) && (cd->global==global);
+ return !memcmp(cd->cardid,cardid,sizeof(cardid) && cd->isIrdMod==isIrdMod);
}
bool cSmartCardDataNagra::Parse(const char *line)
{
- unsigned char buff[512];
line=skipspace(line);
- if(*line++!='[' || GetHex(line,buff,2)!=2 || *(line=skipspace(line))!=']' ) {
- PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: provider id");
+ if(GetHex(line,cardid,sizeof(cardid))!=sizeof(cardid)) {
+ PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: card id");
return false;
}
- provId=buff[0]*256+buff[1];
- line=skipspace(line+1);
- if(!strncasecmp(line,"IRDMOD",6)) {
- global=true;
- line+=6;
- }
- if(GetHex(line,bk,sizeof(bk),false)<=0) {
+ if(GetHex(line,bk,sizeof(bk))!=sizeof(bk)) {
+ line=skipspace(line);
PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: boxkey");
return false;
}
- int l=GetHex(line,buff,sizeof(buff),false);
- if(l!=64) {
- PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: %s",global?"IRDMOD":"CAMMOD");
+ line=skipspace(line);
+ if(!strncasecmp(line,"IRDMOD",6)) { isIrdMod=true; line+=6; }
+ else if(!strncasecmp(line,"CARDMOD",7)) { isIrdMod=false; line+=7; }
+ else {
+ PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: IRDMOD/CARDMOD");
return false;
}
- BN_bin2bn(buff,l,mod);
+ line=skipspace(line);
+ unsigned char buff[72];
+ if(GetHex(line,buff,64)!=64) {
+ PRINTF(L_CORE_LOAD,"smartcarddatanagra: format error: modulus");
+ return false;
+ }
+ BN_bin2bn(buff,64,mod);
return true;
}
// -- cSmartCardNagra -----------------------------------------------------------------
-// ISO 7816 T=1 defines
-#define NAD(a) (a[0])
-#define PCB(a) (a[1])
-#define LEN(a) (a[2])
-#define CLA(a) (a[3])
-#define INS(a) (a[4])
-#define P1(a) (a[5])
-#define P2(a) (a[6])
-#define L(a) (a[7])
-
-// Nagra NAD and reply NAD
-#define N2_NAD 0x21
-#define N2_R_NAD sn8(N2_NAD)
-#define N2_CLA 0xA0
-#define N2_INS 0xCA
-#define N2_P1 0x00
-#define N2_P2 0x00
-#define N2_CMD(a) (a[8])
-#define N2_CLEN(a) (a[9])
-#define N2_DATA(a) (a[10])
-
#define SETIFS 0xC1
-#define CAMDATA 0x08
// Datatypes
#define IRDINFO 0x00
+#define DT01 0x01
+#define DT04 0x04
#define TIERS 0x05
+#define DT06 0x06
+#define CAMDATA 0x08
+
#define MAX_REC 20
// Card Status checks
-#define HAS_CW ((status[1]&1)&&((status[3]&6)==6))
+#define HAS_CW() ((state[2]&6)==6)
+#define RENEW_SESSIONKEY() (state[0]&224)
+#define SENDDATETIME() (state[0]&16)
-class cSmartCardNagra : public cSmartCard, private cCamCryptNagra {
+class cSmartCardNagra : public cSmartCard, public cIdSet, private cCamCryptNagra {
private:
- unsigned char buff[MAX_LEN+1], status[4], cardId[4], irdId[4], block;
- unsigned short provId[MAX_REC], irdProvId;
+ unsigned char buff[MAX_LEN+16], state[3], cardId[4], irdId[4], rominfo[15];
+ int caid, provId, block;
+ bool isTiger, isT14Nagra, swapCW;
//
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 DoCamExchange(void);
+ bool SendDateTimeCmd(void);
+ time_t Date(const unsigned char *data, char *buf, int len);
bool DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, int rlen, const unsigned char *data=0);
bool SetIFS(unsigned char len);
public:
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);
};
static const struct StatusMsg msgs[] = {
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;
+ buf[0]=0x21; buf[1]=0xC1; buf[2]=0x01;
// Information Field size
buf[3]=size; buf[4]=XorSum(buf,4);
if(SerWrite(buf,5)!=5) {
PRINTF(L_SC_ERROR,"failed to read card status");
return false;
}
- memcpy(status,buff+5,4);
+ memcpy(state,buff+6,3);
return true;
}
+bool cSmartCardNagra::CanHandle(unsigned short CaId)
+{
+ return CaId==caid;
+}
+
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");
+ block=0; isTiger=isT14Nagra=swapCW=false;
+ caid=SYSTEM_NAGRA;
+ ResetIdSet();
+
+ static const unsigned char atrDNASP[] = { 'D','N','A','S','P' };
+ static const unsigned char atrTIGER[] = { 'T','I','G','E','R' };
+ static const unsigned char atrIRDET[] = { 'I','R','D','E','T','O' };
+ if(!memcmp(atr->hist,atrDNASP,sizeof(atrDNASP))) {
+ PRINTF(L_SC_INIT,"detected native T1 nagra card");
+ //if(!SetIFS(0xFE)) return false;
+ memcpy(rominfo,atr->hist,sizeof(rominfo));
+ }
+ else if(!memcmp(atr->hist,atrTIGER,sizeof(atrTIGER))) {
+ PRINTF(L_SC_INIT,"detected nagra tiger card");
+ //if(!SetIFS(0xFE)) return false;
+ memcpy(rominfo,atr->hist,sizeof(rominfo));
+ memset(cardId,0xFF,sizeof(cardId));
+ isTiger=true;
+ }
+ else if(!memcmp(atr->hist,atrIRDET,sizeof(atrIRDET))) {
+ PRINTF(L_SC_INIT,"detected tunneled T14 nagra card");
+ if(!allowT14) {
+ PRINTF(L_SC_INIT,"Nagra mode for T14 card disabled in setup");
+ return false;
+ }
+ PRINTF(L_SC_INIT,"using nagra mode");
+ isT14Nagra=true;
+ if(!DoBlkCmd(0x10,0x02,0x90,0x11)) {
+ PRINTF(L_SC_ERROR,"get rom version failed");
+ return false;
+ }
+ memcpy(rominfo,&buff[2],15);
+ }
+ else {
+ PRINTF(L_SC_INIT,"doesn't look like a nagra 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;
+ snprintf(rom,sizeof(rom),"%c%c%c%c%c%c%c%c",rominfo[0],rominfo[1],rominfo[2],rominfo[3],rominfo[4],rominfo[5],rominfo[6],rominfo[7]);
+ snprintf(rev,sizeof(rev),"%c%c%c%c%c%c",rominfo[9],rominfo[10],rominfo[11],rominfo[12],rominfo[13],rominfo[14]);
+ PRINTF(L_SC_INIT,"rom version: %s revision: %s",rom,rev);
+ infoStr.Printf("Rom %s Rev %s\n",rom,rev);
+
+ if(!isTiger) {
+ GetCardStatus();
+ if(!DoBlkCmd(0x12,0x02,0x92,0x06) || !Status()) return false;
+ memcpy(cardId,buff+5,4);
+
+ if(!GetDataType(DT01,0x0E)) return false;
+ GetCardStatus();
+ if(!GetDataType(IRDINFO,0x39)) return false;
+ GetCardStatus();
+ if(!GetDataType(CAMDATA,0x55,0x10)) return false;
+ GetCardStatus();
+ if(!GetDataType(DT04,0x44)) return false;
+ GetCardStatus();
+ if(!memcmp(rominfo+5,"181",3)) {
+ infoStr.Printf("Tiers\n");
+ infoStr.Printf("|id |chid| dates |\n");
+ infoStr.Printf("+----+----+---------------------+\n");
+ if(!GetDataType(TIERS,0x57)) return false;
+ GetCardStatus();
+ }
+ if(!GetDataType(DT06,0x16)) return false;
+ GetCardStatus();
+ }
+ SetCard(new cCardNagra2(cardId));
- 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");
+ if(!HasCamMod()) {
+ cSmartCardDataNagra cd(cardId,false);
+ cSmartCardDataNagra *entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd);
+ if(entry) {
+ SetCardData(cardId,entry->bk);
+ SetCamMod(entry->mod);
}
else {
- InitCamKey(key,entry->bk,irdId);
- if(DecryptCamMod(buff+3,key,cardId,entry->mod)) sessOk=true;
+ PRINTF(L_SC_ERROR,"can't find CARD modulus");
+ return false;
}
}
+ if(!DoCamExchange()) return false;
+ infoStr.Finish();
+ return true;
+}
+
+bool cSmartCardNagra::DoCamExchange(void)
+{
+ if(!isTiger) {
+ if(!DoBlkCmd(0x2A,0x02,0xAA,0x42) || !Status()) return false;
+ }
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;;
+ static const unsigned char d1[] = { 0xd2 };
+ if(!DoBlkCmd(0xD1,0x03,0x51,0x42,d1) || !Status()) return false;
+ }
+ unsigned char res[64];
+ if(!MakeSessionKey(res,buff+5)) return false;
+ if(!isTiger) {
+ if(!DoBlkCmd(0x2B,0x42,0xAB,0x02,res) ||
+ !Status() ||
+ !GetCardStatus()) return false;
+ if(SENDDATETIME())
+ SendDateTimeCmd();
+ if(RENEW_SESSIONKEY()) {
+ PRINTF(L_SC_ERROR,"Session key negotiation failed!");
+ return false;
}
}
- if(sessOk) DoCamExchange(key);
- infoStr.Finish();
+ else {
+ if(!DoBlkCmd(0xD2,0x42,0x52,0x03,res) || !Status()) return false;
+ }
+ return true;
+}
+
+bool cSmartCardNagra::SendDateTimeCmd(void)
+{
+ DoBlkCmd(0xC8,0x02,0xB8,0x06);
return true;
}
bool cSmartCardNagra::GetDataType(unsigned char dt, int len, int shots)
{
+ bool isdt8 = (dt==0x08);
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(buff[5]==0 && !isdt8) break;
if(!ParseDataType(dt&0x0F)) return false;
+ if(isdt8 && buff[14]==0x49) break;
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;
+ case IRDINFO:
+ {
+ provId=(buff[10]*256)|buff[11];
+ caid=SYSTEM_NAGRA+buff[14];
+ memcpy(irdId,buff+17,4);
+ char id[12];
+ LDUMP(L_SC_INIT,irdId,4,"CAID: %04X PROV: %04X, IRD ID:",caid,provId);
+ HexStr(id,irdId,sizeof(irdId));
+ infoStr.Printf("CAID: %04X PROV: %04X\nIRD ID: %s\n",caid,provId,id);
+ break;
+ }
+ case TIERS:
+ {
+ int chid=(buff[14]*256)|buff[15];
+ if(chid) {
+ int id=(buff[10]*256)|buff[11];
+ char ds[16], de[16];
+ Date(buff+23,ds,sizeof(ds));
+ Date(buff+16,de,sizeof(de));
+ infoStr.Printf("|%04X|%04X|%s-%s|\n",id,chid,ds,de);
+ PRINTF(L_SC_INIT,"|%04X|%04X|%s-%s|",id,chid,ds,de);
+ }
+ break;
+ }
+ case CAMDATA:
+ if(buff[14]==0x49) {
+ cSmartCardDataNagra cd(cardId,true);
+ cSmartCardDataNagra *entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd);
+ if(entry) {
+ SetCardData(cardId,entry->bk);
+ return DecryptDT08(buff+15,irdId,entry->mod);
+ }
+ else {
+ PRINTF(L_SC_ERROR,"can't find IRD modulus");
+ return false;
+ }
+ }
+ break;
}
- 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)
+time_t cSmartCardNagra::Date(const unsigned char *data, char *buf, int len)
{
- 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);
+ int day=((data[0]<<8)|data[1])-0x7f7;
+ time_t ut=870393600L+day*(24*3600);
+ if(buf) {
+ struct tm rt;
+ struct tm *t=gmtime_r(&ut,&rt);
+ if(t) snprintf(buf,len,"%04d/%02d/%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday);
+ else buf[0]=0;
+ }
+ return ut;
}
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;
+ if(!isTiger) {
+ if(!DoBlkCmd(data[3],data[4]+2,0x87,0x02,data+3+2) || !Status()) {
+ PRINTF(L_SC_ERROR,"ECM cmd failed, retrying");
+ if(!DoBlkCmd(data[3],data[4]+2,0x87,0x02,data+3+2) || !Status()) {
+ PRINTF(L_SC_ERROR,"ECM cmd failed");
+ return false;
+ }
+ }
+ cCondWait::SleepMs(5);
+ for(int retry=0; !GetCardStatus() && retry<5; retry++) cCondWait::SleepMs(5);
+ cCondWait::SleepMs(5);
+ if(HAS_CW() && DoBlkCmd(0x1C,0x02,0x9C,0x36) && Status()) {
+ DecryptCW(cw,buff+33,buff+7);
+ if(swapCW) {
+ unsigned char tt[8];
+ memcpy(&tt[0],&cw[0],8);
+ memcpy(&cw[0],&cw[8],8);
+ memcpy(&cw[8],&tt[0],8);
+ }
+ return true;
+ }
+ }
+ else {
+ if(DoBlkCmd(0xD3,data[4]+2,0x53,0x16,data+3+2)) {
+ DecryptCW(cw,buff+17,buff+9);
+ 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;
+ if(MatchEMM(data)) {
+ if(DoBlkCmd(data[8],data[9]+2,0x84,0x02,data+8+2) && Status()) {
+ cCondWait::SleepMs(300);
+ GetCardStatus();
+ cCondWait::SleepMs(10);
+ if(RENEW_SESSIONKEY()) DoCamExchange();
+ if(SENDDATETIME()) SendDateTimeCmd();
+ }
+ 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;
-
+ /*
+ here we build the command related to the protocol T1 for ROM142 or T14 for ROM181
+ the only different that i know is the command length byte msg[4], this msg[4]+=1 by a ROM181 smartcard (_nighti_)
+ one example for the cmd$C0
+ T14 protocol: 01 A0 CA 00 00 03 C0 00 06 91
+ T1 protocol: 21 00 08 A0 CA 00 00 02 C0 00 06 87
+ */
+ unsigned char msg[MAX_LEN+16];
+ static char nagra_head[] = { 0xA0,0xCA,0x00,0x00 };
+
+ memset(msg,0,sizeof(msg));
+ int c=0;
+ if(!isT14Nagra) {
+ msg[c++]=0x21;
+ msg[c++]=block; block^=0x40;
+ msg[c++]=ilen+6;
+ }
+ else {
+ msg[c++]=0x01;
+ }
+ memcpy(msg+c,nagra_head,sizeof(nagra_head)); c+=sizeof(nagra_head);
+ msg[c]=ilen;
+ msg[c+1]=cmd;
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: <-");
+ msg[c+2]=dlen;
+ if(isT14Nagra) msg[c]++;
+ if(isTiger) { msg[c]--; msg[c+2]--; }
+ c+=3;
+ if(data && dlen>0) { memcpy(msg+c,data,dlen); c+=dlen; }
+ msg[c++]=rlen;
+ msg[c]=XorSum(msg,c); c++;
+
+ if(SerWrite(msg,c)==c) {
+ LDUMP(L_CORE_SC,msg,c,"NAGRA: <-");
cCondWait::SleepMs(10);
if(SerRead(buff,3,cardCfg.workTO)!=3) {
PRINTF(L_SC_ERROR,"reading back reply failed");
PRINTF(L_SC_ERROR,"reading back information block failed");
return false;
}
- if(XorSum(buff,reslen+3)) {
+ reslen+=3;
+ if(XorSum(buff,reslen)) {
PRINTF(L_SC_ERROR,"checksum failed");
return false;
}
- LDUMP(L_CORE_SC,buff,3+reslen,"NAGRA: ->");
+ LDUMP(L_CORE_SC,buff,reslen,"NAGRA: ->");
if(buff[3]!=res) {
PRINTF(L_SC_ERROR,"result not expected (%02X != %02X)",buff[3],res);
return false;
}
+ if(reslen-2!=rlen) {
+ PRINTF(L_SC_ERROR,"result length expected (%d != %d)",reslen-2,rlen);
+ return false;
+ }
memcpy(sb,&buff[3+rlen],2);
LDUMP(L_CORE_SC,sb,2,"NAGRA: ->");
cCondWait::SleepMs(10);