Opened 14 years ago
Closed 14 years ago
#48 closed enhancement (duplicate)
HD+ Support
Reported by: | madman | Owned by: | |
---|---|---|---|
Priority: | critical | Component: | |
Severity: | high | Keywords: | |
Cc: | Sensitive: | no |
Description
From Streamboard. Could you please add this to make a public test version for hd+ ?
#include <stdio.h> #include <string.h> #include <time.h> #include <unistd.h> #include <openssl/rand.h> #include "common.h" #include "system.h" #include "system-common.h" #include "smartcard.h" #include "crypto.h" #include "data.h" #include "misc.h" #include "parse.h" //DEBUG_CAMCRYPT #ifdef DEBUG_CAMCRYPT #define dcc(x) { x; } #else #define dcc(x) ; #endif #define SYSTEM_NAME "SC-Nagra2" #define SYSTEM_PRI -5 #define SC_NAME "Nagra2" #define SC_ID MAKE_SC_ID('N','g','r','2') // -- cSystemScNagra2 ---------------------------------------------------------- class cSystemScNagra2 : public cSystemScCore { public: cSystemScNagra2(void); }; cSystemScNagra2::cSystemScNagra2(void) :cSystemScCore(SYSTEM_NAME,SYSTEM_PRI,SC_ID,"SC Nagra2") { hasLogger=true; } // -- cSystemLinkScNagra2 ------------------------------------------------------ class cSystemLinkScNagra2 : public cSystemLink { public: cSystemLinkScNagra2(void); virtual bool CanHandle(unsigned short SysId); virtual cSystem *Create(void) { return new cSystemScNagra2; } }; static cSystemLinkScNagra2 staticInit; cSystemLinkScNagra2::cSystemLinkScNagra2(void) : cSystemLink(SYSTEM_NAME,SYSTEM_PRI) { Feature.NeedsSmartCard(); } bool cSystemLinkScNagra2::CanHandle(unsigned short SysId) { bool res=false; cSmartCard *card=smartcards.LockCard(SC_ID); if(card) { res=card->CanHandle(SysId); smartcards.ReleaseCard(card); } return res; } // -- cSmartCardDataNagra2 ----------------------------------------------------- class cSmartCardDataNagra2 : public cSmartCardData { public: int caid; unsigned char camid[4]; unsigned char boxke[8]; unsigned char negok[64]; // cSmartCardDataNagra2(void); cSmartCardDataNagra2(unsigned char camid[4]); virtual bool Parse(const char *line); virtual bool Matches(cSmartCardData *param); }; cSmartCardDataNagra2::cSmartCardDataNagra2(void) : cSmartCardData(SC_ID) {} cSmartCardDataNagra2::cSmartCardDataNagra2(unsigned char CAMid[4]) : cSmartCardData(SC_ID) { memcpy(camid,CAMid,4); } bool cSmartCardDataNagra2::Matches(cSmartCardData *param) { cSmartCardDataNagra2 *cd=(cSmartCardDataNagra2 *)param; return !memcmp(cd->camid,camid,4); } bool cSmartCardDataNagra2::Parse(const char *line) { unsigned char buff[512]; memset(camid,0,4);memset(boxke,0,8);memset(negok,0,64); caid=1802; // default line=skipspace(line); if(*line=='[') { // parse camid & caid line++; if(GetHex(line,buff,4)!=4) { d(printf("smartcarddatanagra2: format error: camid\n")) return false; } memcpy(camid,buff,4); line=skipspace(line); if(*line=='/') { line++; if(GetHex(line,buff,2)!=2) { d(printf("smartcarddatanagra2: format error: caid\n")) return false; } caid=buff[0]*256+buff[1]; line=skipspace(line); } if(!*line==']') { d(printf("smartcarddatanagra2: format error: closing ]\n")) return false; } line++; } line=skipspace(line); int l; if((l=GetHex(line,buff,sizeof(buff),false))!=8) { d(printf("smartcarddatanagra2: format error: boxkey\n")) return false; } memcpy(boxke,buff,8); if((l=GetHex(line,buff,sizeof(buff),false))!=64) { d(printf("smartcarddatanagra2: format error: negok\n")) return false; } memcpy(negok,buff,64); return true; } // -- cSmartCardNagra2 --------------------------------------------------------- #define ADDRLEN 4 // Address length in EMM commands #define MAX_PROV 16 #define RECOVER_TIME 100 // Time in ms which the card needs to recover after // a failed command static const struct StatusMsg msgs[] = { { { 0x00,0x00 }, "Instruction executed without error", true }, { { 0x55,0x00 }, "Instruction executed without error", true }, { { 0x57,0x00 }, "CAM string rejected", false }, { { 0x58,0x00 }, "Instruction executed without error", true }, { { 0x9D,0x00 }, "Decoding successfull", true }, { { 0x90,0x00 }, "ChID missing. Not subscribed?", false }, { { 0x93,0x00 }, "ChID out of date. Subscription expired?", false }, { { 0x9C,0x00 }, "Master key error", false }, { { 0x9E,0x00 }, "Wrong decryption key", false }, { { 0x9F,0x00 }, "Missing key", false }, { { 0x70,0x00 }, "Wrong hex serial", false }, { { 0x71,0x00 }, "Wrong provider", false }, { { 0x72,0x00 }, "Wrong provider group", false }, { { 0x73,0x00 }, "Wrong provider group", false }, { { 0x7C,0x00 }, "Wrong signature", false }, { { 0x7D,0x00 }, "Masterkey missing", false }, { { 0x7E,0x00 }, "Wrong provider identifier", false }, { { 0x7F,0x00 }, "Invalid nano", false }, { { 0x54,0x00 }, "No more ChID's", true }, { { 0xFF,0xFF }, 0, false } }; static const struct CardConfig cardCfg = { SM_8O2,3000,100 }; class cSmartCardNagra2 : public cSmartCard, private cIdSet { private: unsigned char buff[MAX_LEN+1]; unsigned char camid[4]; unsigned char boxke[8]; unsigned char negok[64]; IDEA_KEY_SCHEDULE ksSession; int caid; cTimeMs recoverTime; // static void ReverseMem(unsigned char *vIn, int len); void Signature(unsigned char *sig, const unsigned char *vkey,const unsigned char *msg, int len); bool NegotiateSessionKey(void); int DoCmd(unsigned char *cmd); public: cSmartCardNagra2(void); virtual bool Init(void); virtual bool DumpDatatypes(void); virtual bool DumpDatatype(unsigned char dtbyte); 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); }; cSmartCardNagra2::cSmartCardNagra2(void) : cSmartCard(&cardCfg,msgs) { memset(camid,0,4);memset(boxke,0,8);memset(negok,0,64); } void cSmartCardNagra2::ReverseMem(unsigned char *vIn, int len) { unsigned char temp; for(int i=0; i < (len/2); i++) { temp = vIn[i]; vIn[i] = vIn[len-i-1]; vIn[len-i-1] = temp; } } void cSmartCardNagra2::Signature(unsigned char *sig, const unsigned char *vkey,const unsigned char *msg, int len) { IDEA_KEY_SCHEDULE ks; unsigned char v[8]; unsigned char b200[16]; unsigned char b0f0[8]; memcpy(b200,vkey,sizeof(b200)); for(int i=0; i<len; i+=8) { idea_set_encrypt_key(b200,&ks); memset(v,0,sizeof(v)); idea_cbc_encrypt(msg+i,b0f0,8,&ks,v,IDEA_DECRYPT); for(int j=7; j>=0; j--) b0f0[j]^=msg[i+j]; memcpy(b200+0,b0f0,8); memcpy(b200+8,b0f0,8); } memcpy(sig,b0f0,8); //printf("SIGNATURE: ");DUMP(vkey,16);DUMP(msg,len);DUMP(sig,8); return; } bool cSmartCardNagra2::NegotiateSessionKey(void) { unsigned char cmd2a[] = {0x21, 0x00, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0x2A, 0x00, 0x42, 0x00}; unsigned char cmd2b[] = {0x21, 0x40, 0x48, 0xA0, 0xCA, 0x00, 0x00, 0x42, 0x2B, 0x40, 0x27, 0x54, 0xd1, 0x26, 0xe7, 0xe2, 0x40, 0x20, 0xd1, 0x66, 0xf4, 0x18, 0x97, 0x9d, 0x5f, 0x16, 0x8f, 0x7f, 0x7a, 0x55, 0x15, 0x82, 0x31, 0x14, 0x06, 0x57, 0x1a, 0x3f, 0xf0, 0x75, 0x62, 0x41, 0xc2, 0x84, 0xda, 0x4c, 0x2e, 0x84, 0xe9, 0x29, 0x13, 0x81, 0xee, 0xd6, 0xa9, 0xf5, 0xe9, 0xdb, 0xaf, 0x22, 0x51, 0x3d, 0x44, 0xb3, 0x20, 0x83, 0xde, 0xcb, 0x5f, 0x35, 0x2b, 0xb0, 0xce, 0x70, 0x02, 0x00}; unsigned char negot[64]; unsigned char idea1[16]; unsigned char idea2[16]; unsigned char sign1[8]; unsigned char sign2[8]; unsigned char sessi[16]; int r; if((r=DoCmd(cmd2a))<=0 || !Status()) { di(printf("smartcardnagra2: CMD$2A failed\n")) return false; } { ReverseMem(buff+5, 64); unsigned char vFixed[] = {0,1,2,3}; BN_CTX *ctx = BN_CTX_new(); BIGNUM *bnN = BN_CTX_get(ctx); BIGNUM *bnE = BN_CTX_get(ctx); BIGNUM *bnCT = BN_CTX_get(ctx); BIGNUM *bnPT = BN_CTX_get(ctx); BN_bin2bn(negok, 64, bnN); BN_bin2bn(vFixed+3, 1, bnE); BN_bin2bn(buff+5, 64, bnCT); BN_mod_exp(bnPT, bnCT, bnE, bnN, ctx); memset(negot, 0, 64); BN_bn2bin(bnPT, negot + (64-BN_num_bytes(bnPT))); BN_bin2bn(negot, 64, bnCT); BN_mod_exp(bnPT, bnCT, bnE, bnN, ctx); memset(cmd2b+10, 0, 64); BN_bn2bin(bnPT, cmd2b+10 + (64-BN_num_bytes(bnPT))); BN_CTX_end(ctx); ReverseMem(cmd2b+10, 64); ReverseMem(negot, 64); memcpy(idea1, boxke, 8); memcpy(idea1+8, camid, 4); idea1[12] = ~camid[0]; idea1[13] = ~camid[1]; idea1[14] = ~camid[2]; idea1[15] = ~camid[3]; Signature(sign1, idea1, negot, 32); memcpy(idea2,sign1,8); memcpy(idea2+8,sign1,8); Signature(sign2, idea2, negot, 32); memcpy(sessi,sign1,8); memcpy(sessi+8,sign2,8); IDEA_KEY_SCHEDULE ks; idea_set_encrypt_key(sessi,&ks); idea_set_decrypt_key(&ks,&ksSession); } if((r=DoCmd(cmd2b))<=0 || !Status()) { di(printf("smartcardnagra2: CMD$2B failed\n")) return false; } di(printf("smartcardnagra2: Session Key ")) DUMP(sessi, 16); return true; } bool cSmartCardNagra2::DumpDatatype(unsigned char dtbyte) { static unsigned char cmd22[] = {0x21, 0x00, 0x09, 0xA0, 0xCA, 0x00, 0x00, 0x03, 0x22, 0x01, 0x00, 0x07, 0x3E}; int r; unsigned char dtactualsize; cmd22[0x0A] = dtbyte; while(true) { cmd22[0x0B] = 7; if((r=DoCmd(cmd22))<=0 || !Status() || r!=13) { di(printf("smartcardnagra2: DT read failed\n")) return false; } dtactualsize = buff[5]; if(!dtactualsize) break; cmd22[0x0A] = dtbyte | 0xC0; cmd22[0x0B] = dtactualsize + 3; if((r=DoCmd(cmd22))<=0 || !Status() || r!=(dtactualsize+9)) { di(printf("smartcardnagra2: DT read failed\n")) return false; } cmd22[0x0A] = dtbyte | 0x80; } return true; } bool cSmartCardNagra2::DumpDatatypes(void) { static unsigned char cmdc7[] = {0x21, 0x00, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0xC7, 0x00, 0x04, 0x82}; int r; unsigned char dtbyte = 0; unsigned short dtflags; while(true) { if((r=DoCmd(cmdc7))<=0 || !Status() || r!=10) { di(printf("smartcardnagra2: Determine updated DTs failed\n")) return false; } memcpy(&dtflags,buff+5,2); if(!dtflags) break; for(dtbyte = 0; dtbyte < 16; dtbyte++) if(dtflags & (0x01 << dtbyte)) DumpDatatype(dtbyte); } return true; } bool cSmartCardNagra2::Init(void) { ResetIdSet(); recoverTime.Set(-RECOVER_TIME); if(atr->histLen<5 || memcmp(atr->hist,"DNASP",5)) { di(printf("smartcardnagra2: doesn't looks like a Nagra2 card\n")) return false; } infoStr.Begin(); infoStr.Strcat("Nagra2 smartcard\n"); int r; static unsigned char cmdsz[] = {0x21, 0xC1, 0x01, 0xA0, 0x41}; if((r=DoCmd(cmdsz))<=0 || !Status() || r!=5) { di(printf("smartcardnagra2: Set CMD maximum lenght failed\n")) return false; } static unsigned char cmdc0[] = {0x21, 0x00, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x06, 0x87}; if((r=DoCmd(cmdc0))<=0 || !Status() || r!=12) { di(printf("smartcardnagra2: Query CAM status failed\n")) return false; } DumpDatatypes(); static unsigned char cmd12[] = {0x21, 0x40, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0x12, 0x00, 0x06, 0x15}; if((r=DoCmd(cmd12))<=0 || !Status() || r!=12) { di(printf("smartcardnagra2: Query CAMID failed\n")) return false; } memcpy(camid, buff+5, 4); cSmartCardDataNagra2 *entry=0; cSmartCardDataNagra2 cd(camid); if(entry=(cSmartCardDataNagra2 *)smartcards.FindCardData(&cd)) { //printf("smartcardnagra2: CAID %X\n",entry->caid); caid = entry->caid; memcpy(boxke,entry->boxke,8); memcpy(negok,entry->negok,64); } else { di(printf("smartcardnagra2: No configuration for this card found\n")) return false; } if(!NegotiateSessionKey()) return false; DumpDatatypes(); infoStr.Finish(); return true; } bool cSmartCardNagra2::CanHandle(unsigned short CaId) { return (CaId==caid); } bool cSmartCardNagra2::Decode(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw) { int r = 0; if(!NegotiateSessionKey()) return false; unsigned char cmd07[8+0x8F+1+1]; static const unsigned char cmd07Head[] = {0x21, 0x00, 0x95, 0xA0, 0xCA, 0x00, 0x00, 0x8F}; memcpy(cmd07,cmd07Head,sizeof(cmd07Head)); memcpy(cmd07+8, data+3, 0x8F); cmd07[8+0x95] = 0x02; if( (r=DoCmd(cmd07))<=0 || !Status() || r!=8) return false; recoverTime.Set(); static unsigned char cmdc0[] = {0x21, 0x00, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x06, 0x87}; for(int retry = 0; ; retry++) { if( (r=DoCmd(cmdc0))>0 && Status() && r==12) break; if( retry == 7 ) return false; } if( (buff[8] & 0x06) != 0x06 ) return false; unsigned char cmd1c[] = {0x21, 0x00, 0x08, 0xA0, 0xCA, 0x00, 0x00, 0x02, 0x1C, 0x00, 0x36, 0x6B}; if( (r=DoCmd(cmd1c))<=0 || !Status() || r!=60) return false; unsigned char v[8]; memset(v,0,sizeof(v)); idea_cbc_encrypt(buff+7 ,cw+8,8,&ksSession,v,IDEA_DECRYPT); memset(v,0,sizeof(v)); idea_cbc_encrypt(buff+33,cw+0,8,&ksSession,v,IDEA_DECRYPT); return true; } bool cSmartCardNagra2::Update(int pid, int caid, const unsigned char *data) { int r = 0; unsigned char cmd04[113] = {0x21, 0x00, 0x6D, 0xA0, 0xCA, 0x00, 0x00, 0x67}; cmd04[111] = 0x02; if( (data[1]!=0x70) || (data[2]!=0x6C) || (data[9]!=0x65) ) return false; int emmtype = -1; //if( (data[0]==0x82) && ((data[3] | data[4] | data [5] | data[6]) == 0x00) ) emmtype = 0; //if( (data[0]==0x83) && ((data[3] | data[4] | data [5]) != 0x00) && (data[6] == 0) && (data[7]==0x10) ) emmtype = 1; //if( (data[0]==0x83) && ((data[3] | data[4] | data [5]) != 0x00) && (data[6] != 0) && (data[7]==0x00) ) emmtype = 2; if( (data[0]==0x82) ) emmtype = 0; if( (data[0]==0x83) && (data[7]==0x10) ) emmtype = 1; if( (data[0]==0x83) && (data[7]==0x00) ) emmtype = 2; if( emmtype < 0) { di(printf("\nNAGRA2: EMM %i\n", emmtype)) DUMP(data,111); return false; } if( (emmtype > 0) && ( (camid[0] != data[5]) || (camid[1] != data[4]) || (camid[2] != data[3]) ) ) return false; if( (emmtype == 2) && (camid[3] != data[6]) ) return false; //di(printf("\nNAGRA2: EMM %i\n", emmtype)) memcpy(cmd04+8, data+8, 0x67); // Beg Hardcoded blockers // //if(emmtype == 2) return false; // No "U" commands //if(emmtype == 1) return false; // No "S" commands //if(emmtype == 0) return false; // No "G" commands // // End Hardcoded blockers if( (r=DoCmd(cmd04))>0 && Status() && r==8) return true; return false; } int cSmartCardNagra2::DoCmd(unsigned char *cmd) { int len=cmd[2]+3; cmd[len]=XorSum(cmd,len); // wait until recover time is over int r=RECOVER_TIME-recoverTime.Elapsed(); if(r>0) { di(printf("NAGRA2: recover time, waiting %d ms\n",r)) cCondWait::SleepMs(r+1); } di(printf("NAGRA2: CMD ->")) DUMP(cmd,len+1); r=-1; if( SerWrite(cmd,len+1)>0 && (len = SerRead(buff,3,cardCfg.workTO))==3 ) { if(SerRead(buff+len,buff[2]+1)<=0) { recoverTime.Set(); di(printf("NAGRA2: setting %d ms recover time\n",RECOVER_TIME)) return -1; } len+=buff[2]+1; if( (XorSum(buff,len)==0x00) && (buff[0] == 0x12) ) { r=len; } } di(printf("NAGRA2: RES <-")) DUMP(buff,len); if(r<=0) { recoverTime.Set(); di(printf("NAGRA2: setting %d ms recover time\n",RECOVER_TIME)) } return r; } // -- cSmartCardLinkNagra2 ----------------------------------------------------- class cSmartCardLinkNagra2 : public cSmartCardLink { public: cSmartCardLinkNagra2(void):cSmartCardLink(SC_NAME,SC_ID) {} virtual cSmartCard *Create(void) { return new cSmartCardNagra2(); } virtual cSmartCardData *CreateData(void) { return new cSmartCardDataNagra2; } }; static cSmartCardLinkNagra2 staticScInit;
Note:
See TracTickets
for help on using tickets.
Same ticket as 46. HD+ is based on Nagra N3.