📄 nagra2.c
字号:
// Calculate P idata[0] |= 0x80; idata[47] |= 1; BN_bin2bn(idata,48,p); BN_add_word(p,(key[21] << 5 ) | ((key[22] & 0xf0) >> 3)); // Calculate Q idata[48] |= 0x80; idata[95] |= 1; BN_bin2bn(idata+48,48,q); BN_add_word(q,(key[22] &0xf << 9 ) | (key[23]<<1));}bool cNagra2::Signature(const unsigned char *vkey, const unsigned char *sig, const unsigned char *msg, int len){ unsigned char buff[16]; memcpy(buff,vkey,sizeof(buff)); for(int i=0; i<len; i+=8) { IdeaKS ks; idea.SetEncKey(buff,&ks); memcpy(buff,buff+8,8); idea.Encrypt(msg+i,8,buff+8,&ks,0); xxor(&buff[8],8,&buff[8],msg+i); } buff[8]&=0x7F; return (memcmp(sig,buff+8,8)==0);}bool cNagra2::DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m){ int sign=in[0] & 0x80; if(rsa.RSA(out,in+1,64,pubExp,m)<=0) { PRINTF(L_SYS_CRYPTO,"first RSA failed (ECM)"); return false; } out[63]|=sign; // sign adjustment if(len>64) memcpy(out+64,in+65,len-64); if(in[0]&0x04) { unsigned char tmp[8]; DES_key_schedule ks1, ks2; RotateBytes(tmp,&key[0],8); DES_key_sched((DES_cblock *)tmp,&ks1); RotateBytes(tmp,&key[8],8); DES_key_sched((DES_cblock *)tmp,&ks2); memset(tmp,0,sizeof(tmp)); for(int i=7; i>=0; i--) RotateBytes(out+8*i,8); DES_ede2_cbc_encrypt(out,out,len,&ks1,&ks2,(DES_cblock *)tmp,DES_DECRYPT); for(int i=7; i>=0; i--) RotateBytes(out+8*i,8); } else idea.Decrypt(out,len,key,0); RotateBytes(out,64); if(rsa.RSA(out,out,64,pubExp,m,false)<=0) { PRINTF(L_SYS_CRYPTO,"second RSA failed (ECM)"); return false; } if(vkey && !Signature(vkey,out,out+8,len-8)) { PRINTF(L_SYS_CRYPTO,"signature failed (ECM)"); return false; } return true;}bool cNagra2::DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m){ int sign=in[0]&0x80; if(rsa.RSA(out,in+1,96,pubExp,m)<=0) { PRINTF(L_SYS_CRYPTO,"first RSA failed (EMM)"); return false; } out[95]|=sign; // sign adjustment cBN exp; if(in[0]&0x08) { // standard IDEA decrypt if(len>96) memcpy(out+96,in+97,len-96); idea.Decrypt(out,len,key,0); BN_set_word(exp,3); } else { // private RSA key expansion CreateRSAPair(key,0,exp,m); } RotateBytes(out,96); if(rsa.RSA(out,out,96,exp,m,false)<=0) { PRINTF(L_SYS_CRYPTO,"second RSA failed (EMM)"); return false; } if(vkey && !Signature(vkey,out,out+8,len-8)) { PRINTF(L_SYS_CRYPTO,"signature failed (EMM)"); return false; } return true;}// -- cSystemNagra2 ------------------------------------------------------------class cSystemNagra2 : public cSystem, protected cNagra2 {private: int lastEcmId, lastEmmId; cN2Prov *ecmP, *emmP;public: cSystemNagra2(void); ~cSystemNagra2(); virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data); virtual void ProcessEMM(int pid, int caid, unsigned char *buffer); };cSystemNagra2::cSystemNagra2(void):cSystem(SYSTEM_NAME,SYSTEM_PRI){ hasLogger=true; lastEcmId=lastEmmId=0; ecmP=emmP=0;}cSystemNagra2::~cSystemNagra2(){ delete ecmP; delete emmP;}bool cSystemNagra2::ProcessECM(const cEcmInfo *ecm, unsigned char *data){ int cmdLen=data[4]-5; int id=(data[5]*256)+data[6]; cTimeMs minTime; if(id==0x4101) StartLog(ecm,0x1881); // D+ AU if(cmdLen<64 || SCT_LEN(data)<cmdLen+10) { if(doLog) PRINTF(L_SYS_ECM,"bad ECM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(data)); return false; } int keyNr=(data[7]&0x10)>>4; cKeySnoop ks(this,'N',id,keyNr); cPlainKey *pk; cBN m1; unsigned char ideaKey[16], vKey[16]; bool hasVerifyKey=false; if(!(pk=keys.FindKey('N',id,MBC('M','1'),-1))) { if(doLog) PRINTF(L_SYS_KEY,"missing %04x M1 key",id); return false; } pk->Get(m1); if((pk=keys.FindKey('N',id,'V',sizeof(vKey)))) { pk->Get(vKey); hasVerifyKey=true; } else if(doLog && id!=lastEcmId) PRINTF(L_SYS_KEY,"missing %04x V key (non-fatal)",id); if(!(pk=keys.FindKey('N',id,keyNr,sizeof(ideaKey)))) return false; pk->Get(ideaKey); unsigned char buff[256]; if(!DecryptECM(data+9,buff,ideaKey,cmdLen,hasVerifyKey?vKey:0,m1)) { if(doLog) PRINTF(L_SYS_ECM,"decrypt of ECM failed (%04x)",id); return false; } if((!ecmP && id!=lastEcmId) || (ecmP && !ecmP->CanHandle(id))) { delete ecmP; ecmP=cN2Providers::GetProv(id,N2FLAG_NONE); if(ecmP) PRINTF(L_SYS_ECM,"provider %04x capabilities%s%s%s%s",id, ecmP->HasFlags(N2FLAG_MECM) ?" MECM":"", ecmP->HasFlags(N2FLAG_Bx) ?" Bx":"", ecmP->HasFlags(N2FLAG_POSTAU) ?" POSTPROCAU":"", ecmP->HasFlags(N2FLAG_INV) ?" INVCW":""); } lastEcmId=id; int l=0, mecmAlgo=0; LBSTARTF(L_SYS_ECM); bool contFail=false; for(int i=16; i<cmdLen-10 && l!=3; ) { switch(buff[i]) { case 0x10: case 0x11: if(buff[i+1]==0x09) { int s=(~buff[i])&1; mecmAlgo=buff[i+2]&0x60; memcpy(cw+(s<<3),&buff[i+3],8); i+=11; l|=(s+1); } else { PRINTF(L_SYS_ECM,"bad length %d in CW nano %02x",buff[i+1],buff[i]); i++; } break; case 0x00: i+=2; break; case 0x13 ... 0x17: i+=4; break; case 0x30 ... 0x36: case 0xB0: i+=buff[i+1]+2; break; default: if(!contFail) LBPUT("unknown ECM nano"); LBPUT(" %02x",buff[i]); contFail=true; i++; continue; } LBFLUSH(); contFail=false; } LBEND(); if(l!=3) return false; if(mecmAlgo>0) { if(ecmP && ecmP->HasFlags(N2FLAG_MECM)) { if(!ecmP->MECM(buff[15],mecmAlgo,cw)) return false; } else { PRINTF(L_SYS_ECM,"MECM for provider %04x not supported",id); return false; } } if(ecmP) ecmP->SwapCW(cw); ks.OK(pk); int i=minEcmTime-minTime.Elapsed(); if(i>0) cCondWait::SleepMs(i); return true;}void cSystemNagra2::ProcessEMM(int pid, int caid, unsigned char *buffer){ int cmdLen=buffer[9]-5; int id=buffer[10]*256+buffer[11]; if(cmdLen<96 || SCT_LEN(buffer)<cmdLen+15) { PRINTF(L_SYS_EMM,"bad EMM message msgLen=%d sctLen=%d",cmdLen,SCT_LEN(buffer)); return; } int keyset=(buffer[12]&0x03); int sel=(buffer[12]&0x10)<<2; int rsasel=(id==0x4101 || id==0x4001) ? 0:sel; // D+ hack int sigsel=(buffer[13]&0x80)>>1; cPlainKey *pk; cBN n; unsigned char ideaKey[24], vKey[16]; bool hasVerifyKey=false; if(!(pk=keys.FindKey('N',id,MBC(N2_MAGIC,keyset+0x10+rsasel),96))) { PRINTF(L_SYS_EMM,"missing %04x NN %.02X RSA key (96 bytes)",id,keyset+0x10+rsasel); return; } pk->Get(n); if((pk=keys.FindKey('N',id,MBC(N2_MAGIC,0x03+sigsel),sizeof(vKey)))) { pk->Get(vKey); hasVerifyKey=true; } else if(id!=lastEmmId) PRINTF(L_SYS_EMM,"missing %04x NN %.02X signature key (non-fatal)",id,0x03+sigsel); if(!(pk=keys.FindKey('N',id,MBC(N2_MAGIC,keyset),24))) { if(!(pk=keys.FindKey('N',id,MBC(N2_MAGIC,keyset+sel),16))) { PRINTF(L_SYS_EMM,"missing %04x NN %.02x IDEA key (24 or 16 bytes)",id,keyset+sel); return; } memset(ideaKey+16,0,8); } pk->Get(ideaKey); unsigned char emmdata[256]; if(!DecryptEMM(buffer+14,emmdata,ideaKey,cmdLen,hasVerifyKey?vKey:0,n)) { PRINTF(L_SYS_EMM,"decrypt of EMM failed (%04x)",id); return; } if((!emmP && id!=lastEmmId) || (emmP && !emmP->CanHandle(id))) { delete emmP; emmP=cN2Providers::GetProv(id,N2FLAG_NONE); if(emmP) PRINTF(L_SYS_EMM,"provider %04x capabilities%s%s%s%s",id, emmP->HasFlags(N2FLAG_MECM) ?" MECM":"", emmP->HasFlags(N2FLAG_Bx) ?" Bx":"", emmP->HasFlags(N2FLAG_POSTAU) ?" POSTPROCAU":"", emmP->HasFlags(N2FLAG_INV) ?" INVCW":""); } lastEmmId=id; HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM"); id=(emmdata[8]<<8)+emmdata[9]; LBSTARTF(L_SYS_EMM); bool contFail=false; for(int i=8+2+4+4; i<cmdLen-22; ) { switch(emmdata[i]) { case 0x42: // plain Key update if(emmdata[i+2]==0x10 && (emmdata[i+3]&0xBF)==0x06 && (emmdata[i+4]&0xF8)==0x08 && emmdata[i+5]==0x00 && emmdata[i+6]==0x10) { if(!emmP || emmP->PostProcAU(id,&emmdata[i])) { FoundKey(); if(keys.NewKey('N',id,(emmdata[i+3]&0x40)>>6,&emmdata[i+7],16)) NewKey(); cLoaders::SaveCache(); } } i+=23; break; case 0xE0: // DN key update if(emmdata[i+1]==0x25) { FoundKey(); if(keys.NewKey('N',id,(emmdata[i+16]&0x40)>>6,&emmdata[i+23],16)) NewKey(); cLoaders::SaveCache(); } i+=39; break; case 0x83: // change data prov. id id=(emmdata[i+1]<<8)|emmdata[i+2]; i+=3; break; case 0xA4: // conditional (always no match assumed for now) i+=emmdata[i+1]+2+4; break; case 0xA6: i+=15; break; case 0xAE: i+=11; break; case 0x13 ... 0x17: // Date i+=4; break; case 0xB0 ... 0xBF: // Update with ROM CPU code { int bx=emmdata[i]&15; if(!emmP || !emmP->HasFlags(N2FLAG_Bx)) { PRINTF(L_SYS_EMM,"B%X for provider %04x not supported",bx,id); i=cmdLen; break; } int r; if((r=emmP->ProcessBx(emmdata,cmdLen,i+1))>0) i+=r; else { PRINTF(L_SYS_EMM,"B%X executing failed for %04x",bx,id); i=cmdLen; } break; } case 0xE3: // Eeprom update i+=emmdata[i+4]+4; break; case 0xE1: case 0xE2: case 0x00: // end of processing i=cmdLen; break; default: if(!contFail) LBPUT("unknown EMM nano"); LBPUT(" %02x",emmdata[i]); contFail=true; i++; continue; } LBFLUSH(); contFail=false; } LBEND();}// -- cSystemLinkNagra2 --------------------------------------------------------static const tI18nPhrase Phrases2[] = { { "Nagra2: AUXserver hostname", "Nagra2: AUXserver Hostname", "", "", "", "", "", "", "Nagra2: AUX-palvelimen osoite", "", "", "", "", }, { "Nagra2: AUXserver port", "Nagra2: AUXserver Port", "", "", "", "", "", "", "Nagra2: AUX-palvelimen portti", "", "", "", "", }, { "Nagra2: AUXserver password", "Nagra2: AUXserver Passwort", "", "", "", "", "", "", "Nagra2: AUX-palvelimen salasana", "", "", "", "", }, { NULL } };class cSystemLinkNagra2 : public cSystemLink {public: cSystemLinkNagra2(void); virtual bool CanHandle(unsigned short SysId); virtual cSystem *Create(void) { return new cSystemNagra2; } };static cSystemLinkNagra2 staticInitN2;cSystemLinkNagra2::cSystemLinkNagra2(void):cSystemLink(SYSTEM_NAME,SYSTEM_PRI){#ifdef HAS_AUXSRV static const char allowed_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz-."; opts=new cOpts(SYSTEM_NAME,3); opts->Add(new cOptStr("AuxServerAddr","Nagra2: AUXserver hostname",auxAddr,sizeof(auxAddr),allowed_chars)); opts->Add(new cOptInt("AuxServerPort","Nagra2: AUXserver port",&auxPort,0,65535)); opts->Add(new cOptStr("AuxServerPass","Nagra2: AUXserver password",auxPassword,sizeof(auxPassword),allowed_chars)); Feature.AddPhrases(Phrases2);#endif Feature.NeedsKeyFile();}bool cSystemLinkNagra2::CanHandle(unsigned short SysId){ return ((SysId&SYSTEM_MASK)==SYSTEM_NAGRA && (SysId&0xFF)>0) || SysId==SYSTEM_NAGRA_BEV;}#endif //TESTER
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -