SASC-NG
DVBSoftCAM

cryptoworks.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023 #include <byteswap.h>
00024 
00025 #include "system-common.h"
00026 #include "data.h"
00027 #include "helper.h"
00028 #include "crypto.h"
00029 #include "misc.h"
00030 #include "log-sys.h"
00031 #include "version.h"
00032 
00033 SCAPIVERSTAG();
00034 
00035 #define SYSTEM_CRYPTOWORKS   0x0D00
00036 
00037 #define SYSTEM_NAME          "Cryptoworks"
00038 #define SYSTEM_PRI           -10
00039 #define SYSTEM_CAN_HANDLE(x) ((x)==SYSTEM_CRYPTOWORKS)
00040 
00041 #define L_SYS        4
00042 #define L_SYS_ALL    LALL(L_SYS_LASTDEF)
00043 
00044 static const struct LogModule lm_sys = {
00045   (LMOD_ENABLE|L_SYS_ALL)&LOPT_MASK,
00046   (LMOD_ENABLE|L_SYS_DEFDEF)&LOPT_MASK,
00047   "cryptoworks",
00048   { L_SYS_DEFNAMES }
00049   };
00050 ADD_MODULE(L_SYS,lm_sys)
00051 
00052 #define DUMPNANO(t,p,n) \
00053   LBSTART(L_SYS_VERBOSE); \
00054   LBPUT("%s",(t)); \
00055   unsigned char *__p=(unsigned char *)(p); \
00056   int __n=(n); \
00057   for(int i=0; i<__n;) { \
00058     LBFLUSH(); \
00059     LBPUT("%02X %02X -",__p[i],__p[i+1]); \
00060     i+=2; \
00061     for(int l=__p[i-1]; l>0; l--) { LBPUT(" %02X",__p[i]); i++; }\
00062     if(i>__n) { LBFLUSH(); LBPUT("length exceeded %d != %d",i,__n); } \
00063     } \
00064   LBEND();
00065 
00066 // -- cCwDes -------------------------------------------------------------------
00067 
00068 static const unsigned char cryptoPC1[] = {
00069    53,46,39,32,50,43,36,29,
00070    22,15, 8, 1,51,44,37,30,
00071    23,16, 9, 2,52,45,38,31,
00072    24,17,10, 3,53,46,39,32,
00073    25,18,11, 4,56,49,42,35,
00074    28,21,14, 7,55,48,41,34,
00075    27,20,13, 6,54,47,40,33,
00076    26,19,12, 5,25,18,11, 4
00077   };
00078 
00079 static const unsigned char cryptoPC2[] = {
00080   18,21,15,28, 5, 9,   7,32,19,10,25,14,
00081   27,23,16, 8,30,12,  20,11,31,24,17, 6,
00082   49,60,39,45,55,63,  38,48,59,53,41,56,
00083   52,57,47,64,42,61,  54,50,58,44,37,40,
00084   };
00085 
00086 #define shiftin(V,R,n) ((V<<1)+(((R)>>(n))&1))
00087 #define rol28(V,n) (V<<(n) | ((V&0x0fffffffL)>>(28-(n))))
00088 #define ror28(V,n) (V>>(n) | ((V&0xfffffff0L)<<(28-(n))))
00089 
00090 #define DESROUND(C,D,T) { \
00091    unsigned int s=0; \
00092    for(int j=7, k=0; j>=0; j--) { \
00093      unsigned int v=0, K=0; \
00094      for(int t=5; t>=0; t--, k++) { \
00095        v=shiftin(v,T,E[k]); \
00096        if(PC2[k]<33) K=shiftin(K,C,32-PC2[k]); \
00097        else          K=shiftin(K,D,64-PC2[k]); \
00098        } \
00099      s=(s<<4) + S[7-j][v^K]; \
00100      } \
00101    T=0; \
00102    for(int j=31; j>=0; j--) T=shiftin(T,s,P[j]); \
00103    }
00104 
00105 class cCwDes : public cDes {
00106 private:
00107   void PrepKey(unsigned char *out, const unsigned char *key) const;
00108   void PrepKey48(unsigned char *out, const unsigned char *key22, unsigned char algo) const;
00109 public:
00110   cCwDes(void);
00111   void CwDes(unsigned char *data, const unsigned char *key22, int mode) const;
00112   void CwL2Des(unsigned char *data, const unsigned char *key22, unsigned char algo) const;
00113   void CwR2Des(unsigned char *data, const unsigned char *key22, unsigned char algo) const;
00114   };
00115 
00116 cCwDes::cCwDes(void)
00117 :cDes(cryptoPC1,cryptoPC2)
00118 {}
00119 
00120 void cCwDes::PrepKey(unsigned char *out, const unsigned char *key) const
00121 {
00122   if(key!=out) memcpy(out,key,8);
00123   Permute(out,PC1,64);
00124 }
00125 
00126 void cCwDes::PrepKey48(unsigned char *out, const unsigned char *key22, unsigned char algo) const
00127 {
00128   memset(out,0,8);
00129   memcpy(out,&key22[16],6);
00130   int ctr=7-(algo&7);
00131   for(int i=8; i>=2 && i>ctr; i--) out[i-2]=key22[i];
00132 }
00133 
00134 void cCwDes::CwDes(unsigned char *data, const unsigned char *key22, int mode) const
00135 {
00136   unsigned char mkey[8];
00137   PrepKey(mkey,key22+9);
00138   LDUMP(L_SYS_VERBOSE,mkey,8,"prepped key DES:");
00139   unsigned int C=UINT32_BE(mkey  );
00140   unsigned int D=UINT32_BE(mkey+4);
00141   unsigned int L=UINT32_BE(data  );
00142   unsigned int R=UINT32_BE(data+4);
00143   if(!(mode&DES_RIGHT)) {
00144     for(int i=15; i>=0; i--) {
00145       C=rol28(C,LS[15-i]); D=rol28(D,LS[15-i]);
00146       unsigned int T=R;
00147       DESROUND(C,D,T);
00148       T^=L; L=R; R=T;
00149       }
00150     }
00151   else {
00152     for(int i=15; i>=0; i--) {
00153       unsigned int T=R;
00154       DESROUND(C,D,T);
00155       T^=L; L=R; R=T;
00156       C=ror28(C,LS[i]); D=ror28(D,LS[i]);
00157       }
00158     }
00159   BYTE4_BE(data  ,L);
00160   BYTE4_BE(data+4,R);
00161 }
00162 
00163 void cCwDes::CwL2Des(unsigned char *data, const unsigned char *key22, unsigned char algo) const
00164 {
00165   unsigned char mkey[8];
00166   PrepKey48(mkey,key22,algo);
00167   PrepKey(mkey,mkey);
00168   LDUMP(L_SYS_VERBOSE,mkey,8,"prepped key L2:");
00169   unsigned int C=UINT32_BE(mkey  );
00170   unsigned int D=UINT32_BE(mkey+4);
00171   unsigned int L=UINT32_BE(data  );
00172   unsigned int R=UINT32_BE(data+4);
00173   for(int i=1; i>=0; i--) {
00174     C=rol28(C,1); D=rol28(D,1);
00175     unsigned int T=R;
00176     DESROUND(C,D,T);
00177     T^=L; L=R; R=T;
00178     PRINTF(L_SYS_VERBOSE,"round %d key L2: %08x %08x",i,C,D);
00179     }
00180   BYTE4_BE(data  ,L);
00181   BYTE4_BE(data+4,R);
00182 }
00183 
00184 void cCwDes::CwR2Des(unsigned char *data, const unsigned char *key22, unsigned char algo) const
00185 {
00186   unsigned char mkey[8];
00187   PrepKey48(mkey,key22,algo);
00188   PrepKey(mkey,mkey);
00189   LDUMP(L_SYS_VERBOSE,mkey,8,"prepped key R2:");
00190   unsigned int C=UINT32_BE(mkey  );
00191   unsigned int D=UINT32_BE(mkey+4);
00192   unsigned int L=UINT32_BE(data  );
00193   unsigned int R=UINT32_BE(data+4);
00194   for(int i=1; i>=0; i--) {
00195     C=rol28(C,15); D=rol28(D,15);
00196     }
00197   for(int i=1; i>=0; i--) {
00198     unsigned int T=R;
00199     DESROUND(C,D,T);
00200     T^=L; L=R; R=T;
00201     C=ror28(C,1); D=ror28(D,1);
00202     }
00203   BYTE4_BE(data  ,R);
00204   BYTE4_BE(data+4,L);
00205 }
00206 
00207 // -- cCryptoworks -------------------------------------------------------------
00208 
00209 class cCryptoworks {
00210 private:
00211   cCwDes des;
00212   cRSA rsa;
00213   cBN exp;
00214   //
00215   void EncDec(unsigned char *data, const unsigned char *key22, unsigned char algo, int mode);
00216 public:
00217   cCryptoworks(void);
00218   void Signature(const unsigned char *data, int len, const unsigned char *key22, unsigned char *sig);
00219   void DecryptDES(unsigned char *data, unsigned char algo, const unsigned char *key22);
00220   bool DecryptRSA(unsigned char *data, int len, unsigned char algo, const unsigned char *key22, BIGNUM *mod);
00221   };
00222 
00223 cCryptoworks::cCryptoworks(void)
00224 {
00225   BN_set_word(exp,2);
00226 }
00227 
00228 void cCryptoworks::EncDec(unsigned char *data, const unsigned char *key22, unsigned char algo, int mode)
00229 {
00230   LDUMP(L_SYS_VERBOSE,data,8,"encdec in :");
00231   PRINTF(L_SYS_VERBOSE,"algo %d",algo);
00232   LDUMP(L_SYS_VERBOSE,key22,22,"encdec key:");
00233   des.CwL2Des(data,key22,algo);
00234   des.CwDes(data,key22,mode);
00235   des.CwR2Des(data,key22,algo);
00236   LDUMP(L_SYS_VERBOSE,data,8,"encdec out:");
00237 }
00238 
00239 void cCryptoworks::Signature(const unsigned char *data, int len, const unsigned char *key22, unsigned char *sig)
00240 {
00241   PRINTF(L_SYS_VERBOSE,"sig start");
00242   int algo=data[0]&7;
00243   if(algo==7) algo=6;
00244   memset(sig,0,8);
00245   int j=0;
00246   bool first=true;
00247   for(int i=0; i<len; i++) {
00248     sig[j]^=data[i];
00249     if(++j>7) {
00250       LDUMP(L_SYS_VERBOSE,sig,8,"sig buf");
00251       if(first) {
00252         des.CwL2Des(sig,key22,algo);
00253         LDUMP(L_SYS_VERBOSE,sig,8,"sig -> ");
00254         }
00255       des.CwDes(sig,key22,DES_LEFT);
00256       j=0; first=false;
00257       LDUMP(L_SYS_VERBOSE,sig,8,"sig -> ");
00258       }
00259     }
00260   if(j>0) {
00261     LDUMP(L_SYS_VERBOSE,sig,8,"sig buf final ");
00262     des.CwDes(sig,key22,DES_LEFT);
00263     LDUMP(L_SYS_VERBOSE,sig,8,"sig        -> ");
00264     }
00265   des.CwR2Des(sig,key22,algo);
00266   LDUMP(L_SYS_VERBOSE,sig,8,"sig calc ");
00267 }
00268 
00269 void cCryptoworks::DecryptDES(unsigned char *data, unsigned char algo, const unsigned char *key22)
00270 {
00271   algo&=7;
00272   if(algo<7) {
00273     EncDec(data,key22,algo,DES_RIGHT);
00274     }
00275   else {
00276     unsigned char k[22], t[8];
00277     memcpy(k,key22,22);
00278     for(int i=0; i<3; i++) {
00279       EncDec(data,k,algo,i&1);
00280       memcpy(t,k,8); memcpy(k,k+8,8); memcpy(k+8,t,8);
00281       }
00282     }
00283 }
00284 
00285 bool cCryptoworks::DecryptRSA(unsigned char *data, int len, unsigned char algo, const unsigned char *key22, BIGNUM *mod)
00286 {
00287   unsigned char buf[64], *mask=AUTOMEM(len);
00288 
00289   LDUMP(L_SYS_VERBOSE,data+len,8,"rsa in:");
00290   memcpy(buf,data+len,8);
00291   EncDec(buf,key22,algo,DES_LEFT);
00292   buf[0]|=0x80;
00293   if((algo&0x18)<0x18) buf[0]=0xFF;
00294   if(algo&8) buf[1]=0xFF;
00295   LDUMP(L_SYS_VERBOSE,buf,8,"rsa seed:");
00296   
00297   static const unsigned char t1[] = { 0xE,0x3,0x5,0x8,0x9,0x4,0x2,0xF,0x0,0xD,0xB,0x6,0x7,0xA,0xC,0x1 };
00298   for(int k=0; k<len; k+=32) {
00299     memcpy(buf+8,buf,8);
00300     for(int i=0; i<8; i++) {
00301       int n=i<<1;
00302       buf[n+1]=buf[i+8];
00303       buf[n  ]=(t1[buf[n+1]>>4]<<4) | t1[buf[i+8]&0xF];
00304       LDUMP(L_SYS_VERBOSE,buf,16,"rsa buf:");
00305       }
00306     for(int i=16; i<64; i+=16) memcpy(&buf[i],buf,16);
00307     buf[31]=((buf[15]<<4)&0xFF) | 6;
00308     buf[16]=buf[0]^1;
00309     buf[32]&=0x7F;
00310     buf[32]|=0x40;
00311     RotateBytes(buf,32);
00312     RotateBytes(buf+32,32);
00313     LDUMP(L_SYS_VERBOSE,buf,64,"rsa data:");
00314 
00315     if(rsa.RSA(buf,buf,64,exp,mod,true)==0) {
00316       PRINTF(L_SYS_CRYPTO,"RSA failed");
00317       return false;
00318       }
00319     RotateBytes(buf,8);
00320     RotateBytes(mask+k,buf+8,min(32,len-k));
00321     }
00322   LDUMP(L_SYS_VERBOSE,mask,len,"rsa out:");
00323 
00324   xxor(data,len,data,mask);
00325   return true;
00326 }
00327 
00328 // -- cPlainKeyCryptoworks -----------------------------------------------------
00329 
00330 #define PLAINLEN_CW_D  16
00331 #define PLAINLEN_CW_CC  6
00332 #define PLAINLEN_CW_R  64
00333 
00334 #define CCTYP               0x00
00335 #define CCID                0xFF
00336 
00337 #define PROV(keynr)         (((keynr)>>16)&0xFF)
00338 #define TYPE(keynr)         (((keynr)>> 8)&0xFF)
00339 #define ID(keynr)           (((keynr)   )&0xFF)
00340 #define KEYSET(prov,typ,id) ((((prov)&0xFF)<<16)|(((typ)&0xFF)<<8)|((id)&0xFF))
00341 
00342 class cPlainKeyCryptoworks : public cDualKey {
00343 protected:
00344   virtual bool IsBNKey(void) const;
00345   virtual int IdSize(void) { return 4; }
00346   virtual cString PrintKeyNr(void);
00347 public:
00348   cPlainKeyCryptoworks(bool Super);
00349   virtual bool Parse(const char *line);
00350   };
00351 
00352 static cPlainKeyTypeReg<cPlainKeyCryptoworks,'W'> KeyReg;
00353 
00354 cPlainKeyCryptoworks::cPlainKeyCryptoworks(bool Super)
00355 :cDualKey(Super,true)
00356 {}
00357 
00358 bool cPlainKeyCryptoworks::IsBNKey(void) const
00359 {
00360   return TYPE(keynr)==0x10;
00361 }
00362 
00363 bool cPlainKeyCryptoworks::Parse(const char *line)
00364 {
00365   unsigned char sid[2], sprov;
00366   if(GetChar(line,&type,1) && GetHex(line,sid,2) && GetHex(line,&sprov,1)) {
00367     int keylen, prov;
00368     type=toupper(type); id=Bin2Int(sid,2); prov=sprov;
00369     line=skipspace(line);
00370     bool ok;
00371     if(!strncasecmp(line,"CC",2)) { // cardkey
00372       keynr=KEYSET(prov,CCTYP,CCID);
00373       keylen=PLAINLEN_CW_CC;
00374       line+=2;
00375       ok=true;
00376       }
00377     else {
00378       unsigned char sid, styp;
00379       ok=GetHex(line,&styp,1) && GetHex(line,&sid,1);
00380       keynr=KEYSET(prov,styp,sid);
00381       keylen=IsBNKey() ? PLAINLEN_CW_R : PLAINLEN_CW_D;
00382       }
00383     if(ok) {
00384       unsigned char *skey=AUTOMEM(keylen);
00385       if(GetHex(line,skey,keylen)) {
00386         SetBinKey(skey,keylen);
00387         return true;
00388         }
00389       }
00390     }
00391   return false;
00392 }
00393 
00394 cString cPlainKeyCryptoworks::PrintKeyNr(void)
00395 {
00396   int prov=PROV(keynr);
00397   int keytyp=TYPE(keynr);
00398   int keyid=ID(keynr);
00399   return cString::sprintf(keytyp==CCTYP && keyid==CCID ? "%02X CC":"%02X %02X %02X",prov,keytyp,keyid);
00400 }
00401 
00402 // -- cSystemCryptoworks -------------------------------------------------------
00403 
00404 #define ECM_ALGO_TYP   5
00405 #define ECM_DATA_START ECM_ALGO_TYP
00406 #define ECM_NANO_LEN   7
00407 #define ECM_NANO_START 8
00408 
00409 class cSystemCryptoworks : public cSystem, private cCryptoworks {
00410 private:
00411 public:
00412   cSystemCryptoworks(void);
00413   virtual bool ProcessECM(const cEcmInfo *ecmInfo, unsigned char *data);
00414 //  virtual void ProcessEMM(int pid, int caid, unsigned char *data);
00415   };
00416 
00417 cSystemCryptoworks::cSystemCryptoworks(void)
00418 :cSystem(SYSTEM_NAME,SYSTEM_PRI)
00419 {
00420 //  hasLogger=true;
00421 }
00422 
00423 bool cSystemCryptoworks::ProcessECM(const cEcmInfo *ecmInfo, unsigned char *data)
00424 {
00425   int len=SCT_LEN(data);
00426   if(data[ECM_NANO_LEN]!=len-ECM_NANO_START) {
00427     PRINTF(L_SYS_ECM,"invalid ECM structure");
00428     return false;
00429     }
00430 
00431   int prov=-1, keyid=0;
00432   for(int i=ECM_NANO_START; i<len; i+=data[i+1]+2) {
00433     if(data[i]==0x83) {
00434       prov =data[i+2]&0xFC;
00435       keyid=data[i+2]&0x03;
00436       break;
00437       }
00438     }
00439   if(prov<0) {
00440     PRINTF(L_SYS_ECM,"provider ID not located in ECM");
00441     return false;
00442     }
00443 
00444   unsigned char key[22];
00445   cPlainKey *pk;
00446   if(!(pk=keys.FindKey('W',ecmInfo->caId,KEYSET(prov,CCTYP,CCID),6))) {
00447     if(doLog) PRINTF(L_SYS_KEY,"missing %04X %02X CC key",ecmInfo->caId,prov);
00448     return false;
00449     }
00450   pk->Get(key+16);
00451 
00452   // RSA stage
00453   DUMPNANO("pre-RSA",&data[ECM_NANO_START],len-ECM_NANO_START);
00454   for(int i=ECM_NANO_START; i<len; i+=data[i+1]+2) {
00455     int l=data[i+1]+2;
00456     switch(data[i]) {
00457       case 0x85:
00458         {
00459         if(!(pk=keys.FindKey('W',ecmInfo->caId,KEYSET(prov,0x31,keyid),16))) {
00460           if(doLog) PRINTF(L_SYS_KEY,"missing %04X %02X 31 %02X key",ecmInfo->caId,prov,keyid);
00461           return false;
00462           }
00463         pk->Get(key);
00464         cBN mod;
00465         if(!(pk=keys.FindKey('W',ecmInfo->caId,KEYSET(prov,0x10,0x00),64))) {
00466           if(doLog) PRINTF(L_SYS_KEY,"missing %04X %02X 10 00 key",ecmInfo->caId,prov);
00467           return false;
00468           }
00469         pk->Get(mod);
00470 
00471         l-=10;
00472         if(!DecryptRSA(&data[i+2],l,data[ECM_ALGO_TYP],key,mod))
00473           return false;
00474         memmove(&data[i],&data[i+2],l);
00475         memmove(&data[i+l],&data[i+l+10],len-i-l);
00476         len-=10;
00477         break;
00478         }
00479       case 0x86:
00480         memmove(&data[i],&data[i+l],len-i-l);
00481         len-=l;
00482         continue;
00483       }
00484     }
00485   DUMPNANO("post-RSA",&data[ECM_NANO_START],len-ECM_NANO_START);
00486 
00487   cKeySnoop ks(this,'W',ecmInfo->caId,KEYSET(prov,0x20,keyid));
00488   if(!(pk=keys.FindKey('W',ecmInfo->caId,KEYSET(prov,0x20,keyid),16))) {
00489     if(doLog) PRINTF(L_SYS_KEY,"missing %04X %02X 20 %02X key",ecmInfo->caId,prov,keyid);
00490     return false;
00491     }
00492   pk->Get(key);
00493 
00494   // DES stage
00495   unsigned char sig[8];
00496   LDUMP(L_SYS_VERBOSE,&data[len-8],8,"sig org:");
00497   data[ECM_NANO_LEN]=len-ECM_NANO_START;
00498   Signature(&data[ECM_DATA_START],len-ECM_DATA_START-10,key,sig);
00499   for(int i=ECM_NANO_START; i<len; i+=data[i+1]+2) {
00500     switch(data[i]) {
00501       case 0xDA:
00502       case 0xDB:
00503       case 0xDC:
00504         for(int j=0; j<data[i+1]; j+=8)
00505           DecryptDES(&data[i+2+j],data[ECM_ALGO_TYP],key);
00506         break;
00507       case 0xDF:
00508         if(memcmp(&data[i+2],sig,8)) {
00509           PRINTF(L_SYS_ECM,"signature failed in ECM");
00510           return false;
00511           }
00512         break;
00513       }
00514     }
00515   
00516   // CW stage
00517   for(int i=ECM_NANO_START; i<len; i+=data[i+1]+2) {
00518     switch(data[i]) {
00519       case 0xDB:
00520         if(data[i+1]==0x10) {
00521           memcpy(cw,&data[i+2],16);
00522           LDUMP(L_SYS_VERBOSE,cw,16,"cw:");
00523           ks.OK(pk);
00524           return true;
00525           }
00526         break;
00527       }
00528     }
00529 
00530   return false;
00531 }
00532 
00533 /*
00534 void cSystemCryptoworks::ProcessEMM(int pid, int caid, unsigned char *data)
00535 {
00536 }
00537 */
00538 
00539 // -- cSystemLinkCryptoworks ---------------------------------------------------
00540 
00541 class cSystemLinkCryptoworks : public cSystemLink {
00542 public:
00543   cSystemLinkCryptoworks(void);
00544   virtual bool CanHandle(unsigned short SysId);
00545   virtual cSystem *Create(void) { return new cSystemCryptoworks; }
00546   };
00547 
00548 static cSystemLinkCryptoworks staticInit;
00549 
00550 cSystemLinkCryptoworks::cSystemLinkCryptoworks(void)
00551 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI)
00552 {
00553   Feature.NeedsKeyFile();
00554 }
00555 
00556 bool cSystemLinkCryptoworks::CanHandle(unsigned short SysId)
00557 {
00558   SysId&=SYSTEM_MASK;
00559   return SYSTEM_CAN_HANDLE(SysId);
00560 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines