From: leslie Date: Tue, 22 Nov 2011 20:11:32 +0000 (+0100) Subject: viaccess: add via3 patch X-Git-Tag: upstream/620~18 X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=4fb2298ab646466ec870f0103ed0ce0c15a3b9b9;p=sasc-ng.git viaccess: add via3 patch --- diff --git a/systems/viaccess/viaccess.c b/systems/viaccess/viaccess.c index 85fed32..f44294b 100644 --- a/systems/viaccess/viaccess.c +++ b/systems/viaccess/viaccess.c @@ -26,6 +26,7 @@ #include "misc.h" #include "parse.h" #include "log-core.h" +#include "helper.h" #include "viaccess.h" #include "tps.h" @@ -99,6 +100,25 @@ bool cPlainKeyVia::Parse(const char *line) keynr=MBC3('T','P','S'); ok=(len=GetHex(line,skey,VIATPS_KEYLEN)); } + else if(*line == 'D' || *line == 'P' || *line == 'X' || *line == 'C' || *line == 'E') { + if(isxdigit(line[1])) { + bool e_line=(*line=='E'); + keynr=MBC3(*line,line[1]>='A' ? toupper(line[1])-'A' : line[1]-'0', 0); + line+=2; + ok=((len=GetHex(line,skey,VIA2_KEYLEN,false)) && (len==e_line ? VIA2_KEYLEN : VIA1_KEYLEN)); + } + } + else if(*line == 'T') { + unsigned char tkey[256]; + if(isxdigit(line[1])) { + keynr=MBC3(*line,line[1]>='A' ? toupper(line[1])-'A' : line[1]-'0', 0); + line+=2; + if((len=GetHex(line,tkey,256,false)) && (len==256)) { + SetBinKey(tkey,len); + return true; + } + } + } else if(GetHex(line,&skeynr,1)) { keynr=skeynr; ok=((len=GetHex(line,skey,VIA2_KEYLEN,false)) && (len==VIA1_KEYLEN || len==VIA2_KEYLEN)); @@ -124,7 +144,14 @@ cString cPlainKeyVia::PrintKeyNr(void) case MBC3('M','K',9): snprintf(tmp,sizeof(tmp),"TPSMK%d",C3(keynr)); break; default: - snprintf(tmp,sizeof(tmp),"%02X",keynr); break; + { + char c2=C2(keynr); + if(c2=='D' || c2=='P' || c2=='X' || c2=='C' || c2=='E' || c2=='T') + snprintf(tmp,sizeof(tmp),"%c%01X",c2,keynr & 0x0f); + else + snprintf(tmp,sizeof(tmp),"%02X",keynr); + break; + } } return kn; } @@ -156,6 +183,44 @@ public: static cViaccessCardInfos Vcards; +// -- cViacessExtendedKeys ----------------------------------------------------- + +class cViacessExtendedKeys { +public: + static bool GetKey(int provId, char keyId, int keyNr, unsigned char *key, int len, int log=1, cPlainKey **ppk=0); + bool GetVia26BasicKeys(int provId, int log=1); + unsigned char key[VIA2_KEYLEN]; + unsigned char dkey[VIA1_KEYLEN]; + unsigned char pkey[VIA1_KEYLEN]; + unsigned char xkey[VIA1_KEYLEN]; + unsigned char ckey[VIA1_KEYLEN]; + unsigned char tkey[256]; + unsigned char ekey[VIA2_KEYLEN]; + }; + +bool cViacessExtendedKeys::GetKey(int provId, char keyId, int keyNr, unsigned char *key, int len, int log, cPlainKey **ppk) +{ + cPlainKey *pk = keys.FindKey('V', provId, MBC3(keyId, keyNr, 0),-1,0); + if(pk && pk->Size()==len) { + pk->Get(key); + if(log>1) PRINTF(L_SYS_KEY,"found key \"%s\"",*pk->ToString(true)); + if(ppk) *ppk = pk; + return true; + } + if(log) PRINTF(L_SYS_KEY,"missing key \"V %06X %c1 ...\"",provId, keyId); + return false; +} + +bool cViacessExtendedKeys::GetVia26BasicKeys(int provId, int log) +{ + bool result=true; + if(!GetKey(provId, 'P', 1, pkey, sizeof(pkey), log)) result=false; + if(!GetKey(provId, 'X', 1, xkey, sizeof(xkey), log)) result=false; + if(!GetKey(provId, 'C', 1, ckey, sizeof(ckey), log)) result=false; + if(!GetKey(provId, 'T', 1, tkey, sizeof(tkey), log)) result=false; + return result; +} + // -- cViaccess ---------------------------------------------------------------- class cViaccess : protected cDes { @@ -165,6 +230,10 @@ private: // int HashNanos(const unsigned char *data, int len); void Via2Mod(const unsigned char *key2, unsigned char *data); + // + void Via3Core(int provID, const cViacessExtendedKeys *keys, unsigned char *data, int Off); + void Via3Fct1(int provID, const cViacessExtendedKeys *keys, unsigned char *data); + void Via3Fct2(int provID, const cViacessExtendedKeys *keys, unsigned char *data); protected: unsigned char hbuff[8], hkey[8]; int pH; @@ -177,6 +246,8 @@ protected: // void Decode(unsigned char *data, const unsigned char *key); bool Decrypt(const unsigned char *work_key, const unsigned char *data, int len, unsigned char *des_data1, unsigned char *des_data2); + bool Decrypt26(const cViacessExtendedKeys *work_keys, const unsigned char *ecw, unsigned char *des_data1, unsigned char *des_data2); + bool Decrypt3(int provID, const cViacessExtendedKeys *work_keys, const unsigned char *ecw, int modeAES, unsigned char *des_data1, unsigned char *des_data2); // virtual unsigned int Mod(unsigned int R, unsigned int key7) const; public: @@ -346,6 +417,206 @@ bool cViaccess::Decrypt(const unsigned char *work_key, const unsigned char *data return (memcmp(signatur,hbuff,8)==0); } +void cViaccess::Via3Core(int provID, const cViacessExtendedKeys *keys, unsigned char *data, int Off) +{ + int i; + unsigned long R2, R3, R4, R6, R7; + + for(i=0; i<4; i++) data[i]^= keys->xkey[(Off+i) & 0x07]; + switch(provID) { + case 0x032820: + R2 = (data[0]^0xBD)+data[0]; + R3 = (data[3]^0xEB)+data[3]; + R2 = (R2-R3)^data[2]; + R3 = ((0x39*data[1])<<2); + data[4] = (R2|R3)+data[2]; + + R3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0]; + R2 = (data[1]^0xED)+data[1]; + R7 = ((data[3]+0x29)^data[3])*R2; + data[5] = R7+R3; + + R2 = ((data[2]^0x33)+data[2]) & 0x0A; + R3 = (data[0]+0xAD)^data[0]; + R3 = R3+R2; + R2 = data[3]*data[3]; + R7 = (R2 | 1) + data[1]; + data[6] = (R3|R7)+data[1]; + + R3 = data[1] & 0x07; + R2 = (R3-data[2]) & (data[0] | R2 |0x01); + data[7] = R2+data[3]; + break; + case 0x030B00: + R6 = (data[3] + 0x6E) ^ data[3]; + R6 = (R6*(data[2] << 1)) + 0x17; + R3 = (data[1] + 0x77) ^ data[1]; + R4 = (data[0] + 0xD7) ^ data[0]; + data[4] = ((R4 & R3) | R6) + data[0]; + + R4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; + R6 = (data[1] + 0x1B) ^ data[1]; + R4 = (R4*R6) ^ data[0]; + data[5] = (R4 ^ (data[2] << 1)) + data[1]; + + R3 = (data[3] * data[3])| 0x01; + R4 = (((data[2] ^ 0x35) + data[2]) | R3) + data[2]; + R6 = data[1] ^ (data[0] + 0x4A); + data[6] = R6 + R4; + + R3 = (data[0] * (data[2] << 1)) | data[1]; + R4 = 0xFE - data[3]; + R3 = R4 ^ R3; + data[7] = R3 + data[3]; + break; + default: + break; + } + for(i=4;i<8;i++) data[i] = keys->tkey[data[i]]; +} + +void cViaccess::Via3Fct1(int provID, const cViacessExtendedKeys *keys, unsigned char *data) +{ + Via3Core(provID, keys, data, 0); + switch(provID) { + case 0x032820: + // swap data[4] and data[7] + data[4] ^= data[7]; + data[7] ^= data[4]; + data[4] ^= data[7]; + break; + case 0x030B00: + // swap data[5] and data[7] + data[5] ^= data[7]; + data[7] ^= data[5]; + data[5] ^= data[7]; + break; + default: + break; + } +} + +void cViaccess::Via3Fct2(int provID, const cViacessExtendedKeys *keys, unsigned char *data) +{ + unsigned char t; + Via3Core(provID, keys, data, 4); + switch(provID) { + case 0x032820: + t = data[4]; + data[4] = data[7]; + data[7] = data[5]; + data[5] = data[6]; + data[6] = t; + break; + case 0x030B00: + t = data[6]; + data[6] = data[7]; + data[7] = t; + break; + default: + break; + } +} + +#define DES_ECS2_DECRYPT (DES_IP | DES_FP | DES_RIGHT) +#define DES_ECS2_CRYPT (DES_IP | DES_FP) + +bool cViaccess::Decrypt3(int provID, const cViacessExtendedKeys *work_keys, const unsigned char *ecw, int modeAES, unsigned char *des_data1, unsigned char *des_data2) { + unsigned char dcw[16]; + char hex1[34], hex2[34]; + cLogLineBuff LineBuff(L_SYS_KEY); + int i, pass; + memcpy(dcw,ecw,16); + + LineBuff.Printf("ecw %s %s", HexStr(hex1, dcw, 8), HexStr(hex2, dcw+8, 8)); + LineBuff.Flush(); + + if(modeAES==1) { + cAES Aes; + Aes.SetKey(work_keys->ekey); + Aes.Decrypt(dcw, 16); + } + memcpy(des_data1,dcw,8); // needed for final xor + + for(pass = 0; pass < 2; pass++) { + unsigned char *tmp_dcw=dcw + pass * 8, tmp[8]; + for (i=0; i<4; i++) tmp[i] = tmp_dcw[i+4]; + Via3Fct1(provID, work_keys, tmp); + for (i=0; i<4; i++) tmp[i] = tmp_dcw[i]^tmp[i+4]; + Via3Fct2(provID, work_keys, tmp); + for (i=0; i<4; i++) tmp[i]^= work_keys->xkey[i+4]; + for (i=0; i<4; i++) { + tmp_dcw[i] = tmp_dcw[i+4]^tmp[i+4]; + tmp_dcw[i+4] = tmp[i]; + } + Des(tmp_dcw, work_keys->key, DES_PC1 | DES_ECS2_DECRYPT); + Des(tmp_dcw, work_keys->key + 8, DES_PC1 | DES_ECS2_CRYPT); + Des(tmp_dcw, work_keys->key, DES_PC1 | DES_ECS2_DECRYPT); + for (i=0; i<4; i++) tmp[i] = tmp_dcw[i+4]; + Via3Fct2(provID, work_keys, tmp); + for (i=0; i<4; i++) tmp[i] = tmp_dcw[i]^tmp[i+4]; + Via3Fct1(provID, work_keys, tmp); + for (i=0; i<4; i++) tmp[i]^= work_keys->xkey[i]; + for (i=0; i<4; i++) { + tmp_dcw[i] = tmp_dcw[i+4]^tmp[i+4]; + tmp_dcw[i+4] = tmp[i]; + } + } + xxor(dcw, 8, dcw, work_keys->ckey); + xxor(dcw + 8, 8, dcw + 8, des_data1); + + if(modeAES==2) { + cAES Aes; + Aes.SetKey(work_keys->ekey); + Aes.Decrypt(dcw, 16); + } + + LineBuff.Printf("cw %s %s", HexStr(hex1, dcw, 8), HexStr(hex2, dcw+8, 8)); + LineBuff.Flush(); + + for(i=0;i<16;i+=4) if(dcw[i+3] != ((dcw[i]+dcw[i+1]+dcw[i+2]) & 0xFF)) return false; + memcpy(des_data1, dcw, 8); + memcpy(des_data2, dcw+8, 8); + return true; +} + +bool cViaccess::Decrypt26(const cViacessExtendedKeys *work_keys, const unsigned char *ecw, unsigned char *des_data1, unsigned char *des_data2) +{ + unsigned char dcw[16]; + char hex1[34], hex2[34]; + cLogLineBuff LineBuff(L_SYS_KEY); + int i, pass; + memcpy(dcw,ecw,16); + + LineBuff.Printf("ecw %s %s", HexStr(hex1, dcw, 8), HexStr(hex2, dcw+8, 8)); + LineBuff.Flush(); + + for(pass = 0; pass < 2; pass++) { + unsigned char *tmp_dcw=dcw + pass * 8, tmp[8]; + for(i = 0; i < 8; i++) tmp[i] = work_keys->tkey[tmp_dcw[i]]; + for(i = 0; i < 8; i++) tmp_dcw[i] = tmp[work_keys->pkey[i]]; + Des(tmp_dcw, work_keys->dkey, DES_PC1 | DES_ECS2_CRYPT); + xxor(tmp_dcw, 8, tmp_dcw, work_keys->xkey); + Des(tmp_dcw, work_keys->key, DES_PC1 | DES_ECS2_DECRYPT); + Des(tmp_dcw, work_keys->key + 8, DES_PC1 | DES_ECS2_CRYPT); + Des(tmp_dcw, work_keys->key, DES_PC1 | DES_ECS2_DECRYPT); + xxor(tmp_dcw, 8, tmp_dcw, work_keys->xkey); + Des(tmp_dcw, work_keys->dkey, DES_PC1 | DES_ECS2_DECRYPT); + for(i = 0; i < 8; i++) tmp[work_keys->pkey[i]] = tmp_dcw[i]; + for(i = 0; i < 8; i++) tmp_dcw[i] = work_keys->tkey[tmp[i]]; + } + xxor(dcw, 8, dcw, work_keys->ckey); + xxor(dcw + 8, 8, dcw + 8, ecw); + + LineBuff.Printf("cw %s %s", HexStr(hex1, dcw, 8), HexStr(hex2, dcw+8, 8)); + LineBuff.Flush(); + + for(i=0;i<16;i+=4) if(dcw[i+3] != ((dcw[i]+dcw[i+1]+dcw[i+2]) & 0xFF)) return false; + memcpy(des_data1, dcw, 8); + memcpy(des_data2, dcw+8, 8); + return true; +} + // -- cSystemViaccess ---------------------------------------------------------- #define MAX_NEW_KEYS 5 @@ -389,22 +660,119 @@ bool cSystemViaccess::ProcessECM(const cEcmInfo *ecm, unsigned char *data) if(num<0) return false; nanos+=num; len-=num; } - - if(cParseViaccess::CheckNano90FromNano(nanos)) { - int keynr=cParseViaccess::KeyNrFromNano(nanos); - cKeySnoop ks(this,'V',ecm->provId,keynr); - cPlainKey *pk=0; - while((pk=keys.FindKey('V',ecm->provId,keynr,-1,pk))) { - unsigned char key[16]; - if(pk->Size()<=(int)sizeof(key)) { - pk->Get(key); - SetV2Mode(pk->Size()==VIA2_KEYLEN ? &key[VIA1_KEYLEN] : 0); - if(cViaccess::Decrypt(key,&nanos[5],len-5,&cw[0],&cw[8])) { - if(mayHaveTps) tps.PostProc(cw); - ks.OK(pk); - return true; + cViacessExtendedKeys work_keys; + int nanoCmd, nanoLen=0, version=0, pos=0, desKeyIdx=-1, keySelectPos=0, providerKeyLen=0, aesMode=0, encStart=0; + cPlainKey *pk=0; + unsigned char signatur[8]; + for(;pos>4)&0x0F); + desKeyIdx = nanos[pos+3]; + keySelectPos = pos+4; + } + pk=0; + if(keys.FindKey('V',ecm->provId,desKeyIdx,-1,pk)) { + if(version >= 2 && !work_keys.GetVia26BasicKeys(ecm->provId, 1)) + desKeyIdx = -1; + if(version == 2 && !work_keys.GetKey(ecm->provId, 'D', 1, work_keys.dkey, sizeof(work_keys.dkey), 1)) + desKeyIdx = -1; + } + else + desKeyIdx = -1; +// if (showLog) SendMSG(0,"nano40->nanoLen:%d, version:%d, provider:0x%x, keyIdx:0x%x", nanoLen, version, currentIdent, desKeyIdx); + providerKeyLen = nanoLen; + break; + case 0x90: + if (nanoLen < 0x03) + break; + version = nanos[pos]; +// currentIdent= ((nanos[pos]<<16)|(nanos[pos+1]<<8))|(nanos[pos+2]&0xF0); + desKeyIdx = nanos[pos+2]&0x0F; + keySelectPos = pos+4; + if((version == 3) && (nanoLen > 3)) + desKeyIdx = nanos[pos+(nanoLen-4)]&0x0F; + pk=0; + if(keys.FindKey('V',ecm->provId,desKeyIdx,-1,pk)) { + if(version >= 2 && !work_keys.GetVia26BasicKeys(ecm->provId, 1)) + desKeyIdx = -1; + if(version == 2 && !work_keys.GetKey(ecm->provId, 'D', 1, work_keys.dkey, sizeof(work_keys.dkey), 1)) + desKeyIdx = -1; + } + else + desKeyIdx = -1; +// if (showLog) SendMSG(0,"nano90->nanoLen:%d, version:%d, provider:0x%x, keyIdx:0x%x",nanoLen, version,currentIdent,desKeyIdx); + providerKeyLen = nanoLen; + break; + case 0x80: // sub ecm + nanoLen = 0; + break; + case 0xD2: + if(nanoLen < 0x02) break; + if(!work_keys.GetKey(ecm->provId, 'E', nanos[pos+1]==1 ? 1 : 2, work_keys.ekey, sizeof(work_keys.ekey), 1)) + break; + if(nanos[pos]==0x0B) aesMode = 1; + if(nanos[pos]==0x0D) aesMode = 2; + break; + case 0xDD: + nanoLen = 0; + break; + case 0xEA: + if(nanoLen < 0x10) break; +// memcpy(des_data1,&nanos[pos],8); +// memcpy(des_data2,&nanos[pos+8],8); + if (version == 3) { + if (ecm->provId == 0x030B00 && providerKeyLen>3) { + //surencrypted DCWs with set 1 of keys (i.e. publicly known AES keys) + bool isGoodTntPacket = (nanos[keySelectPos]==0x05 && nanos[keySelectPos+1]==0x67 && nanos[keySelectPos+2]==0x00); + if(!isGoodTntPacket) break; //try next TNT packet + } + } + encStart = pos; + break; + case 0xf0: // signature + memcpy(signatur,&nanos[pos],8); + if(desKeyIdx!=-1 && encStart) { // has nano90, encryptet Key (nanoAE) and Signature (nano0F) + cKeySnoop ks(this,'V',ecm->provId,desKeyIdx); + cPlainKey *pk=0; + while((pk=keys.FindKey('V',ecm->provId,desKeyIdx,-1,pk))) { + if(pk->Size()<=(int)sizeof(work_keys.key)) { + pk->Get(work_keys.key); + if(version==1) { + SetV2Mode(pk->Size()==VIA2_KEYLEN ? &work_keys.key[VIA1_KEYLEN] : 0); + if(cViaccess::Decrypt(work_keys.key,&nanos[5],len-5,&cw[0],&cw[8])) { + if(mayHaveTps) tps.PostProc(cw); + ks.OK(pk); + return true; + } + } + else if(version==2) { + if(cViaccess::Decrypt26(&work_keys,&nanos[encStart],&cw[0],&cw[8])) { + ks.OK(pk); + return true; + } + } + else if(version==3) { + if(cViaccess::Decrypt3(ecm->provId, &work_keys,&nanos[encStart], aesMode,&cw[0],&cw[8])) { + ks.OK(pk); + return true; + } + } + } + } + } + version=0; desKeyIdx=-1; encStart=0; + break; } } return false;