📄 nagra1.cpp
字号:
des.Des(out,cardkey,NAGRA_DES_ENCR);
RotateBytes(out,8);
}
bool cNagraDES::SigCheck(const unsigned char *block, const unsigned char *sig, const unsigned char *vkey, const int rounds)
{
unsigned char hash[8];
memcpy(hash,vkey,8);
for(int j=0; j<rounds; j++) {
unsigned char cr[8];
Crypt(block+j*8,hash,cr);
for(int i=0; i<8; i++) hash[i]=cr[i]^block[j*8+i];
}
return (0==memcmp(hash,sig,8));
}
// -- cNagra1 ------------------------------------------------------------------
class cNagra1 : public cNagra, public cNagraDES {
protected:
virtual void CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q);
bool DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2);
bool DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2);
};
bool cNagra1::DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2)
{
cBN result;
if(rsa.RSA(result,&in[2],len,pubExp,n2)<=0) {
dn(printf("nagra: error decrypting ECM (round 1)\n"))
return false;;
}
cBN mod;
BN_set_word(mod,in[0]>>4);
BN_lshift(mod,mod,508);
BN_add(result,result,mod);
if(rsa.RSA(out,64,result,e1,n1,false)!=64) {
dn(printf("nagra: error: result of ECM decryption is not 64 bytes\n"))
return false;
}
if(vkey && !SigCheck(out,&out[56],vkey,7)) {
dn(printf("nagra: ECM decryption failed\n"))
return false;
}
return true;
}
bool cNagra1::DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *vkey, int len, BIGNUM *e1, BIGNUM *n1, BIGNUM *n2)
{
cBN result;
if(rsa.RSA(result,&in[9],len,pubExp,n2)<=0) {
dn(printf("nagra: error decrypting EMM (round 1)\n"))
return false;;
}
cBN mod;
BN_set_word(mod,in[0]>>6);
BN_lshift(mod,mod,510);
BN_add(result,result,mod);
if(rsa.RSA(out,64,result,e1,n1,false)!=64) {
dn(printf("nagra: error: result of EMM decryption is not 64 bytes\n"))
return false;
}
if(!vkey || SigCheck(out,&in[1],vkey,8))
return true;
// We need to use signature exchange method (7blocks emm,1 block signature)
dn(printf("nagra: warning: signature failed,trying signature exchange method\n"))
unsigned char buf[8];
RotateBytes(buf,&in[1],sizeof(buf));
cBN newdata, newsig;
BN_bin2bn(buf,sizeof(buf),newdata);
BN_copy(newsig,result);
BN_mask_bits(newsig,64);
BN_bn2bin(newsig,buf);
RotateBytes(buf,sizeof(buf));
BN_rshift(result,result,64); // delete the lower 64 bits,we saved it
BN_lshift(result,result,64); // before as the new 64 bit signature
BN_add(result,result,newdata);
if(rsa.RSA(out,64,result,e1,n1)!=64) {
dn(printf("nagra: error: result of EMM decryption is not 64 bytes\n"))
return false;
}
if(vkey && !SigCheck(out,buf,vkey,8)) {
dn(printf("nagra: fatal: signature failed in signature exchange method\n"))
return false;
}
return true;
}
void cNagra1::CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q)
{
// Make des_key
unsigned char des_data[32];
unsigned char des_key[8], des_tmp[8];
memcpy(des_data,key,8);
RotateBytes(des_tmp,key,8);
des_tmp[7]=0x00;
Decrypt(des_data,des_tmp,des_key,true);
RotateBytes(des_key,8);
des_key[7]=0x00;
// Calculate P
for(int i=0; i<4; i++) {
const int off=i*8;
memcpy(&des_data[off],&key[4],8);
des_data[off]^=i;
Decrypt(&des_data[off],des_key,des_tmp,true);
memcpy(&des_data[off],des_tmp,8);
}
BN_bin2bn(des_data,32,p);
BN_add_word(p,(key[12]<<4)|((key[13]>>4)&0x0f));
BN_set_bit(p,(BN_num_bytes(p)*8)-1);
// Calculate Q
for(int i=0; i<4; i++) {
const int off=i*8;
memcpy(&des_data[off],&key[4],8);
des_data[off]^=(i+4);
Decrypt(&des_data[off],des_key,des_tmp,true);
memcpy(&des_data[off],des_tmp,8);
}
BN_bin2bn(des_data,32,q);
BN_add_word(q,((key[13]&0x0f)<<8)|key[14]);
BN_set_bit(q,(BN_num_bytes(q)*8)-1);
}
// -- cSystemNagra -------------------------------------------------------------
class cSystemNagra : public cSystem, public cNagra1 {
private:
unsigned char mecmTable[256];
cEmu *emu;
//
void WriteTable(unsigned char *from, int off);
public:
cSystemNagra(void);
virtual ~cSystemNagra();
virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data);
virtual void ProcessEMM(int pid, int caid, unsigned char *buffer);
};
cSystemNagra::cSystemNagra(void)
:cSystem(SYSTEM_NAME,SYSTEM_PRI)
{
emu=0;
memset(mecmTable,0,sizeof(mecmTable));
hasLogger=true;
}
cSystemNagra::~cSystemNagra()
{
delete emu;
}
void cSystemNagra::WriteTable(unsigned char *from, int off)
{
off&=0xFF;
if(off+16<256) memcpy(mecmTable+off,from,16);
else {
int l=256-off;
memcpy(mecmTable+off,from,l);
memcpy(mecmTable,from+l,16-l);
}
}
bool cSystemNagra::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
{
int cmdLen=data[4];
int id=(data[5]*256)+data[6];
cTimeMs minTime;
if(data[3]!=0x03) {
dn(printf("system-nagra: invalid ECM\n"))
return false;
}
data+=7;
if(data[0]!=0x10) {
dn(printf("system-nagra: no ECM data available\n"))
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 {
dn(printf("system-nagra: unknown ecmParm, ignoring ECM\n"))
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) d(printf("system-nagra: missing %04X V TYP%d key (non-fatal)\n",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[desLen];
unsigned char decrypted[16000];
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)) {
dn(printf("system-nagra: signature check failed in DES decrypt\n"))
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: dn(printf("system-nagra: failed to get CW\n")) 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)
d(printf("system-nagra: ECM too big (len: %d)\n",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) d(printf("system-nagra: missing %04x E1 PK%d TYP%d key\n",mecmProvId,pkey,keyType))
return false;
}
pk->Get(e1);
if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','1',KEYSET(0,pkey,keyType)),-1))) {
if(doLog) d(printf("system-nagra: missing %04x N1 PK%d TYP%d key\n",mecmProvId,pkey,keyType))
return false;
}
pk->Get(n1);
if(!(pk=keys.FindKey('N',mecmProvId,MBC3('N','2',KEYSET(0,0,keyType)),-1))) {
if(doLog) d(printf("system-nagra: missing %04x N2 TYP%d key\n",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) d(printf("system-nagra: missing %04x V TYP%d key (non-fatal)\n",mecmProvId,keyType))
// unsigned char decrMecmData[mecmRSALen];
unsigned char decrMecmData[16000];
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;
}
void cSystemNagra::ProcessEMM(int pid, int caid, unsigned char *buffer)
{
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)) {
dl(printf("logger-nagra %d: not a valid EMM structure\n",CardNum()))
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) {
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: 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 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: // Group of cards
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;
dl(printf("logger-nagra %d: setting defaults for ROM %d\n",CardNum(),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: dl(printf("logger-nagra %d: unsupported ROM\n",CardNum())) return;
}
if(!emu || !emu->Init(romNr,id)) {
delete emu; emu=0;
dl(printf("logger-nagra %d: initialization failed for ROM %d\n",CardNum(),romNr))
return;
}
}
unsigned char ki[2];
if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) {
keyId=(ki[0]<<8)+ki[1];
dl(printf("logger-nagra %d: got keys for %04X (ROM %d)\n",CardNum(),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]);
dl(printf("logger-nagra %d: got PK keys for %04X (ROM %d)\n",CardNum(),pkKeyId,romNr))
for(int i=0; i<3; i++) {
CreateRSAPair(pkset[i],0,e1,n1);
cSoftCAM::FoundKey();
if(keys.NewKey('N',pkKeyId,ADDC3(MBC('N','1'),KEYSET(0,i,0)),(void *)n1,64)) cSoftCAM::NewKey();
cSoftCAM::FoundKey();
if(keys.NewKey('N',pkKeyId,ADDC3(MBC('E','1'),KEYSET(0,i,0)),(void *)e1,64)) cSoftCAM::NewKey();
}
cSoftCAM::Save();
}
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;
dl(printf("logger-nagra %d: got keys for %04X (plain)\n",CardNum(),keyId))
break;
}
}
else {
dl(printf("logger-nagra %d: ignored nano %02x\n",CardNum(),emmdata[i]))
break;
}
}
if(gotKeys) {
cSoftCAM::FoundKey();
if(keys.NewKey('N',keyId,00,key0,8)) cSoftCAM::NewKey();
cSoftCAM::FoundKey();
if(keys.NewKey('N',keyId,01,key1,8)) cSoftCAM::NewKey();
cSoftCAM::Save();
}
}
}
// -- cSystemLinkNagra ---------------------------------------------------------
/*
static const tI18nPhrase Phrases[] = {
{ "Nagra: min. ECM processing time",
"Nagra: min. ECM Bearbeitungszeit",
"",
"",
"Nagra: min. ECM bewerkingstijd",
"",
"Nagra: min. dur閑 du processus ECM",
"",
"Nagra: min. ECM:n prosessointiaika",
"Nagra: min. czas przetwarzania ECM",
"",
"",
"",
},
{ NULL }
};
*/
class cSystemLinkNagra : public cSystemLink {
public:
cSystemLinkNagra(void);
virtual bool CanHandle(unsigned short SysId);
virtual cSystem *Create(void) { return new cSystemNagra; }
};
static cSystemLinkNagra staticInitN1;
cSystemLinkNagra::cSystemLinkNagra(void)
:cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
{
opts=new cOpts(SYSTEM_NAME,1);
opts->Add(new cOptInt("MinEcmTime","Nagra: min. ECM processing time",&minEcmTime,0,5000));
Feature.NeedsKeyFile();
// Feature.AddPhrases(Phrases);
}
bool cSystemLinkNagra::CanHandle(unsigned short SysId)
{
//Bev Fix 12/26/06, NooneImportant
//return SysId==SYSTEM_NAGRA || SysId==SYSTEM_NAGRA_BEV;
return SysId==SYSTEM_NAGRA;
}
#endif //TESTER
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -