|
SASC
DVBSoftCAM
|
Inheritance diagram for cSystemNagra:Public Member Functions | |
| cSystemNagra (void) | |
| virtual | ~cSystemNagra () |
| virtual bool | ProcessECM (const cEcmInfo *ecm, unsigned char *data) |
| virtual void | ProcessEMM (int pid, int caid, const unsigned char *buffer) |
| cSystemNagra (void) | |
| virtual | ~cSystemNagra () |
| virtual bool | ProcessECM (const cEcmInfo *ecm, unsigned char *data) |
| virtual void | ProcessEMM (int pid, int caid, const unsigned char *buffer) |
| cSystemNagra::cSystemNagra | ( | void | ) |
Definition at line 697 of file nagra1.c.
References cSystem::hasLogger.
:cSystem(SYSTEM_NAME,SYSTEM_PRI) { emu=0; memset(mecmTable,0,sizeof(mecmTable)); hasLogger=true; }
| cSystemNagra::cSystemNagra | ( | void | ) |
| virtual cSystemNagra::~cSystemNagra | ( | ) | [virtual] |
| bool cSystemNagra::ProcessECM | ( | const cEcmInfo * | ecm, |
| unsigned char * | data | ||
| ) | [virtual] |
Implements cSystem.
Definition at line 721 of file nagra1.c.
References ADDC3, AUTOMEM, cNagra::CreateRSAPair(), cSystem::cw, cNagraDES::Decrypt(), cNagra1::DecryptECM(), cSystem::doLog, cTimeMs::Elapsed(), cPlainKeys::FindKey(), cPlainKey::Get(), i, keys, KEYSET, L_SYS_ECM, L_SYS_KEY, MBC3, minEcmTime, cKeySnoop::OK(), PRINTF, cNagra::pubExp, RotateBytes(), cNagraDES::SigCheck(), and cCondWait::SleepMs().
{
int cmdLen=data[4];
int id=(data[5]*256)+data[6];
cTimeMs minTime;
if(data[3]!=0x03) {
PRINTF(L_SYS_ECM,"invalid ECM");
return false;
}
data+=7;
if(data[0]!=0x10) {
PRINTF(L_SYS_ECM,"no ECM data available");
return false;
}
const int ecmLen=data[1];
const int verType=(data[2]>>3)&1;
const int keynr=(data[2]>>4)&1;
const int ecmParm=data[2]&7;
bool decrypt;
if(ecmParm==7) decrypt=false;
else if(ecmParm==5) decrypt=true;
else {
PRINTF(L_SYS_ECM,"unknown ecmParm, ignoring ECM");
return false;
}
cKeySnoop ks(this,'N',id,keynr);
unsigned char sessionKey[8], verifyKey[8];
bool hasVerifyKey=false;
cPlainKey *pk;
if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(0,0,verType)),sizeof(verifyKey)))) {
pk->Get(verifyKey);
hasVerifyKey=true;
}
else if(doLog) PRINTF(L_SYS_KEY,"missing %04X V TYP%d key (non-fatal)",id,verType);
if(!(pk=keys.FindKey('N',id,keynr,sizeof(sessionKey)))) return false;
pk->Get(sessionKey);
const int desLen=(ecmLen-9) & ~7; // datalen - signature - ks byte
unsigned char *decrypted=AUTOMEM(desLen);
for(int i=(desLen/8)-1; decrypt && i>=0; i--) {
const int off=i*8;
Decrypt(data+11+off,sessionKey,decrypted+off);
}
if(decrypt && hasVerifyKey && !SigCheck(decrypted,data+3,verifyKey,desLen/8)) {
PRINTF(L_SYS_ECM,"signature check failed in DES decrypt");
return false;
}
int cwEvenMecmIndex=-1, cwOddMecmIndex=-1;
switch(decrypted[0]) {
case 0x10: // Whole CW
cwOddMecmIndex=decrypted[1];
memcpy(cw+8,&decrypted[2],8);
cwEvenMecmIndex=decrypted[10];
memcpy(cw,&decrypted[11],8);
break;
case 0x11: // Odd CW
cwOddMecmIndex=decrypted[1];
memcpy(cw+8, &decrypted[2],8);
break;
case 0x12: // Even CW
cwEvenMecmIndex=decrypted[1];
memcpy(cw,&decrypted[2],8);
break;
default: PRINTF(L_SYS_ECM,"failed to get CW"); return false;
}
const unsigned char * const mecmData=data+(ecmLen+2);
const int mecmRSALen=mecmData[1]-4;
if((cmdLen-(ecmLen+2))>64 && (*mecmData==0x20 || *mecmData==0x39)) {
if(mecmRSALen!=64) {
if(mecmRSALen>64 && doLog)
PRINTF(L_SYS_ECM,"ECM too big (len: %d)",mecmRSALen);
return false;
}
const int mecmProvId=mecmData[2]*256+mecmData[3];
const int keyType=(mecmData[4]>>3)&1;
const int pkey=mecmData[4]&3;
cBN e1, n1, n2;
cPlainKey *pk;
if(!(pk=keys.FindKey('N',mecmProvId,MBC3('E','1',KEYSET(0,pkey,keyType)),-1))) {
if(doLog) PRINTF(L_SYS_KEY,"missing %04x E1 PK%d TYP%d key",mecmProvId,pkey,keyType);
return false;
}
pk->Get(e1);
if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','1',KEYSET(0,pkey,keyType)),-1))) {
if(doLog) PRINTF(L_SYS_KEY,"missing %04x N1 PK%d TYP%d key",mecmProvId,pkey,keyType);
return false;
}
pk->Get(n1);
if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','2',KEYSET(0,0,keyType)),-1))) {
if(doLog) PRINTF(L_SYS_KEY,"missing %04x N2 TYP%d key",mecmProvId,keyType);
return false;
}
pk->Get(n2);
hasVerifyKey=false;
if((pk=keys.FindKey('N',mecmProvId,ADDC3('V',KEYSET(0,0,keyType)),sizeof(verifyKey)))) {
pk->Get(verifyKey);
hasVerifyKey=true;
}
else if(doLog) PRINTF(L_SYS_KEY,"missing %04x V TYP%d key (non-fatal)",mecmProvId,keyType);
unsigned char *decrMecmData=AUTOMEM(mecmRSALen);
if(!DecryptECM(&mecmData[4],decrMecmData,hasVerifyKey?verifyKey:0,mecmRSALen,e1,n1,n2))
return false;
if(*mecmData==0x39 || (*mecmData==0x20 && (mecmProvId&0xFE00)==0x4800)) {
unsigned char xor_table[64];
for(int i=sizeof(xor_table)-1; i>=0; i--) xor_table[i]=63-i;
CreateRSAPair(&decrMecmData[24],xor_table,e1,n1);
// new XOR table for MECM data
cBNctx ctx;
cBN x;
BN_mod_exp(x,e1,pubExp,n1,ctx);
int l=sizeof(xor_table)-BN_num_bytes(x);
memset(xor_table,0,l);
BN_bn2bin(x,xor_table+l);
RotateBytes(xor_table,sizeof(xor_table));
// And finally, new MECM table
for(int i=39; i<mecmRSALen; i++) decrMecmData[i]^=xor_table[i-39];
memcpy(&decrMecmData[3],&decrMecmData[39],mecmRSALen-39);
}
if(decrMecmData[0]==0x2F && decrMecmData[1]==mecmData[2] && decrMecmData[2]==mecmData[3])
WriteTable(decrMecmData+4,decrMecmData[3]*2);
}
if(cwOddMecmIndex>=0 && cwOddMecmIndex<0x80) {
const int d=cwOddMecmIndex*2;
for(int i=0 ; i<8 ; i++) cw[i+8]^=mecmTable[(d+i)&0xFF]; // odd
}
if(cwEvenMecmIndex>=0 && cwEvenMecmIndex<0x80) {
const int d=cwEvenMecmIndex*2;
for(int i=0 ; i<8 ; i++) cw[i]^=mecmTable[(d+i)&0xFF]; // even
}
ks.OK(pk);
int i=minEcmTime-minTime.Elapsed();
if(i>0) cCondWait::SleepMs(i);
return true;
}
| virtual bool cSystemNagra::ProcessECM | ( | const cEcmInfo * | ecm, |
| unsigned char * | data | ||
| ) | [virtual] |
Implements cSystem.
| virtual void cSystemNagra::ProcessEMM | ( | int | pid, |
| int | caid, | ||
| const unsigned char * | buffer | ||
| ) | [virtual] |
Reimplemented from cSystem.
| void cSystemNagra::ProcessEMM | ( | int | pid, |
| int | caid, | ||
| const unsigned char * | buffer | ||
| ) | [virtual] |
Reimplemented from cSystem.
Definition at line 866 of file nagra1.c.
References ADDC3, cNagra::CreateRSAPair(), cNagra1::DecryptEMM(), cPlainKeys::FindKey(), cSystem::FoundKey(), cPlainKey::Get(), cEmu::GetOpKeys(), cEmu::GetPkKeys(), HEXDUMP, i, cEmu::Init(), keys, KEYSET, L_SYS_EMM, L_SYS_RAWEMM, cEmu::Matches(), MBC, MBC3, cSystem::NewKey(), cPlainKeys::NewKey(), PRINTF, and SCT_LEN.
{
const int id=buffer[10]*256+buffer[11];
static const unsigned char tester[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x4B };
if(memcmp(&buffer[3],tester,sizeof(tester)) || SCT_LEN(buffer)<(12+9+64)) {
PRINTF(L_SYS_EMM,"not a valid EMM structure");
return;
}
const int pkey=(buffer[12]&3);
cPlainKey *pk;
cBN e1, n1, n2;
if(!(pk=keys.FindKey('N',id,MBC3('E','1',KEYSET(0,pkey,0)),-1))) return;
pk->Get(e1);
if(!(pk=keys.FindKey('N',id,MBC3('N','1',KEYSET(0,pkey,0)),-1))) return;
pk->Get(n1);
unsigned char v[8];
bool hasVerifyKey=false;
if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(0,0,0)),sizeof(v)))) {
pk->Get(v);
hasVerifyKey=true;
}
int mode=(buffer[12]&8) ? 0:2;
unsigned char emmdata[64];
bool r;
do {
switch(mode) {
case 0: // get the ROM10 specific management key
if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(10,0,1)),-1))) return;
pk->Get(n2);
mode=1; break;
case 1: // get the ROM11 specific management keys
if(!(pk=keys.FindKey('N',id,MBC3('E','1',KEYSET(11,pkey,1)),-1))) return;
pk->Get(e1);
if(!(pk=keys.FindKey('N',id,MBC3('N','1',KEYSET(11,pkey,1)),-1))) return;
pk->Get(n1);
if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(11,0,1)),-1))) return;
pk->Get(n2);
hasVerifyKey=false;
if((pk=keys.FindKey('N',id,ADDC3('V',KEYSET(11,0,1)),sizeof(v)))) {
pk->Get(v);
hasVerifyKey=true;
}
mode=-1; break;
case 2: // get the universal management key
if(!(pk=keys.FindKey('N',id,MBC3('N','2',KEYSET(0,0,0)),-1))) return;
pk->Get(n2);
mode=-1; break;
}
r=DecryptEMM(&buffer[12],emmdata,hasVerifyKey?v:0,64,e1,n1,n2);
} while(!r && mode>=0);
if(r) {
HEXDUMP(L_SYS_RAWEMM,emmdata,sizeof(emmdata),"Nagra1 RAWEMM");
unsigned int i=0;
bool gotKeys=false;
unsigned char key0[8], key1[8];
int keyId=(emmdata[i+1]<<8)+emmdata[i+2];
switch(emmdata[i]) { // Check filter type
case 0x00: // One card
i+=7; break;
case 0x01: case 0x02: case 0x03: case 0x04: // Group of cards
case 0x05: case 0x06: case 0x07: case 0x08:
case 0x09: case 0x0A: case 0x0B: case 0x0C:
case 0x0D: case 0x0E: case 0x0F: case 0x10:
case 0x11: case 0x12: case 0x13: case 0x14:
case 0x15: case 0x16: case 0x17: case 0x18:
case 0x19: case 0x1A: case 0x1B: case 0x1C:
case 0x1D: case 0x1E: case 0x1F: case 0x20:
i+=emmdata[i]+0x7; break;
case 0x3e:
i+=6; break;
case 0x3d: // All cards with same system ID
case 0x3f:
i+=3; break;
}
int nrKeys=0;
while(i<sizeof(emmdata)) {
if((emmdata[i]&0xF0)==0xF0) { // Update with CPU code
const int romNr=emmdata[i]&0x0F;
if(!emu || !emu->Matches(romNr,id)) {
delete emu; emu=0;
PRINTF(L_SYS_EMM,"setting defaults for ROM %d",romNr);
switch(romNr) {
case 3: emu=new cEmuRom3; break;
case 7: emu=new cEmuRom7; break;
case 10: emu=new cEmuRom10; break;
case 11: emu=new cEmuRom11; break;
default: PRINTF(L_SYS_EMM,"unsupported ROM"); return;
}
if(!emu || !emu->Init(romNr,id)) {
delete emu; emu=0;
PRINTF(L_SYS_EMM,"initialization failed for ROM %d",romNr);
return;
}
}
unsigned char ki[2];
if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) {
keyId=(ki[0]<<8)+ki[1];
PRINTF(L_SYS_EMM,"got keys for %04X (ROM %d)",keyId,romNr);
}
unsigned char select[3], pkset[3][15];
select[0]=(keyId>>8)|0x01; // always high id for ECM RSA keys
select[1]=keyId&0xFF;
select[2]=0; // type 0
if(emu->GetPkKeys(&select[0],&pkset[0][0])) {
int pkKeyId=((select[0]<<8)+select[1]);
PRINTF(L_SYS_EMM,"got PK keys for %04X (ROM %d)",pkKeyId,romNr);
for(int i=0; i<3; i++) {
CreateRSAPair(pkset[i],0,e1,n1);
FoundKey();
if(keys.NewKey('N',pkKeyId,ADDC3(MBC('N','1'),KEYSET(0,i,0)),n1,64)) NewKey();
FoundKey();
if(keys.NewKey('N',pkKeyId,ADDC3(MBC('E','1'),KEYSET(0,i,0)),e1,64)) NewKey();
}
}
break; // don't process other nanos
}
else if(emmdata[i]==0x60) { // NULL nano
i+=2;
}
else if(emmdata[i]==0x00) {
i++;
}
else if(emmdata[i]==0x81) {
i++;
}
else if(emmdata[i]==0x83) {
keyId=(emmdata[i+1]<<8)+emmdata[i+2];
i+=3;
}
else if(emmdata[i]==0x42) { // plain Key
if(emmdata[i+1]==0x05) memcpy(key0,&emmdata[i+2],sizeof(key0));
else memcpy(key1,&emmdata[i+2],sizeof(key1));
i+=10;
if(++nrKeys==2) {
gotKeys=true;
PRINTF(L_SYS_EMM,"got keys for %04X (plain)",keyId);
break;
}
}
else {
PRINTF(L_SYS_EMM,"ignored nano %02x",emmdata[i]);
break;
}
}
if(gotKeys) {
FoundKey();
if(keys.NewKey('N',keyId,00,key0,8)) NewKey();
FoundKey();
if(keys.NewKey('N',keyId,01,key1,8)) NewKey();
}
}
}