|
SASC
DVBSoftCAM
|
Inheritance diagram for cSystemNagra2:Public Member Functions | |
| cSystemNagra2 (void) | |
| ~cSystemNagra2 () | |
| virtual bool | ProcessECM (const cEcmInfo *ecm, unsigned char *data) |
| virtual void | ProcessEMM (int pid, int caid, const unsigned char *buffer) |
| cSystemNagra2 (void) | |
| ~cSystemNagra2 () | |
| virtual bool | ProcessECM (const cEcmInfo *ecm, unsigned char *data) |
| virtual void | ProcessEMM (int pid, int caid, const unsigned char *buffer) |
| cSystemNagra2::cSystemNagra2 | ( | void | ) |
Definition at line 1270 of file nagra2.c.
References cSystem::hasLogger.
:cSystem(SYSTEM_NAME,SYSTEM_PRI) { hasLogger=true; lastEcmId=lastEmmId=0; ecmP=emmP=0; }
| cSystemNagra2::~cSystemNagra2 | ( | ) |
| cSystemNagra2::cSystemNagra2 | ( | void | ) |
| cSystemNagra2::~cSystemNagra2 | ( | ) |
| bool cSystemNagra2::ProcessECM | ( | const cEcmInfo * | ecm, |
| unsigned char * | data | ||
| ) | [virtual] |
Implements cSystem.
Definition at line 1283 of file nagra2.c.
References cEcmInfo::caId, cN2Prov::CanHandle(), cSystem::cw, cNagra2::DecryptECM(), cSystem::doLog, cTimeMs::Elapsed(), cPlainKeys::FindKey(), cPlainKeys::FindKeyNoTrig(), cPlainKey::Get(), cN2Providers::GetProv(), cN2Prov::HasFlags(), HEXDUMP, i, id, keys, L_SYS_ECM, L_SYS_KEY, L_SYS_RAWECM, LBEND, LBFLUSH, LBPUT, LBSTARTF, MBC, cN2Prov::MECM(), minEcmTime, N2FLAG_MECM, N2FLAG_NONE, NA_SOURCE_END, NA_SOURCE_START, cKeySnoop::OK(), cN2Prov::PostDecrypt(), cN2Prov::PrintCaps(), PRINTF, SCT_LEN, cCondWait::SleepMs(), cEcmInfo::source, cSystem::StartLog(), and cN2Prov::SwapCW().
{
#define NA_SOURCE_START 0x8267 // cSource::FromString("S61.5W");
#define NA_SOURCE_END 0x85c8 // cSource::FromString("S148W");
unsigned char odata[15];
memcpy(odata,data,sizeof(odata));
if(ecm->source>=NA_SOURCE_START && ecm->source<=NA_SOURCE_END) {
if(ecm->caId==0x1234) data[5]=0x09; // NA rev 248 morph
else {
if(ecm->source==0x83ca) data[5]=0xC1; // 97W
else if(ecm->source==0x8334 || ecm->source==0x838e) data[5]=0x09; // 82W 91W
else data[5]=0x01;
}
data[6]&=0x1F;
data[7]=(data[7]&0x10)|0x86;
data[8]=0;
data[9]=(data[9]&0x80)|0x08;
}
int cmdLen=data[4]-5;
int id=(data[5]*256)+data[6];
cTimeMs minTime;
if(id==0x4101) StartLog(ecm,0x1881); // D+ AU
if(id==0x0505 || id==0x0503 || id==0x0511) id=0x0501; // PremStar ugly again :(
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.FindKeyNoTrig('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) ecmP->PrintCaps(L_SYS_ECM);
}
lastEcmId=id;
if(ecmP) ecmP->PostDecrypt(true);
HEXDUMP(L_SYS_RAWECM,buff,cmdLen,"Nagra2 RAWECM");
int l=0, mecmAlgo=0;
LBSTARTF(L_SYS_ECM);
bool contFail=false;
for(int i=(buff[14]&0x10)?16:20; 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 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 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,odata,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;
}
| virtual bool cSystemNagra2::ProcessECM | ( | const cEcmInfo * | ecm, |
| unsigned char * | data | ||
| ) | [virtual] |
Implements cSystem.
| virtual void cSystemNagra2::ProcessEMM | ( | int | pid, |
| int | caid, | ||
| const unsigned char * | buffer | ||
| ) | [virtual] |
Reimplemented from cSystem.
| void cSystemNagra2::ProcessEMM | ( | int | pid, |
| int | caid, | ||
| const unsigned char * | buffer | ||
| ) | [virtual] |
Reimplemented from cSystem.
Definition at line 1403 of file nagra2.c.
References cN2Prov::CanHandle(), cNagra2::DecryptEMM(), cPlainKeys::FindKeyNoTrig(), cSystem::FoundKey(), cPlainKey::Get(), cBN::GetLE(), cN2Providers::GetProv(), cN2Prov::HasFlags(), HEXDUMP, i, id, cPlainKeyNagra::IsBNKey(), keys, L_SYS_EMM, L_SYS_RAWEMM, LBEND, LBFLUSH, LBPUT, LBSTARTF, MATCH_ID, MBC, N2_MAGIC, N2FLAG_Bx, N2FLAG_Ex, N2FLAG_NONE, N2FLAG_POSTAU, cSystem::NewKey(), cPlainKeys::NewKey(), cN2Prov::PostDecrypt(), cN2Prov::PostProcAU(), cN2Prov::PrintCaps(), PRINTF, cN2Prov::ProcessBx(), cN2Prov::ProcessEx(), cBN::PutLE(), and SCT_LEN.
{
int cmdLen=buffer[9]-5;
int id=buffer[10]*256+buffer[11];
if(buffer[0]==0x83 && dropEMMs) return; // skip EMM-S if disabled
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=(MATCH_ID(id,0x4101) || MATCH_ID(id,0x7101)) ? 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.FindKeyNoTrig('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.FindKeyNoTrig('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.FindKeyNoTrig('N',id,MBC(N2_MAGIC,keyset),24))) {
if(!(pk=keys.FindKeyNoTrig('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) emmP->PrintCaps(L_SYS_EMM);
}
lastEmmId=id;
if(emmP) emmP->PostDecrypt(false);
HEXDUMP(L_SYS_RAWEMM,emmdata,cmdLen,"Nagra2 RAWEMM");
if(buffer[0]==0x82) 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+3]|0xF3)+1)&0xFF) != 0) {
int len=emmdata[i+2];
int off=emmdata[i+5];
int ulen=emmdata[i+6];
if(len>0 && ulen>0 && off+ulen<=len) {
int ks=emmdata[i+3], kn;
if(ks==0x06 || ks==0x46) kn=(ks>>6)&1; else kn=MBC(N2_MAGIC,ks);
unsigned char key[256];
memset(key,0,sizeof(key));
if((pk=keys.FindKeyNoTrig('N',id,kn,len))) {
if(cPlainKeyNagra::IsBNKey(kn)) { pk->Get(n); n.PutLE(key,len); }
else pk->Get(key);
}
bool ok=false;
if((emmdata[i+1]&0x7F)==0) ok=true;
else {
if(emmP && emmP->HasFlags(N2FLAG_POSTAU)) {
if(emmP->PostProcAU(id,&emmdata[i])) ok=true;
}
else PRINTF(L_SYS_EMM,"POSTAU for provider %04x not supported",id);
}
if(ok) {
memcpy(&key[off],&emmdata[i+7],ulen);
FoundKey();
if(cPlainKeyNagra::IsBNKey(kn)) {
n.GetLE(key,len);
if(keys.NewKey('N',id,kn,n,len)) NewKey();
}
else {
if(keys.NewKey('N',id,kn,key,len)) NewKey();
}
}
i+=ulen;
}
else PRINTF(L_SYS_EMM,"nano42 key size mismatch len=%d off=%d ulen=%d",len,off,ulen);
}
else PRINTF(L_SYS_EMM,"nano42 0xf3 status exceeded");
i+=7;
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();
}
i+=emmdata[i+1]+2;
break;
case 0x83: // change data prov. id
id=(emmdata[i+1]<<8)|emmdata[i+2];
i+=3;
break;
case 0xB0: case 0xB1: case 0xB2: case 0xB3: // Update with ROM CPU code
case 0xB4: case 0xB5: case 0xB6: case 0xB7:
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
case 0xBC: case 0xBD: case 0xBE: case 0xBF:
{
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 0xA0: i+=5; break; // CamID target update
case 0xA3: i+=4; break; // Cam group target update
case 0xA4: i+=emmdata[i+1]+2+4; break; // conditional (always no match assumed for now)
case 0xA6: // updates tier/blackout
if(emmdata[i+4]==0xFD && emmdata[i+5]==0x98) i+=(emmdata[i+1]+emmdata[i+3]+4);
else i+=15;
break;
case 0xAA: i+=emmdata[i+1]+5; break;
case 0xAD: i+=emmdata[i+1]+2; break;
case 0xA2:
case 0xAE: i+=11; break;
case 0x01: i+=3; break;
case 0x10: i+=18; break;
case 0x12: i+=emmdata[i+1]+2; break; // create tier
case 0x20: i+=19; break; // modify tier
case 0x9F: i+=6; break;
case 0xE3: // Eeprom update
{
int ex=emmdata[i]&15;
if(!emmP || !emmP->HasFlags(N2FLAG_Ex)) {
i+=emmdata[i+4]+5;
PRINTF(L_SYS_EMM,"E%X for provider %04x not supported",ex,id);
break;
}
int r;
if((r=emmP->ProcessEx(emmdata,cmdLen,i+1))>0)
i+=r;
else {
PRINTF(L_SYS_EMM,"E%X executing failed for %04x",ex,id);
i=cmdLen;
}
break;
}
case 0x13:
case 0x14:
case 0x15:
case 0x85:
case 0xE1:
case 0xE2:
case 0x00: i=cmdLen; break; // end of processing
default:
if(!contFail) LBPUT("unknown EMM nano");
LBPUT(" %02x",emmdata[i]);
contFail=true;
i++;
continue;
}
LBFLUSH(); contFail=false;
}
LBEND();
}