📄 nagra2.cpp
字号:
SHA1_Init(&sctx);
break;
case 0x44: // add 64 bytes to SHA1 buffer
RotateBytes(data,64);
SHA1_Update(&sctx,data,64);
BYTE4_LE(data ,sctx.h4);
BYTE4_LE(data+4 ,sctx.h3);
BYTE4_LE(data+8 ,sctx.h2);
BYTE4_LE(data+12,sctx.h1);
BYTE4_LE(data+16,sctx.h0);
break;
case 0x45: // add wordsize bytes to SHA1 buffer and finalize SHA result
if(wordsize) {
if(wordsize>1) RotateBytes(data,wordsize);
SHA1_Update(&sctx,data,wordsize);
}
memset(data,0,64);
SHA1_Final(data+64,&sctx);
break;
default:
return false;
}
return true;
}
#include "nagra2-prov.cpp"
//#include "nagra2-0101.cpp"
#ifndef TESTER
// -- cNagra2 ------------------------------------------------------------------
class cNagra2 : public cNagra {
private:
bool Signature(const unsigned char *vkey, const unsigned char *sig, const unsigned char *msg, int len);
protected:
cIDEA idea;
//
virtual void CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q);
bool DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m);
bool DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m);
};
void cNagra2::CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q)
{
// Calculate P and Q from PK
IdeaKS ks;
idea.SetEncKey(key,&ks);
// expand IDEA-G key
unsigned char idata[96];
for(int i=11; i>=0; i--) {
const int off=i*8;
memcpy(&idata[off],&key[13],8);
idata[off]^=i;
idea.Decrypt(&idata[off],8,&ks,0);
for(int j=7; j>=0; j--) idata[off+j] ^= key[13+j];
idata[off]^=i;
}
// 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);
for(int j=7; j>=0; j--) buff[j+8]^=msg[i+j];
}
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) {
d(printf("nagra2: first RSA failed (ECM)\n"))
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) {
//d(printf("nagra2: second RSA failed (ECM)\n"))
return false;
}
if(vkey && !Signature(vkey,out,out+8,len-8)) {
//d(printf("nagra2: signature failed (ECM)\n"))
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) {
dl(printf("nagra2: first RSA failed (EMM)\n"))
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) {
dl(printf("nagra2: second RSA failed (EMM)\n"))
return false;
}
if(vkey && !Signature(vkey,out,out+8,len-8)) {
dl(printf("nagra2: signature failed (EMM)\n"))
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;
int provider=id;
if (id >= 0x0101 && id <= 0x010F) {
provider = 0x0101;
} else if (id >= 0x0901 && id <= 0x090F) {
provider = 0x0901;
} else {
provider = id;
}
if(cmdLen<64 || SCT_LEN(data)<cmdLen+10) {
if(doLog) d(printf("system-nagra2: bad ECM message msgLen=%d sctLen=%d\n",cmdLen,SCT_LEN(data)))
return false;
}
int keyNr=(data[7]&0x10)>>4;
// cKeySnoop ks(this,'N',id,keyNr);
cKeySnoop ks(this,'N',provider,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(!(pk=keys.FindKey('N',provider,MBC('M','1'),-1,0))) {
if(doLog) d(printf("system-nagra2: missing %04x M1 key\n",id))
return false;
}
pk->Get(m1);
// if((pk=keys.FindKey('N',id,'V',sizeof(vKey)))) {
if((pk=keys.FindKey('N',provider,'V',sizeof(vKey),0))) {
pk->Get(vKey);
hasVerifyKey=true;
}
// else if(doLog && id!=lastEcmId) d(printf("system-nagra2: missing %04x V key (non-fatal)\n",id))
else if(doLog && provider!=lastEcmId) d(printf("system-nagra2: missing %04x V key (non-fatal)\n",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) d(printf("system-nagra2: decrypt of ECM failed (%04x)\n",id))
return false;
}
if((!ecmP && id!=lastEcmId) || (ecmP && !ecmP->CanHandle(provider))) {
delete ecmP;
ecmP=cN2Providers::GetProv(provider,N2FLAG_NONE);
if(ecmP) d(printf("\nsystem-nagra2: provider %04x capabilities%s%s%s\n",id,ecmP->HasFlags(N2FLAG_MECM)?" MECM":"",ecmP->HasFlags(N2FLAG_B1) ?" B1":"",ecmP->HasFlags(N2FLAG_INV) ?" INVCW":""))
}
lastEcmId=id;
lastEcmId=provider;
#ifdef DEBUG
bool contFail=false;
#endif
int l=0, mecmAlgo=0;
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;
// if(provider==0x0501) s^=1; //PW
// if(provider==0x1101) s^=1; //KD 23,5 Kabel
// if(provider==0x1102) s^=1; //KD ISH
mecmAlgo=buff[i+2]&0x60;
memcpy(cw+(s<<3),&buff[i+3],8);
i+=11; l|=(s+1);
}
else {
d(printf("system-nagra2: bad length %d in CW nano %02x\n",buff[i+1],buff[i]))
i++;
}
break;
case 0x00:
i+=2; break;
case 0x13: case 0x14: case 0x15: case 0x16:
i+=4; break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:
case 0xB0:
i+=buff[i+1]+2;
break;
default:
#ifdef DEBUG
if(!contFail) printf("system-nagra2: unknown ECM nano");
printf(" %02x",buff[i]);
contFail=true;
#endif
i++;
continue;
}
#ifdef DEBUG
if(contFail) { printf("\n"); contFail=false; }
#endif
}
#ifdef DEBUG
if(contFail) printf("\n");
#endif
if(l!=3) return false;
if(mecmAlgo>0) {
if(ecmP && ecmP->HasFlags(N2FLAG_MECM)) {
if(!ecmP->MECM(buff[15],mecmAlgo,cw)) return false;
}
else { d(printf("system-nagra2: MECM for provider %04x not supported\n",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];
char txt[150];
if(cmdLen<96 || SCT_LEN(buffer)<cmdLen+15) {
sprintf(txt,"Bad EMM-G Packet (bad EMM message msgLen=%d sctLen=%d)\n",cmdLen,SCT_LEN(buffer));
m_DLLInstance.PushMessage(MSG_EMM_DATA,txt);
dl(printf("logger-nagra2: bad EMM message msgLen=%d sctLen=%d\n",cmdLen,SCT_LEN(buffer)))
return;
}
int checkid = 0;
int keyset=(buffer[12]&0x03);
int sel=(buffer[12]&0x10)<<2;
int sigsel=(buffer[13]&0x80)>>1;
char time_str[20];
_strtime(time_str);
char text[100];
char filename[_MAX_PATH];
char EMM_filename[_MAX_PATH];
int CamID = 0;
int LogType = 0;
int provider=id;
if (id >= 0x0101 && id <= 0x010F) {
provider = 0x0101;
} else if (id >= 0x0901 && id <= 0x090F) {
provider = 0x0901;
} else {
provider = id;
}
int keyPTR = N2_MAGIC;
if (buffer[0] == 0x83) {
keyPTR = 0;
for (int it=5; it>2; it--) {
CamID = MBC(CamID,buffer[it]);
}
keyPTR=CID(N2_EMM_S,buffer[5],buffer[4],buffer[3]);
LogType = m_DLLInstance.m_log_emm_by;
switch(LogType) {
case 0: //0=no logging
sprintf(EMM_filename,"");
break;
case 1: //1=single file
sprintf(EMM_filename,"EMM-S.log");
break;
case 2: //2= two files (group / cam spec.)
if (buffer[6] == 0x00) {
sprintf(EMM_filename,"EMM-S_By_Group.log");
} else {
sprintf(EMM_filename,"EMM-S_By_Target.log");
}
break;
case 3: //3=by camid
default:
sprintf(EMM_filename,"CamID_%02X%02X%02X%02X.log",buffer[5],buffer[4],buffer[3],buffer[6]);
break;
}
}
cPlainKey *pk;
cBN n;
unsigned char ideaKey[24], vKey[16];
bool hasVerifyKey=false;
if(!(pk=keys.FindKey('N',provider,MBC(keyPTR,keyset+0x10+sel),96,0))) {
if (buffer[0] == 0x83) {
sprintf(text,"[%s] EMM-S {%06X%02X} Missing: %04x S %.06X %.02X RSA key",time_str,CamID,buffer[6],id,CamID,keyset+0x10+sel);
m_DLLInstance.PushMessage(MSG_MESSAGE,text);
sprintf(txt,"Your missing: %04x S %.06X %.02X RSA key (96 bytes)",id,CamID,keyset+0x10+sel);
} else {
sprintf(txt,"Your missing: %04x NN %.02X RSA key (96 bytes)",id,keyset+0x10+sel);
}
m_DLLInstance.PushMessage(MSG_EMM_DATA,txt);
dl(printf("logger-nagra2: missing %04x NN %.02X RSA key (96 bytes)\n",id,keyset+0x10+sel))
return;
}
pk->Get(n);
if (buffer[0] != 0x83) {
if((pk=keys.FindKey('N',provider,MBC(keyPTR,0x03+sigsel),sizeof(vKey)))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -