📄 nagra1.c
字号:
// -- cNagraDES ----------------------------------------------------------------class cNagraDES {private: cDes des;protected: void Decrypt(const unsigned char *data, const unsigned char *key, unsigned char *out, bool desmod=false); void Crypt(const unsigned char *data, const unsigned char *key, unsigned char *out); bool SigCheck(const unsigned char *block, const unsigned char *sig, const unsigned char *vkey, const int rounds);};void cNagraDES::Decrypt(const unsigned char *data, const unsigned char *key, unsigned char *out, bool desmod){ unsigned char cardkey[8]; memcpy(cardkey,key,8); RotateBytes(cardkey,8); memcpy(out,data,8); if(!desmod) RotateBytes(out,8); des.Des(out,cardkey,NAGRA_DES_DECR); if(!desmod) RotateBytes(out,8);}void cNagraDES::Crypt(const unsigned char *data, const unsigned char *key, unsigned char *out){ unsigned char cardkey[8]; memcpy(cardkey,key,8); RotateBytes(cardkey,8); memcpy(out,data,8); RotateBytes(out,8); 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); xxor(hash,8,cr,&block[j*8]); } 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) { PRINTF(L_SYS_CRYPTO,"error decrypting ECM (round 1)"); 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) { PRINTF(L_SYS_CRYPTO,"error: result of ECM decryption is not 64 bytes"); return false; } if(vkey && !SigCheck(out,&out[56],vkey,7)) { PRINTF(L_SYS_CRYPTO,"ECM decryption failed"); 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) { PRINTF(L_SYS_CRYPTO,"error decrypting EMM (round 1)"); 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) { PRINTF(L_SYS_CRYPTO,"error: result of EMM decryption is not 64 bytes"); return false; } if(!vkey || SigCheck(out,&in[1],vkey,8)) return true; // We need to use signature exchange method (7blocks emm,1 block signature) PRINTF(L_SYS_CRYPTO,"warning: signature failed,trying signature exchange method"); 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) { PRINTF(L_SYS_CRYPTO,"error: result of EMM decryption is not 64 bytes"); return false; } if(vkey && !SigCheck(out,buf,vkey,8)) { PRINTF(L_SYS_CRYPTO,"fatal: signature failed in signature exchange method"); 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);}#ifndef TESTER// -- 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) { 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;} 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)) { PRINTF(L_SYS_EMM,"%d: not a valid EMM structure",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) { 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,"%d: setting defaults for ROM %d",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: PRINTF(L_SYS_EMM,"%d: unsupported ROM",CardNum()); return; } if(!emu || !emu->Init(romNr,id)) { delete emu; emu=0; PRINTF(L_SYS_EMM,"%d: initialization failed for ROM %d",CardNum(),romNr); return; } } unsigned char ki[2]; if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) { keyId=(ki[0]<<8)+ki[1]; PRINTF(L_SYS_EMM,"%d: got keys for %04X (ROM %d)",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]); PRINTF(L_SYS_EMM,"%d: got PK keys for %04X (ROM %d)",CardNum(),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,"%d: got keys for %04X (plain)",CardNum(),keyId); break; } } else { PRINTF(L_SYS_EMM,"%d: ignored nano %02x",CardNum(),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(); } }}// -- cSystemLinkNagra ---------------------------------------------------------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",trNOOP("Nagra: min. ECM processing time"),&minEcmTime,0,5000)); Feature.NeedsKeyFile();}bool cSystemLinkNagra::CanHandle(unsigned short SysId){ return SysId==SYSTEM_NAGRA; // || SysId==SYSTEM_NAGRA_BEV;}#endif //TESTER
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -