]> www.vanbest.org Git - sasc-ng.git/commitdiff
viaccess: add via3 patch
authorleslie <unknown>
Tue, 22 Nov 2011 20:11:32 +0000 (21:11 +0100)
committerleslie <unknown>
Tue, 22 Nov 2011 20:11:32 +0000 (21:11 +0100)
systems/viaccess/viaccess.c

index 85fed321556e68a6871ece55f06daaff333d86d9..f44294b1f71ff60b731ad020ca43b13b20f2474b 100644 (file)
@@ -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<len; pos+=nanoLen) {
+    nanoCmd = nanos[pos++];
+    nanoLen = nanos[pos++];
+    switch(nanoCmd) {
+      case 0x40:
+        if(nanoLen < 0x03) break;
+        version = nanos[pos];
+        if(nanoLen == 3) { //CSat
+//        currentIdent=((nanos[pos+i]<<16)|(nanos[pos+1]<<8))|(nanos[pos+2]&0xF0);
+          desKeyIdx = nanos[pos+2]&0x0F;
+          keySelectPos = pos+3;
           }
-        }
+        else { //TNT
+//        currentIdent=(nanos[pos+0]<<16)|(nanos[pos+1]<<8)|((nanos[pos+2]>>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;