📄 viaccess.cpp
字号:
unsigned char prepared_key[8];
if(work_key[7]==0) {
// 8th key-byte = 0 then like Eurocrypt-M but with viaccess mods
HashNanos(data,encStart+16);
memcpy(prepared_key,work_key,sizeof(prepared_key));
}
else { // key8 not zero
// rotate the key 2x left
prepared_key[0]=work_key[2];
prepared_key[1]=work_key[3];
prepared_key[2]=work_key[4];
prepared_key[3]=work_key[5];
prepared_key[4]=work_key[6];
prepared_key[5]=work_key[0];
prepared_key[6]=work_key[1];
prepared_key[7]=work_key[7];
// test if key8 odd
if(work_key[7]&1) {
HashNanos(data,encStart);
// test if low nibble zero
unsigned char k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5;
for(int i=0; i<8; i++) {
unsigned char tmp=des_data1[i];
des_data1[i]=(k & hbuff[pH]) ^ tmp;
HashByte(tmp);
}
for(int i=0; i<8; i++) {
unsigned char tmp=des_data2[i];
des_data2[i]=(k & hbuff[pH]) ^ tmp;
HashByte(tmp);
}
}
else {
HashNanos(data,encStart+16);
}
}
Decode(des_data1,prepared_key);
Decode(des_data2,prepared_key);
Hash();
return (memcmp(signatur,hbuff,8)==0);
}
// -- cTPS ---------------------------------------------------------------------
class cTPS : private cAES {
private:
bool keySet;
static const unsigned char T1[], T2[];
protected:
void SetV2Key(const unsigned char *key);
int Decrypt(unsigned char *data, int len);
public:
cTPS(void);
};
const unsigned char cTPS::T1[] = {
0x4F,0xB4,0xFC,0x9B,0x4A,0x7F,0x44,0xFB,0x05,0xFF,0xBD,0xBB,0x16,0x2D,0x6C,0xC8,
0xD8,0x96,0xF9,0xFE,0x3F,0xFF,0x36,0x24,0xB6,0xBF,0x49,0xC9,0x2D,0x36,0x5E,0xD0,
0x1F,0x09,0x7E,0xA9,0x7F,0xFF,0x64,0xB6,0x5B,0x7E,0xF8,0xFC,0x6E,0x3F,0x7F,0xBF,
0xDD,0x36,0x12,0xE9,0x05,0xFE,0xB4,0x6C,0x6F,0xFE,0x7E,0xC8,0x25,0x90,0x6D,0x90
};
const unsigned char cTPS::T2[] = {
0x7E,0x6D,0x7E,0x12,0x76,0xFD,0x2F,0xFE,0x6D,0xFE,0xDA,0x3F,0xDA,0x6D,0xBD,0x97,
0xD0,0x6D,0xD8,0x9F,0x69,0xFD,0xB6,0x37,0xFE,0x7F,0x36,0x92,0xBD,0x52,0x16,0xDF,
0xFC,0x96,0xFF,0x92,0xFD,0x6D,0x7F,0xB5,0xFB,0x4C,0xB6,0xB7,0x7E,0xD9,0xFE,0x9B,
0xFD,0xF4,0x6D,0x9B,0xB9,0x36,0xBF,0x7F,0xD2,0x2D,0xDF,0xB7,0xD9,0xFE,0x69,0xBF
};
cTPS::cTPS(void)
{
keySet=false;
}
void cTPS::SetV2Key(const unsigned char *key)
{
cAES::SetKey(key); keySet=true;
}
int cTPS::Decrypt(unsigned char *data, int len)
{
if(data[0]!=0xD2 || data[1]!=0x01 || data[2]!=0x01) return 0;
data+=3; len-=3;
if(data[0]==0x40) { // TPS crypt v2 (AES)
if(!keySet) return -1;
data[0]=0x90;
for(int i=0; i<len; i+=data[i+1]+2)
if(data[i]==0xEA) {
cAES::Decrypt(&data[i+2],16);
break;
}
return 2;
}
else { // TPS crypt v1 (XOR)
const unsigned char * const table=(data[0]==0xDF) ? T1 : T2;
for(int i=len-1 ; i>=0 ; i--) data[i]^=table[i&63];
return 1;
}
}
// -- cSystemViaccess ----------------------------------------------------------
struct ViaccessSOIDData {
unsigned char ident[3];
unsigned char keyno;
};
#define MAX_NEW_KEYS 5
class cSystemViaccess : public cSystem, private cViaccess, private cTPS {
private:
struct ViaccessSOIDData sd;
unsigned char emmBuff[256];
int emmLen;
bool haveSOID;
//
bool DownloadAES(unsigned char *key);
bool ParseAES(const regex_t *re, regmatch_t *pm, const char *buf, unsigned char *key);
public:
cSystemViaccess(void);
virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data);
virtual void ProcessEMM(int pid, int caid, unsigned char *buffer);
};
cSystemViaccess::cSystemViaccess(void)
:cSystem(SYSTEM_NAME,SYSTEM_PRI)
{
haveSOID=false; emmLen=0;
hasLogger=true;
}
bool cSystemViaccess::ParseAES(const regex_t *re, regmatch_t *pm, const char *buf, unsigned char *key)
{
int i, j;
unsigned char val;
if (regexec(re, buf, 1, pm, 0))
return false;
for (i = 0, j = 0; i < 23; ++i)
if (i % 3 == 0)
val = (buf[pm->rm_so + i] < 'A' ? buf[pm->rm_so + i] - '0' : buf[pm->rm_so + i] - 'A' + 10) * 16;
else if (i % 3 == 1)
key[j++] = val + (buf[pm->rm_so + i] < 'A' ? buf[pm->rm_so + i] - '0' : buf[pm->rm_so + i] - 'A' + 10);
return (j == 8);
}
bool cSystemViaccess::DownloadAES(unsigned char *key)
{
char buf[4096], *ptr;
regex_t re;
regmatch_t pm;
cNetSocket so(DEFAULT_CONNECT_TIMEOUT, DEFAULT_READWRITE_TIMEOUT, DEFAULT_IDLE_TIMEOUT, false);
if (!so.Connect(AESKeyHost, AESKeyPort))
return false;
memset(buf, 0x00, sizeof(buf));
sprintf(buf, "GET /%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla\r\nReferer: http://%s/%s\r\n\r\n", AESKeyPath, AESKeyHost, AESKeyHost, AESKeyPath);
so.Write((unsigned char *) buf, strlen(buf));
memset(buf, 0x00, sizeof(buf));
so.Read((unsigned char *) buf, sizeof(buf) - 1);
if (regcomp(&re, "[0-9A-F]{2}( [0-9A-F]{2}){7}", REG_EXTENDED))
return false;
if (!ParseAES(&re, &pm, buf, key))
return false;
if (!ParseAES(&re, &pm, buf + pm.rm_eo, key + 8))
return false;
return true;
}
bool cSystemViaccess::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
{
int len=SCT_LEN(data);
unsigned char tmp[0x100];
cPlainKey *tpsPk=0;
cKeySnoop *ks=0;
while(1) {
memcpy(tmp,data,len);
unsigned char *nanos=(unsigned char *)cParseViaccess::NanoStart(tmp);
int nlen=len-(nanos-tmp);
int tps=cTPS::Decrypt(nanos,nlen);
if(tps>0) { nanos+=3; nlen-=3; }
unsigned char key[16];
if(tps>=0 && cParseViaccess::CheckNano90FromNano(nanos)) {
int keynr=cParseViaccess::KeyNrFromNano(nanos);
if(!ks) ks=new cKeySnoop(this,'V',ecm->provId,keynr);
cPlainKey *pk=0;
while((pk=keys.FindKey('V',ecm->provId,keynr,-1,pk))) {
pk->Get(key);
SetV2Mode(pk->Size()==VIA2_KEYLEN ? &key[VIA1_KEYLEN] : 0);
if(cViaccess::Decrypt(key,&nanos[5],nlen-5,&cw[0],&cw[8])) {
ks->OK(pk); delete ks;
return true;
}
}
}
if(tps==1 || tps==0) {
delete ks;
return false;
}
tpsPk=keys.FindKey('V',ecm->provId,MBC3('T','P','S'),sizeof(key),tpsPk);
if(!tpsPk) {
unsigned char newKey[16];
/* if (DownloadAES(newKey)) {
cSoftCAM::FoundKey();
if (keys.NewKey('V',ecm->provId,MBC3('T','P','S'),newKey,16)) {
cSoftCAM::NewKey();
cSoftCAM::Save();
tpsPk=keys.FindKey('V',ecm->provId,MBC3('T','P','S'),16,tpsPk);
}
}*/
if(!tpsPk) {
d(printf("system-viaccess: missing/invalid %.4x TPS or OP key\n",ecm->provId))
delete ks;
return false;
}
}
tpsPk->Get(key);
cTPS::SetV2Key(key);
}
}
void cSystemViaccess::ProcessEMM(int pid, int caid, unsigned char *buffer)
{
unsigned char ua[5], sa[3], signature[8], addressdata[34];
unsigned char *scan=0;
unsigned int updtype=0, scanlen=0;
bool haveData=false;
const unsigned int msgLen=buffer[2];
switch(buffer[0]) {
case 0x8C: // shared update message
case 0x8D:
if(msgLen<=sizeof(emmBuff)) {
scan=&buffer[3]; // Skip SA
}
case 0x8E: // shared update data/message
{
static const unsigned char addr_nano[] = { 0x9E,0x20 };
memcpy(sa,&buffer[3],sizeof(sa));
}
case 0x88:
{
if(msgLen>=0xB4) {
return;
}
}
}
}
// -- cSystemLinkViaccess ------------------------------------------------------
class cSystemLinkViaccess : public cSystemLink {
public:
cSystemLinkViaccess(void);
virtual bool CanHandle(unsigned short SysId);
virtual cSystem *Create(void) { return new cSystemViaccess; }
virtual bool Init(const char *cfgdir);
};
static cSystemLinkViaccess staticInit;
cSystemLinkViaccess::cSystemLinkViaccess(void)
:cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
{
opts=new cOpts(SYSTEM_NAME,3);
opts->Add(new cOptStr("AESKeyHost","Viaccess: AES Key website host",AESKeyHost,sizeof(AESKeyHost),"0123456789abcdefghijklmnopqrstuvwxyz.-"));
opts->Add(new cOptInt("AESKeyPort","Viaccess: AES Key website port",&AESKeyPort,1,65535));
opts->Add(new cOptStr("AESKeyPath","Viaccess: AES Key website path",AESKeyPath,sizeof(AESKeyPath),"0123456789abcdefghijklmnopqrstuvwxyz.-_/~"));
Feature.NeedsKeyFile();
}
bool cSystemLinkViaccess::CanHandle(unsigned short SysId)
{
SysId&=SYSTEM_MASK;
return SYSTEM_CAN_HANDLE(SysId);
}
bool cSystemLinkViaccess::Init(const char *cfgdir)
{
Vcards.Load(cfgdir,SYSTEM_NAME,"Viaccess.KID");
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -