From 2fcb8800bc99bae2a94fba46be9122310ec4de87 Mon Sep 17 00:00:00 2001 From: leslie Date: Thu, 27 Dec 2007 22:01:12 +0100 Subject: [PATCH] release 0.8.4 --- HISTORY | 10 + examples/smartcard.conf.example | 14 + po/fi_FI.po | 2 +- po/ru_RU.po | 32 +- systems/nagra/cpu.c | 8 +- systems/nagra/cpu.h | 2 +- systems/nagra/nagra2-0101.c | 2 +- systems/nagra/nagra2-4101.c | 53 +- systems/sc-videoguard2/sc-videoguard2.c | 801 +++++++++++++++++++++++ systems/sc-videoguard2/sc-videoguard2.mk | 5 + systems/viaccess/tps.c | 2 +- version.h | 4 +- 12 files changed, 900 insertions(+), 35 deletions(-) create mode 100644 systems/sc-videoguard2/sc-videoguard2.c create mode 100644 systems/sc-videoguard2/sc-videoguard2.mk diff --git a/HISTORY b/HISTORY index e8cdfbc..f503e82 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,16 @@ VDR Plugin 'sc' Revision History -------------------------------- +30.09.2007: Version 0.8.4 +- Added Nagra2 4101 Bx support. +- Added smartcard NDS Videoguard2 code (untested). Needs NDS seed and boxid in + smartcard.conf (later only for newer card revisions). This is based on code + from sasc-ng changeset r155. +- Fixed Nagra cpu emu SetPc and ReadHandler call. +- Fixed crash on TPS ECM when no TPS encryption is used and no TPS AU keys are + available (null pointer dereference). +- Updated russian and finnish translations. + 15.09.2007: Version 0.8.3 - Added Nagra2 3101 MECM (same as 0501). - Added Nagra2 0901 new 0x40 MECM and rev248 morph (from sasc-ng). diff --git a/examples/smartcard.conf.example b/examples/smartcard.conf.example index 7c7bf4c..c2fb4a2 100644 --- a/examples/smartcard.conf.example +++ b/examples/smartcard.conf.example @@ -2,6 +2,20 @@ ; Comment lines can start with # or ; ; +; Videoguard2 +; +; NDS seed and boxid for camcrypt +; +; boxid - boxid (4 byte = 8 chars) +; seed1 - 1st seed (64 byte = 128 chars) +; seed2 - 2nd seed (64 byte = 128 chars) +; +; videoguard2: SEED seed1 seed2 +videoguard2: SEED 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 00112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233 +; +; videoguard2: BOXID boxid +videoguard2: BOXID 11223344 + ; Nagra ; ; boxkey and modulus for camcrypt diff --git a/po/fi_FI.po b/po/fi_FI.po index ff89dd7..0176172 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -182,7 +182,7 @@ msgstr "Tiedoston nimi" #: sc.c:1210 msgid "Filesize limit (KB)" -msgstr "" +msgstr "Tiedoston maksimikoko (KB)" #: sc.c:1211 msgid "Log to syslog" diff --git a/po/ru_RU.po b/po/ru_RU.po index a39a04b..a17c015 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -7,12 +7,13 @@ msgstr "" "Project-Id-Version: VDR 1.5.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-09-13 19:11+0200\n" -"PO-Revision-Date: 2007-08-27 12:45+0200\n" -"Last-Translator: somebody\n" -"Language-Team: somebody\n" +"PO-Revision-Date: 2007-09-17 23:03+0200\n" +"Last-Translator: \n" +"Language-Team: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-5\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" #: sc.c:117 sc.c:1198 msgid "off" @@ -182,7 +183,7 @@ msgstr " #: sc.c:1210 msgid "Filesize limit (KB)" -msgstr "" +msgstr "»ØÜØâ äÐÙÛÐ (Ú±)" #: sc.c:1211 msgid "Log to syslog" @@ -198,44 +199,45 @@ msgstr " #: systems/cardclient/cc.c:241 msgid "Cardclient: connect immediately" -msgstr "" +msgstr "Cardclient: áÞÕÔØÝØâì ÝÕÜÕÔÛÕÝÝÞ" #: systems/nagra/nagra1.c:977 msgid "Nagra: min. ECM processing time" -msgstr "" +msgstr "Nagra: ÜØÝ. ÒàÕÜï ÞÑàÐÑÞâÚØ ECM" #: systems/sc-cryptoworks/sc-cryptoworks.c:81 msgid "don't touch" -msgstr "" +msgstr "ÝÕ Ø×ÜÕÝïâì" #: systems/sc-cryptoworks/sc-cryptoworks.c:82 msgid "disable" -msgstr "" +msgstr "ÒëÚÛîçØâì" #: systems/sc-cryptoworks/sc-cryptoworks.c:86 msgid "SC-Cryptoworks: Parental rating" -msgstr "" +msgstr "SC-Cryptoworks: ÒÞ×àÐáâÝÞÕ ÞÓàÐÝØçÕÝØÕ" #: systems/sc-seca/sc-seca.c:81 msgid "allow ALL" -msgstr "" +msgstr "ÒáÕ àÐ×àÕèØâì" #: systems/sc-seca/sc-seca.c:82 msgid "block UNIQUE" -msgstr "" +msgstr "ÑÛÞÚØàÞÒÐâì UNIQUE" #: systems/sc-seca/sc-seca.c:83 msgid "block SHARED" -msgstr "" +msgstr "ÑÛÞÚØàÞÒÐâì SHARED" #: systems/sc-seca/sc-seca.c:84 msgid "block ALL" -msgstr "" +msgstr "ÒáÕ ÑÛÞÚØàÞÒÐâì" #: systems/sc-seca/sc-seca.c:100 msgid "SC-Seca: EMM updates" -msgstr "" +msgstr "SC-Seca: ÞÑÝÞÒÛÕÝØï EMM" #: systems/sc-seca/sc-seca.c:101 msgid "SC-Seca: activate PPV" -msgstr "" +msgstr "SC-Seca: ÐÚâØÒØàÞÒÐâì PPV" + diff --git a/systems/nagra/cpu.c b/systems/nagra/cpu.c index cdb972b..b283b00 100644 --- a/systems/nagra/cpu.c +++ b/systems/nagra/cpu.c @@ -35,7 +35,7 @@ cMapMem::cMapMem(unsigned short Offset, int Size) offset=Offset; size=Size; if((mem=(unsigned char *)malloc(size))) memset(mem,0,size); - PRINTF(L_SYS_EMU,"mapmem: new map off=%04x size=%04x",offset,size); +// PRINTF(L_SYS_EMU,"mapmem: new map off=%04x size=%04x",offset,size); } cMapMem::~cMapMem() @@ -255,9 +255,9 @@ void c6805::SetSp(unsigned short SpHi, unsigned short SpLow) spLow =SpLow; } -void c6805::SetPc(unsigned short addr) +void c6805::SetPc(unsigned short addr, unsigned char seg) { - pc=addr; + pc=addr; cr=seg; } void c6805::PopPc(void) @@ -562,7 +562,7 @@ int c6805::Run(int max_count) case 0x0: // bit case 0x1: op=Get(pr,ea); - if(hasReadHandler) ReadHandler(cr,ea,op); + if(hasReadHandler) ReadHandler(pr,ea,op); CCLOGLBPUT("{%02x} ",op); break; case 0xA: // immediate diff --git a/systems/nagra/cpu.h b/systems/nagra/cpu.h index 5e1cfea..9cf7852 100644 --- a/systems/nagra/cpu.h +++ b/systems/nagra/cpu.h @@ -140,7 +140,7 @@ protected: void SetMem(unsigned short addr, const unsigned char *data, int len, unsigned char seg=0); void ForceSet(unsigned short ea, unsigned char val, bool ro); void SetSp(unsigned short SpHi, unsigned short SpLow); - void SetPc(unsigned short addr); + void SetPc(unsigned short addr, unsigned char seg=0); unsigned short GetPc(void) const { return pc; } void PopPc(void); void PopCr(void); diff --git a/systems/nagra/nagra2-0101.c b/systems/nagra/nagra2-0101.c index e543b32..b56fe1a 100644 --- a/systems/nagra/nagra2-0101.c +++ b/systems/nagra/nagra2-0101.c @@ -286,7 +286,7 @@ void cN2Prov0101::WriteHandler(unsigned char seg, unsigned short ea, unsigned ch if(ea==0x05) { special05=(op&0x40)!=0; } - else if(ea==0x16) { + else if(ea==0x0a || ea==0x12 || ea==0x16) { unsigned char old=Get(ea); if(old&2) op=(old&~0x02) | (op&0x02); } diff --git a/systems/nagra/nagra2-4101.c b/systems/nagra/nagra2-4101.c index f140b47..0abe6d6 100644 --- a/systems/nagra/nagra2-4101.c +++ b/systems/nagra/nagra2-4101.c @@ -19,14 +19,22 @@ // -- cN2Prov4101 ---------------------------------------------------------------- -class cN2Prov4101 : public cN2Prov { +class cN2Prov4101 : public cN2Prov, public cN2Emu { protected: + virtual void WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op); public: - cN2Prov4101(int Id, int Flags):cN2Prov(Id,Flags) {} + cN2Prov4101(int Id, int Flags); virtual bool PostProcAU(int id, unsigned char *data); + virtual int ProcessBx(unsigned char *data, int len, int pos); }; -static cN2ProvLinkReg staticPL4101; +static cN2ProvLinkReg staticPL4101; + +cN2Prov4101::cN2Prov4101(int Id, int Flags) +:cN2Prov(Id,Flags) +{ + hasWriteHandler=true; +} bool cN2Prov4101::PostProcAU(int id, unsigned char *data) { @@ -47,13 +55,38 @@ bool cN2Prov4101::PostProcAU(int id, unsigned char *data) return true; } -// -- cN2Prov7101 ---------------------------------------------------------------- +int cN2Prov4101::ProcessBx(unsigned char *data, int len, int pos) +{ + if(Init(id,110)) { + SetMem(0x80,data,len); + SetPc(0x80+pos); + SetSp(0x0FFF,0x0FE0); + ClearBreakpoints(); + AddBreakpoint(0xACDD); + AddBreakpoint(0x9BDD); + while(!Run(5000)) { + switch(GetPc()) { + case 0xACDD: + return -1; + case 0x9BDD: + GetMem(0x80,data,len); + return a; + } + } + } + return -1; +} -/* -class cN2Prov7101 : public cN2Prov4101 { -public: - cN2Prov7101(int Id, int Flags):cN2Prov4101(Id,Flags) {} - }; -*/ +void cN2Prov4101::WriteHandler(unsigned char seg, unsigned short ea, unsigned char &op) +{ + if(cr==0x00) { + if(ea==0x0a || ea==0x12 || ea==0x16) { + unsigned char old=Get(ea); + if(old&2) op=(old&~0x02) | (op&0x02); + } + } +} + +// -- cN2Prov7101 ---------------------------------------------------------------- static cN2ProvLinkReg staticPL7101; diff --git a/systems/sc-videoguard2/sc-videoguard2.c b/systems/sc-videoguard2/sc-videoguard2.c new file mode 100644 index 0000000..05b4c84 --- /dev/null +++ b/systems/sc-videoguard2/sc-videoguard2.c @@ -0,0 +1,801 @@ +/* + * Softcam plugin to VDR (C++) + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include + +#include "system-common.h" +#include "smartcard.h" +#include "data.h" +#include "crypto.h" +#include "misc.h" +#include "parse.h" +#include "helper.h" +#include "log-sc.h" + +#define SYSTEM_VIDEOGUARD2 0x0900 + +#define SYSTEM_NAME "SC-VideoGuard2" +#define SYSTEM_PRI -5 + +#define SC_NAME "VideoGuard2" +#define SC_ID MAKE_SC_ID('V','i','G','2') + +#define L_SC 17 +#define L_SC_ALL LALL(L_SC_LASTDEF) + +static const struct LogModule lm_sc = { + (LMOD_ENABLE|L_SC_ALL)&LOPT_MASK, + (LMOD_ENABLE|L_SC_DEFDEF)&LOPT_MASK, + "sc-videoguard2", + { L_SC_DEFNAMES } + }; +ADD_MODULE(L_SC,lm_sc) + +// -- cSystemScVideoGuard2 --------------------------------------------------------------- + +class cSystemScVideoGuard2 : public cSystemScCore { +public: + cSystemScVideoGuard2(void); + }; + +cSystemScVideoGuard2::cSystemScVideoGuard2(void) +:cSystemScCore(SYSTEM_NAME,SYSTEM_PRI,SC_ID,"SC VideoGuard2") +{ + hasLogger=true; +} + +// -- cSystemLinkScVideoGuard2 -------------------------------------------------------- + +class cSystemLinkScVideoGuard2 : public cSystemLink { +public: + cSystemLinkScVideoGuard2(void); + virtual bool CanHandle(unsigned short SysId); + virtual cSystem *Create(void) { return new cSystemScVideoGuard2; } + }; + +static cSystemLinkScVideoGuard2 staticInit; + +cSystemLinkScVideoGuard2::cSystemLinkScVideoGuard2(void) +:cSystemLink(SYSTEM_NAME,SYSTEM_PRI) +{} + +bool cSystemLinkScVideoGuard2::CanHandle(unsigned short SysId) +{ + bool res=false; + cSmartCard *card=smartcards.LockCard(SC_ID); + if(card) { + res=card->CanHandle(SysId); + smartcards.ReleaseCard(card); + } + return res; +} + +// -- cSmartCardDataVideoGuard2 ----------------------------------------------------- + +enum eDataType { dtBoxId, dtSeed }; + +class cSmartCardDataVideoGuard2 : public cSmartCardData { +public: + eDataType type; + unsigned char boxid[4]; + unsigned char seed0[64], seed1[64]; + // + cSmartCardDataVideoGuard2(void); + cSmartCardDataVideoGuard2(eDataType Type); + virtual bool Parse(const char *line); + virtual bool Matches(cSmartCardData *param); + }; + +cSmartCardDataVideoGuard2::cSmartCardDataVideoGuard2(void) +:cSmartCardData(SC_ID) +{} + +cSmartCardDataVideoGuard2::cSmartCardDataVideoGuard2(eDataType Type) +:cSmartCardData(SC_ID) +{ + type=Type; +} + +bool cSmartCardDataVideoGuard2::Matches(cSmartCardData *param) +{ + cSmartCardDataVideoGuard2 *cd=(cSmartCardDataVideoGuard2 *)param; + return cd->type==type; +} + +bool cSmartCardDataVideoGuard2::Parse(const char *line) +{ + line=skipspace(line); + if(!strncasecmp(line,"BOXID",5)) { type=dtBoxId; line+=5; } + else if(!strncasecmp(line,"SEED",4)) { type=dtSeed; line+=4; } + else { + PRINTF(L_CORE_LOAD,"smartcarddatavideoguard2: format error: datatype"); + return false; + } + line=skipspace(line); + switch(type) { + case dtBoxId: + if(GetHex(line,boxid,sizeof(boxid))!=sizeof(boxid)) { + PRINTF(L_CORE_LOAD,"smartcarddatavideoguard2: format error: boxid"); + return false; + } + break; + case dtSeed: + if(GetHex(line,seed0,sizeof(seed0))!=sizeof(seed0)) { + PRINTF(L_CORE_LOAD,"smartcarddatacryptoworks: format error: seed0"); + return false; + } + line=skipspace(line); + if(GetHex(line,seed1,sizeof(seed1))!=sizeof(seed1)) { + PRINTF(L_CORE_LOAD,"smartcarddatacryptoworks: format error: seed1"); + return false; + } + break; + } + return true; +} + +// -- cCamCryptVG2 ------------------------------------------------------------- + +#define xor16(v1,v2,d) xxor((d),16,(v1),(v2)) +#define val_by2on3(x) ((0xaaab*(x))>>16) //fixed point *2/3 + +class cCamCryptVG2 : private cAES { +private: + unsigned short cardkeys[3][32]; + unsigned char stateD3A[16]; + // + void LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry); + void PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey); + void RotateRightAndHash(unsigned char *p); + void Reorder16A(unsigned char *dest, const unsigned char *src); + void ReorderAndEncrypt(unsigned char *p); + // + void Process_D0(const unsigned char *ins, unsigned char *data, const unsigned char *status); + void Process_D1(const unsigned char *ins, unsigned char *data, const unsigned char *status); + void Decrypt_D3(unsigned char *ins, unsigned char *data, const unsigned char *status); +public: + void PostProcess_Decrypt(unsigned char *buff, int len, unsigned char *cw1, unsigned char *cw2); + void SetSeed(const unsigned char *Key1, const unsigned char *Key2); + void GetCamKey(unsigned char *buff); +}; + +void cCamCryptVG2::SetSeed(const unsigned char *Key1, const unsigned char *Key2) +{ + memcpy(cardkeys[1],Key1,sizeof(cardkeys[1])); + memcpy(cardkeys[2],Key2,sizeof(cardkeys[2])); +} + +void cCamCryptVG2::GetCamKey(unsigned char *buff) +{ + unsigned short *tb2=(unsigned short *)buff, c=1; + memset(tb2,0,64); + tb2[0]=1; + for(int i=0; i<32; i++) LongMult(tb2,&c,cardkeys[1][i],0); +} + +void cCamCryptVG2::PostProcess_Decrypt(unsigned char *buff, int len, unsigned char *cw1, unsigned char *cw2) +{ + switch(buff[0]) { + case 0xD0: + Process_D0(buff,buff+5,buff+buff[4]+5); + break; + case 0xD1: + Process_D1(buff,buff+5,buff+buff[4]+5); + break; + case 0xD3: + Decrypt_D3(buff,buff+5,buff+buff[4]+5); + if(buff[1]==0x54) { + memcpy(cw1,buff+5,8); + for(int ind=14; ind=0; i--) { + unsigned int x=idata[i] | (rem<<16); + rem=(x%div)&0xffff; + } + unsigned int carry=1, t=val_by2on3(div) | 1; + while(t) { + if(t&1) carry=((carry*rem)%div)&0xffff; + rem=((rem*rem)%div)&0xffff; + t>>=1; + } + PartialMod(carry,count2,key2,key1); + } + unsigned short idatacount=0; + for(int i=31; i>=0; i--) LongMult(idata,&idatacount,key1[i],key2[i]); + unsigned char stateD1[16]; + Reorder16A(stateD1,data); + cAES::SetKey(stateD1); + break; + } + } +} + +void cCamCryptVG2::Process_D1(const unsigned char *ins, unsigned char *data, const unsigned char *status) +{ + unsigned char iter[16], tmp[16]; + memset(iter,0,sizeof(iter)); + memcpy(iter,ins,5); + xor16(iter,stateD3A,iter); + memcpy(stateD3A,iter,sizeof(iter)); + + int datalen=status-data; + int datalen1=datalen; + if(datalen<0) datalen1+=15; + int blocklen=datalen1>>4; + for(int i=0,iblock=0; i16) ins[4]-=16; + if(ins[1]==0xbe) memset(stateD3A,0,sizeof(stateD3A)); + + unsigned char tmp[16]; + memset(tmp,0,sizeof(tmp)); + memcpy(tmp,ins,5); + xor16(tmp,stateD3A,stateD3A); + + int len1=ins[4]; + int blocklen=len1>>4; + if(ins[1]!=0xbe) blocklen++; + + unsigned char iter[16], states[16][16]; + memset(iter,0,sizeof(iter)); + for(int blockindex=0; blockindex>4)) { + int c=len1-(blockindex*16); + if(c<16) memset(&states[blockindex][c],0,16-c); + } + xor16(states[blockindex],stateD3A,stateD3A); + RotateRightAndHash(stateD3A); + } + memset(tmp,0,sizeof(tmp)); + memcpy(tmp+5,status,2); + xor16(tmp,stateD3A,stateD3A); + ReorderAndEncrypt(stateD3A); + + memcpy(stateD3A,status-16,sizeof(stateD3A)); + ReorderAndEncrypt(stateD3A); + + memcpy(data,states[0],len1); + if(ins[1]==0xbe) { + Reorder16A(tmp,states[0]); + cAES::SetKey(tmp); + } +} + +void cCamCryptVG2::ReorderAndEncrypt(unsigned char *p) +{ + unsigned char tmp[16]; + Reorder16A(tmp,p); cAES::Encrypt(tmp,16,tmp); Reorder16A(p,tmp); +} + +// reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD + +void cCamCryptVG2::Reorder16A(unsigned char *dest, const unsigned char *src) +{ + for(int i=0,k=0; i<4; i++) + for(int j=i; j<16; j+=4,k++) + dest[k]=src[j]; +} + +void cCamCryptVG2::LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry) +{ + for(int i=0; i<*pLen; i++) { + carry+=pData[i]*mult; + pData[i]=(unsigned short)carry; + carry>>=16; + } + if(carry) pData[*pLen++]=carry; +} + +void cCamCryptVG2::PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey) +{ + if(count) { + unsigned int mod=inkey[count]; + unsigned short mult=(inkey[count]-outkey[count-1])&0xffff; + for(unsigned int i=0,ib1=count-2; it) mult+=mod; + } + mult+=val; + if((val>mult) || (mod>1) | ((p[(i-1)&15]&1)<<7) ]; +} + +// -- cCmdTable ---------------------------------------------------------------- + +struct CmdTabEntry { + unsigned char cla; + unsigned char cmd; + unsigned char len; + unsigned char mode; +}; + +struct CmdTab { + unsigned char index; + unsigned char size; + unsigned char Nentries; + unsigned char dummy; + CmdTabEntry e[0]; +}; + +class CmdTable { +private: + struct CmdTab *tab; +public: + CmdTable(const unsigned char *mem, int size); + ~CmdTable(); + bool GetInfo(const unsigned char *cmd, unsigned char &rlen, unsigned char &rmode); + }; + +CmdTable::CmdTable(const unsigned char *mem, int size) +{ + tab=(struct CmdTab *)new unsigned char[size]; + memcpy(tab,mem,size); +} + +CmdTable::~CmdTable() +{ + delete tab; +} + +bool CmdTable::GetInfo(const unsigned char *cmd, unsigned char &rlen, unsigned char & rmode) +{ + struct CmdTabEntry *pcte=tab->e; + for(int i=0; iNentries; i++,pcte++) + if(cmd[1]==pcte->cmd) { + rlen=pcte->len; + rmode=pcte->mode; + return true; + } + return false; +} + +// -- cSmartCardVideoGuard2 ----------------------------------------------------------- + +#define BASEYEAR 2000 // for date calculation + +class cSmartCardVideoGuard2 : public cSmartCard, private cIdSet { +private: + unsigned char CW1[8], CW2[8]; + unsigned char cardID[4], groupID[4], boxID[4]; + unsigned int CAID; + cCamCryptVG2 state; + CmdTable *cmdList; +public: + void ReadTiers(void); + void RevDateCalc(const unsigned char *Date, int &year, int &mon, int &day, int &hh, int &mm, int &ss); + void Datecalc(int year, int mon, int day, int hh, int mm, int ss , unsigned char * Date); + int DoCmd(const unsigned char *ins, const unsigned char *txbuff=0, unsigned char *rxbuff=0); + int ReadCmdLen(const unsigned char *cmd); +public: + cSmartCardVideoGuard2(void); + ~cSmartCardVideoGuard2(); + 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 SysId); + }; + +static const struct StatusMsg msgs[] = { + { { 0x90,0x00 }, "Instruction executed without errors, noupdate, nofilter, IRD# not set", true }, + { { 0x90,0x01 }, "Instruction executed without errors, update, nofilter, IRD# not set", true }, + { { 0x90,0x20 }, "Instruction executed without errors, noupdate, nofilter, IRD# set", true }, + { { 0x90,0x21 }, "Instruction executed without errors, update, nofilter, IRD# set", true }, + { { 0x90,0x80 }, "Instruction executed without errors, noupdate, filter, IRD# not set", true }, + { { 0x90,0x81 }, "Instruction executed without errors, update, filter, IRD# not set", true }, + { { 0x90,0xa0 }, "Instruction executed without errors, noupdate, filter, IRD# set", true }, + { { 0x90,0xa1 }, "Instruction executed without errors, update, filter, IRD# set", true }, + { { 0x91,0x00 }, "Instruction executed without errors, noupdate, nofilter, IRD# not set", true }, + { { 0x91,0x01 }, "Instruction executed without errors, update, nofilter, IRD# not set", true }, + { { 0x91,0x20 }, "Instruction executed without errors, noupdate, nofilter, IRD# set", true }, + { { 0x91,0x21 }, "Instruction executed without errors, update, nofilter, IRD# set", true }, + { { 0x91,0x80 }, "Instruction executed without errors, noupdate, filter, IRD# not set", true }, + { { 0x91,0x81 }, "Instruction executed without errors, update, filter, IRD# not set", true }, + { { 0x91,0xa0 }, "Instruction executed without errors, noupdate, filter, IRD# set", true }, + { { 0x91,0xa1 }, "Instruction executed without errors, update, filter, IRD# set", true }, + { { 0xFF,0xFF }, 0, false } + }; + +static const struct CardConfig cardCfg = { + SM_8O2,2000,1400 + }; + +cSmartCardVideoGuard2::cSmartCardVideoGuard2(void) +:cSmartCard(&cardCfg,msgs) +{ + cmdList=0; +} + +cSmartCardVideoGuard2::~cSmartCardVideoGuard2(void) +{ + delete cmdList; +} + +bool cSmartCardVideoGuard2::CanHandle(unsigned short SysId) +{ + return SysId==CAID; +} + +bool cSmartCardVideoGuard2::Init(void) +{ + static const unsigned char vg2Hist[] = { 'i',0xff,'J','P' }; + if(atr->histLen<4 || memcmp(&atr->hist[3],vg2Hist,4)) { + PRINTF(L_SC_INIT,"doesn't look like a VideoGuard2 card"); + return false; + } + + infoStr.Begin(); + infoStr.Strcat("VideoGuard2 smartcard\n"); + snprintf(idStr,sizeof(idStr),"%s (%c%c.%d)",SC_NAME,atr->hist[10],atr->hist[11],atr->hist[12]); + + ResetIdSet(); + delete cmdList; cmdList=0; + + static unsigned char ins7401[] = { 0xD0,0x74,0x01,0x00,0x00 }; + int l; + if((l=ReadCmdLen(ins7401))<0) return false; + ins7401[4]=l; + unsigned char buff[256]; + if(!IsoRead(ins7401,buff) || !Status()) { + PRINTF(L_SC_ERROR,"failed to read cmd list"); + return false; + } + cmdList=new CmdTable(buff,l); + + static const unsigned char ins7416[5] = { 0xD0,0x74,0x16,0x00,0x00 }; + if(DoCmd(ins7416)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd 7416 failed"); + return false; + } + + static const unsigned char ins36[5] = { 0xD0,0x36,0x00,0x00,0x00 }; + bool boxidOK=false; + if((l=DoCmd(ins36,0,buff))>0 && Status()) + for(int i=0; iboxid,sizeof(boxID)); + boxidOK=true; + } + } + if(!boxidOK) { + PRINTF(L_SC_ERROR,"no boxID available"); + return false; + } + + static const unsigned char ins4C[5] = { 0xD0,0x4C,0x00,0x00,0x00 }; + static unsigned char payload4C[9] = { 0,0,0,0, 3,0,0,2,4 }; + memcpy(payload4C,boxID,4); + if(DoCmd(ins4C,payload4C)<0 || !Status()) { + PRINTF(L_SC_ERROR,"sending boxid failed"); + return false; + } + + static const unsigned char ins58[5] = { 0xD0,0x58,0x00,0x00,0x00 }; + if(DoCmd(ins58,0,buff)<0 || !Status()) { + PRINTF(L_SC_ERROR,"failed to read card details"); + return false; + } + + CAID=WORD(buff,0x1D,0xFFFF); + memcpy(&cardID,&buff[8],4); + memcpy(&groupID,&buff[8],4); groupID[3]=0; + SetCard(new cCardNDS(cardID)); + AddProv(new cProviderNDS(groupID)); + char str[20], str2[20]; + infoStr.Printf("Cardtype: %c%c.%d\n" + "BoxID %s Caid %04x CardID %s\n", + atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4)); + PRINTF(L_SC_INIT,"cardtype: %c%c.%d boxID %s caid %04x cardID %s",atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4)); + + cSmartCardDataVideoGuard2 cd(dtSeed); + cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd); + if(!entry) { + PRINTF(L_SC_ERROR,"no NDS seed available"); + return false; + } + state.SetSeed(entry->seed0,entry->seed1); + unsigned char tbuff[64]; + state.GetCamKey(tbuff); + + static const unsigned char insB4[5] = { 0xD0,0xB4,0x00,0x00,0x00 }; + if(DoCmd(insB4,tbuff)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd D0B4 failed"); + return false; + } + + static const unsigned char insBC[5] = { 0xD0,0xBC,0x00,0x00,0x00 }; + if(DoCmd(insBC)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd D0BC failed"); + return false; + } + static const unsigned char insBE[5] = { 0xD3,0xBE,0x00,0x00,0x00 }; + if(DoCmd(insBE)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd D3BE failed"); + return false; + } + + static const unsigned char ins58a[5] = { 0xD1,0x58,0x00,0x00,0x00 }; + if(DoCmd(ins58a)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd D158 failed"); + return false; + } + static const unsigned char ins4Ca[5] = { 0xD1,0x4C,0x00,0x00,0x00 }; + if(DoCmd(ins4Ca,payload4C)<0 || !Status()) { + PRINTF(L_SC_ERROR,"cmd D14C failed"); + return false; + } + ReadTiers(); + return true; +} + +bool cSmartCardVideoGuard2::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw) +{ + static unsigned char ins40[5] = { 0xD1,0x40,0x40,0x80,0xFF }; + static const unsigned char ins54[5] = { 0xD3,0x54,0x00,0x00,0x00 }; + int posECMpart2=data[6]+7; + int lenECMpart2=data[posECMpart2]+1; + unsigned char tbuff[264]; + tbuff[0]=0; + memcpy(&tbuff[1],&data[posECMpart2+1],lenECMpart2); + ins40[4]=lenECMpart2; + if(DoCmd(ins40,tbuff)>0 && Status()) { + if(DoCmd(ins54)>0 && Status()) { + if(data[0]&1) memcpy(cw+8,CW1,8); + else memcpy(cw+0,CW1,8); + return true; + } + } + return false; +} + +bool cSmartCardVideoGuard2::Update(int pid, int caid, const unsigned char *data) +{ + static unsigned char ins42[5] = { 0xD1,0x40,0x00,0x00,0xFF }; + if(MatchEMM(data)) { + const unsigned char *payloaddata=cParseNDS::PayloadStart(data); //points to 02 xx yy + int lenEMM; + switch(payloaddata[0]) { + case 2: + lenEMM=payloaddata[payloaddata[1]+2]; + payloaddata+=3+payloaddata[1]; // skip len specifier + break; + default: +// di(printf("scvg2: ***ERROR***: EMM: bad payload type byte %02x\n",payloaddata[0])); +// DUMP3("VG2EMM",data,32); + return false; + } +// di(printf("scvg2: EMM: pid %d (%x) caid %d (%x) len %d (%x)\n",pid,pid,caid,caid,lenEMM,lenEMM)); +// DUMP3("VG2EMM",data,32); + if(lenEMM<=8 || lenEMM>188) { +// di(printf("scvg2: ***ERROR***: EMM: len %d bad\n",lenEMM)); + return false; + } + ins42[4]=lenEMM; + if(DoCmd(ins42,payloaddata)>0 && Status()) + return true; + } + return false; +} + +/* +bool cSmartCardVideoGuard2::ZKT(void) +{ + static unsigned char payload4A[1] = { 0x01 }; + static unsigned char ins4A[5] = { 0xD0,0x4A,0x15,0x01,0x01 }; + DoCmd(ins4A,payload4A); + static unsigned char ins5A1[5] = { 0xD0,0x5A,0x15,0x01,0x10 }; + DoCmd(ins5A1); + static unsigned char ins5A2[5] = { 0xD0,0x5A,0x11,0x02,0x40 }; + DoCmd(ins5A2); + DoCmd(ins4A,payload4A); + DoCmd(ins5A1); + static unsigned char ins5A3[5] = { 0xD0,0x5A,0x10,0x02,0x40 }; + DoCmd(ins5A3); + return true; +} +*/ + +void cSmartCardVideoGuard2::ReadTiers(void) +{ + static const unsigned char ins2a[5] = { 0xd0,0x2a,0x00,0x00,0x00 }; + if(DoCmd(ins2a)<0 || !Status()) return; + static unsigned char ins76[5] = { 0xd0,0x76,0x00,0x00,0x00 }; + ins76[3]=0x7f; ins76[4]=2; + unsigned char buff[270]; + if(!IsoRead(ins76,buff) || !Status()) return; + ins76[3]=0; ins76[4]=0; + int num=buff[1]; + if(num>0) { + infoStr.Strcat("Tier\tExpiry Date\n"); + infoStr.Strcat("----\t-----------\n"); + } + for(int i=0; iGetInfo(ins2,len,mode)) { + if(len==0xFF && mode==2) { + if(ins2[4]==0) ins2[4]=len=ReadCmdLen(ins2); + } + else if(mode!=0) ins2[4]=len; + } + if(ins2[0]==0xd3) ins2[4]=len+16; + len=ins2[4]; + + unsigned char b[256], tmp[264]; + if(!rxbuff) rxbuff=tmp; + if(mode>1) { + if(!IsoRead(ins2,b) || !Status()) return -1; + memcpy(rxbuff,ins2,5); + memcpy(rxbuff+5,b,len); + memcpy(rxbuff+5+len,sb,2); + } + else { + if(!IsoWrite(ins2,txbuff) || !Status()) return -1; + memcpy(rxbuff,ins2,5); + memcpy(rxbuff+5,txbuff,len); + memcpy(rxbuff+5+len,sb,2); + } + state.PostProcess_Decrypt(rxbuff,len,CW1,CW2); + return len; +} + +int cSmartCardVideoGuard2::ReadCmdLen(const unsigned char *cmd) +{ + unsigned char cmd2[5], resp[16]; + memcpy(cmd2,cmd,5); + cmd2[3]=0x80; + cmd2[4]=1; + if(!IsoRead(cmd2,resp) || !Status()) { + PRINTF(L_SC_ERROR,"failed to read %02x%02x cmd length",cmd[1],cmd[2]); + return -1; + } + return resp[0]; +} + +// -- cSmartCardLinkVG2 ------------------------------------------------------- + +class cSmartCardLinkVG2 : public cSmartCardLink { +public: + cSmartCardLinkVG2(void):cSmartCardLink(SC_NAME,SC_ID) {} + virtual cSmartCard *Create(void) { return new cSmartCardVideoGuard2; } + virtual cSmartCardData *CreateData(void) { return new cSmartCardDataVideoGuard2; } + }; + +static cSmartCardLinkVG2 staticScInit; diff --git a/systems/sc-videoguard2/sc-videoguard2.mk b/systems/sc-videoguard2/sc-videoguard2.mk new file mode 100644 index 0000000..749aaeb --- /dev/null +++ b/systems/sc-videoguard2/sc-videoguard2.mk @@ -0,0 +1,5 @@ +# +# Smartcard VideoGuard2 +# +TARGET = sc_videoguard2 +OBJS = sc-videoguard2.o diff --git a/systems/viaccess/tps.c b/systems/viaccess/tps.c index 6989e43..8bc8d01 100644 --- a/systems/viaccess/tps.c +++ b/systems/viaccess/tps.c @@ -1186,10 +1186,10 @@ int cTPS::Decrypt(int cardNum, int Source, int Transponder, unsigned char *data, case 0xEA: if(doPre) TpsDecrypt(&data[i+2],k->Mode(0),k->Key(0)); if(doTPS) TpsDecrypt(&data[i+2],(hasDF)?k->Mode(2):1,k->Key(2)); + if(doPost) { postMode=k->Mode(1); memcpy(postKey,k->Key(1),sizeof(postKey)); } break; } } - postMode=k->Mode(1); memcpy(postKey,k->Key(1),sizeof(postKey)); return ret; } diff --git a/version.h b/version.h index 058a93a..3bde6fe 100644 --- a/version.h +++ b/version.h @@ -21,8 +21,8 @@ #define ___VERSION_H // all release versions must end with 0xFF !! -#define SCVERSNUM 0x000803FF -#define SCVERSION "0.8.3" +#define SCVERSNUM 0x000804FF +#define SCVERSION "0.8.4" extern const char *ScVersion; -- 2.39.5