From: leslie Date: Mon, 21 Dec 2009 14:04:37 +0000 (+0100) Subject: sc-nagra: code rework based on OSCAM rev 933 X-Git-Tag: upstream/620~126 X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=eb3458aae4eb9767d351d71dda5df48007ec0533;p=sasc-ng.git sc-nagra: code rework based on OSCAM rev 933 --- diff --git a/examples/smartcard.conf.example b/examples/smartcard.conf.example index 92a4f69..a659d0f 100644 --- a/examples/smartcard.conf.example +++ b/examples/smartcard.conf.example @@ -20,18 +20,18 @@ videoguard2: BOXID 11223344 ; ; boxkey and modulus for camcrypt ; -; prvid - provider ID (2 byte = 4 chars) +; cardid - card ID / serial (4 byte = 8 chars) ; boxkey - boxkey (8 byte = 16 chars) -; mod - modulus (64 byte = 128 chars) +; mod - modulus (big endian) (64 byte = 128 chars) ; -; If IRDMOD is present, the given mod is used to decrypt the cammod from DT08 -; data. If IRDMOD is obmited, the given mod is used as cammod directly +; For a card with dt08 you should give the IRDMOD to decrypt the dt08. +; Otherwise the CARDMOD is used directly for session key negotiation. ; -; nagra: [prvid] IRDMOD boxkey mod -nagra: [0501] IRDMOD 0011223344556677 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 +; nagra: cardid boxkey IRDMOD mod +nagra: 12345678 0011223344556677 IRDMOD 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 ; -; nagra: [prvid] boxkey mod -nagra: [1201] 0011223344556677 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 +; nagra: cardid boxkey CARDMOD mod +nagra: 12345678 0011223344556677 CARDMOD 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 ; Cryptoworks ; diff --git a/po/de_DE.po b/po/de_DE.po index 95350db..77030a9 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2007-08-27 12:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "ausschalten" msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Altersbeschränkung" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "SC-Nagra: T14 Nagra Modus benutzen" + msgid "allow ALL" msgstr "alle erlauben" diff --git a/po/fi_FI.po b/po/fi_FI.po index 69ea68b..1b79490 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2008-11-19 13:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "poista" msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Ikäraja" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "salli kaikki" diff --git a/po/fr_FR.po b/po/fr_FR.po index adf4681..89011d9 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2007-08-27 12:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "d msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Contrôle parentale" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "permettre TOUS" diff --git a/po/hu_HU.po b/po/hu_HU.po index f03382a..56d8506 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.11\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2009-05-17 11:09+0800\n" "Last-Translator: jv\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "kikapcsolva" msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Szüloi zár" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "engedélyezd MIND" diff --git a/po/it_IT.po b/po/it_IT.po index 3d7a66d..a2d8fce 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2008-11-19 12:23+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "disabilita" msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Filtro famiglia" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "permetti TUTTI" diff --git a/po/nl_NL.po b/po/nl_NL.po index eec1522..0bec0c8 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2007-08-27 12:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "uitschakelen" msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: Leeftijdsadvies" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "ALLES toestaan" diff --git a/po/pl_PL.po b/po/pl_PL.po index 8dfe30a..dbd3afb 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2007-08-27 12:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "wy msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: wska¼nik rodzica" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "dopu¶æ wszystkie" diff --git a/po/ru_RU.po b/po/ru_RU.po index 5a9c37f..6e2ab43 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2009-05-14 19:33+0100\n" "Last-Translator: somebody\n" "Language-Team: ru\n" @@ -206,6 +206,9 @@ msgstr " msgid "SC-Cryptoworks: Parental rating" msgstr "SC-Cryptoworks: ÒÞ×àÐáâÝÞÕ ÞÓàÐÝØçÕÝØÕ" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "ÒáÕ àÐ×àÕèØâì" diff --git a/po/sv_SE.po b/po/sv_SE.po index 08d2567..e3d6dfd 100644 --- a/po/sv_SE.po +++ b/po/sv_SE.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-18 08:17-0400\n" +"POT-Creation-Date: 2009-12-21 08:38-0500\n" "PO-Revision-Date: 2007-08-27 12:45+0200\n" "Last-Translator: somebody\n" "Language-Team: somebody\n" @@ -205,6 +205,9 @@ msgstr "" msgid "SC-Cryptoworks: Parental rating" msgstr "" +msgid "SC-Nagra: use T14 Nagra mode" +msgstr "" + msgid "allow ALL" msgstr "" diff --git a/systems/sc-nagra/sc-nagra.c b/systems/sc-nagra/sc-nagra.c index 3ce16c5..d464fc3 100644 --- a/systems/sc-nagra/sc-nagra.c +++ b/systems/sc-nagra/sc-nagra.c @@ -24,8 +24,10 @@ #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" @@ -52,6 +54,8 @@ static const struct LogModule lm_sc = { }; ADD_MODULE(L_SC,lm_sc) +static int allowT14=0; + // -- cSystemScNagra --------------------------------------------------------------------- class cSystemScNagra : public cSystemScCore { @@ -79,12 +83,20 @@ static cSystemLinkScNagra staticInit; 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 ------------------------------------------------------------------ @@ -94,17 +106,20 @@ private: 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) @@ -113,22 +128,20 @@ 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=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); @@ -138,74 +151,90 @@ void cCamCryptNagra::InitCamKey(unsigned char *key, const unsigned char *bk, con //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"); + 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); }; @@ -213,89 +242,79 @@ public: 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: @@ -303,6 +322,7 @@ 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[] = { @@ -317,15 +337,13 @@ static const struct CardConfig cardCfg = { 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) { @@ -345,81 +363,150 @@ bool cSmartCardNagra::GetCardStatus(void) 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; ibk); + 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"); @@ -540,16 +668,21 @@ bool cSmartCardNagra::DoBlkCmd(unsigned char cmd, int ilen, unsigned char res, i 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);