SASC
DVBSoftCAM

newcamd.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 <stdio.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <crypt.h>
00024 #include <byteswap.h>
00025 
00026 #include <vdr/thread.h>
00027 
00028 #include "cc.h"
00029 #include "misc.h"
00030 #include "parse.h"
00031 
00032 #include <openssl/des.h>
00033 
00034 #define CWS_NETMSGSIZE 272
00035 
00036 // -- cTripleDes ---------------------------------------------------------------
00037 
00038 class cTripleDes {
00039 private:
00040   DES_key_schedule ks1,ks2;
00041   //
00042   void SetOddParity(unsigned char *key); // key must be 16 bytes!
00043 protected:
00044   unsigned char desKey[16];
00045   //
00046   void ScheduleKey(void);
00047   int PadMessage(unsigned char *data, int len);
00048   void Expand(unsigned char *expanded, const unsigned char *normal); // 14 byte key input, 16 byte expanded output
00049   void Decrypt(unsigned char *data, int len);
00050   const unsigned char *Encrypt(const unsigned char *data, int len, unsigned char *crypt);
00051   };
00052 
00053 void cTripleDes::SetOddParity(unsigned char *key)
00054 {
00055   DES_set_odd_parity((DES_cblock *)&key[0]); // set odd parity on both keys
00056   DES_set_odd_parity((DES_cblock *)&key[8]); // 
00057 }
00058 
00059 void cTripleDes::ScheduleKey(void)
00060 {
00061   DES_key_sched((DES_cblock *)&desKey[0],&ks1);
00062   DES_key_sched((DES_cblock *)&desKey[8],&ks2);
00063 }
00064 
00065 void cTripleDes::Expand(unsigned char *expand, const unsigned char *normal)
00066 {
00067   expand[0]  =   normal[0] & 0xfe;
00068   expand[1]  = ((normal[0] << 7) | (normal[1] >> 1)) & 0xfe;
00069   expand[2]  = ((normal[1] << 6) | (normal[2] >> 2)) & 0xfe;
00070   expand[3]  = ((normal[2] << 5) | (normal[3] >> 3)) & 0xfe;
00071   expand[4]  = ((normal[3] << 4) | (normal[4] >> 4)) & 0xfe;
00072   expand[5]  = ((normal[4] << 3) | (normal[5] >> 5)) & 0xfe;
00073   expand[6]  = ((normal[5] << 2) | (normal[6] >> 6)) & 0xfe;
00074   expand[7]  =   normal[6] << 1;
00075   expand[8]  =   normal[7] & 0xfe;
00076   expand[9]  = ((normal[7] << 7)  | (normal[8] >> 1)) & 0xfe;
00077   expand[10] = ((normal[8] << 6)  | (normal[9] >> 2)) & 0xfe;
00078   expand[11] = ((normal[9] << 5)  | (normal[10] >> 3)) & 0xfe;
00079   expand[12] = ((normal[10] << 4) | (normal[11] >> 4)) & 0xfe;
00080   expand[13] = ((normal[11] << 3) | (normal[12] >> 5)) & 0xfe;
00081   expand[14] = ((normal[12] << 2) | (normal[13] >> 6)) & 0xfe;
00082   expand[15] =   normal[13] << 1;
00083   SetOddParity(expand);
00084 }
00085 
00086 int cTripleDes::PadMessage(unsigned char *data, int len)
00087 {
00088   DES_cblock padBytes;
00089   unsigned char noPadBytes;
00090 
00091   noPadBytes = (8 - ((len - 1) % 8)) % 8;
00092   if(len+noPadBytes+1 >= CWS_NETMSGSIZE-8) {
00093     PRINTF(L_CC_NEWCAMD,"message overflow in cTripleDes::PadMessage");
00094     return -1;
00095     }
00096 
00097   DES_random_key((DES_cblock *)padBytes);
00098   memcpy(data+len,padBytes,noPadBytes); len+=noPadBytes;
00099   data[len]=XorSum(data+2,len-2);
00100   return len+1;
00101 }
00102 
00103 const unsigned char *cTripleDes::Encrypt(const unsigned char *data, int len, unsigned char *crypt)
00104 {
00105   DES_cblock ivec;
00106   DES_random_key((DES_cblock *)ivec);
00107   memcpy(crypt+len,ivec,sizeof(ivec));
00108   DES_ede2_cbc_encrypt(data+2,crypt+2,len-2,&ks1,&ks2,(DES_cblock *)ivec,DES_ENCRYPT);
00109   return crypt;
00110 }
00111 
00112 void cTripleDes::Decrypt(unsigned char *data, int len)
00113 {
00114   if((len-2) % 8 || (len-2)<16) {
00115     PRINTF(L_CC_NEWCAMD,"warning: encrypted data size mismatch");
00116     return;
00117     }
00118   DES_cblock ivec;
00119   len-=sizeof(ivec); memcpy(ivec, data+len, sizeof(ivec));
00120   DES_ede2_cbc_encrypt(data+2,data+2,len-2,&ks1,&ks2,(DES_cblock *)ivec,DES_DECRYPT);
00121 }
00122 
00123 // -- cNewCamdClient -----------------------------------------------------------
00124 
00125 #define USERLEN        32
00126 #define PASSWDLEN      32
00127 #define CWS_FIRSTCMDNO 0xe0
00128 
00129 typedef enum {
00130   MSG_CLIENT_2_SERVER_LOGIN = CWS_FIRSTCMDNO,
00131   MSG_CLIENT_2_SERVER_LOGIN_ACK,
00132   MSG_CLIENT_2_SERVER_LOGIN_NAK,
00133   MSG_CARD_DATA_REQ,
00134   MSG_CARD_DATA,
00135   MSG_SERVER_2_CLIENT_NAME,
00136   MSG_SERVER_2_CLIENT_NAME_ACK,
00137   MSG_SERVER_2_CLIENT_NAME_NAK,
00138   MSG_SERVER_2_CLIENT_LOGIN,
00139   MSG_SERVER_2_CLIENT_LOGIN_ACK,
00140   MSG_SERVER_2_CLIENT_LOGIN_NAK,
00141   MSG_ADMIN,
00142   MSG_ADMIN_ACK,
00143   MSG_ADMIN_LOGIN,
00144   MSG_ADMIN_LOGIN_ACK,
00145   MSG_ADMIN_LOGIN_NAK,
00146   MSG_ADMIN_COMMAND,
00147   MSG_ADMIN_COMMAND_ACK,
00148   MSG_ADMIN_COMMAND_NAK
00149   } net_msg_type_t;
00150 
00151 typedef enum {
00152   COMMTYPE_CLIENT,
00153   COMMTYPE_SERVER
00154   } comm_type_t;
00155 
00156 struct CustomData {
00157   union {
00158     struct {
00159       unsigned short prgId; // Big-Endian
00160       unsigned char data[6];
00161       } V525;
00162     struct {
00163       unsigned int prgId;  // Big-Endian
00164       } V520;
00165     };
00166   };
00167 
00168 class cCardClientNewCamd : public cCardClient, private cTripleDes, private cIdSet {
00169 private:
00170   unsigned char configKey[14];
00171   unsigned short netMsgId;
00172   int caId, protoVers, cdLen;
00173   bool emmProcessing, loginOK;
00174   char username[USERLEN], password[PASSWDLEN];
00175   //
00176   void InitVars(void);
00177   void InitProtoVers(int vers);
00178   bool NextProto(void);
00179   void InitCustomData(struct CustomData *cd, const unsigned short PrgId, const unsigned char *data);
00180   void PrepareLoginKey(unsigned char *deskey, const unsigned char *rkey, const unsigned char *ckey);
00181   // Client Helper functions
00182   bool SendMessage(const unsigned char *data, int len, bool UseMsgId, const struct CustomData *cd=0, comm_type_t commType=COMMTYPE_CLIENT);
00183   int ReceiveMessage(unsigned char *data, bool UseMsgId, struct CustomData *cd=0, comm_type_t commType=COMMTYPE_CLIENT);
00184   bool CmdSend(net_msg_type_t cmd,  comm_type_t commType=COMMTYPE_CLIENT);
00185   int CmdReceive(comm_type_t commType=COMMTYPE_CLIENT);
00186 public:
00187   cCardClientNewCamd(const char *Name);
00188   // 
00189   virtual bool Init(const char *CfgDir);
00190   virtual bool Login(void);
00191   virtual bool CanHandle(unsigned short SysId);
00192   virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
00193   virtual bool ProcessEMM(int caSys, const unsigned char *data);
00194   };
00195 
00196 static cCardClientLinkReg<cCardClientNewCamd> __ncd("Newcamd");
00197 
00198 cCardClientNewCamd::cCardClientNewCamd(const char *Name)
00199 :cCardClient(Name)
00200 {
00201   memset(username,0,sizeof(username));
00202   memset(password,0,sizeof(password));
00203   InitVars();
00204   InitProtoVers(525);
00205   so.SetRWTimeout(20*1000);
00206 }
00207 
00208 void cCardClientNewCamd::InitVars(void)
00209 {
00210   netMsgId=0; caId=-1; emmProcessing=false;
00211   ResetIdSet();
00212 }
00213 
00214 void cCardClientNewCamd::InitProtoVers(int vers)
00215 {
00216   switch(vers) {
00217     case 525: protoVers=525; cdLen=8; break;
00218     default:  protoVers=520; cdLen=4; break;
00219     }
00220   PRINTF(L_CC_NEWCAMD,"now using protocol version %d (cdLen=%d)",protoVers,cdLen);
00221   loginOK=false;
00222 }
00223 
00224 bool cCardClientNewCamd::NextProto(void)
00225 {
00226   if(loginOK) return false;
00227   switch(protoVers) {
00228     case 525: InitProtoVers(520); break;
00229     default:  return false;
00230     }
00231   return true;
00232 }
00233 
00234 void cCardClientNewCamd::InitCustomData(struct CustomData *cd, const unsigned short PrgId, const unsigned char *data)
00235 {
00236   if(cd) {
00237     switch(protoVers) {
00238       case 525:
00239         cd->V525.prgId=bswap_16(PrgId);
00240         if(data) memcpy(cd->V525.data,data,sizeof(cd->V525.data));
00241         else memset(cd->V525.data,0,sizeof(cd->V525.data));
00242         break;
00243       default:
00244         cd->V520.prgId=bswap_32((unsigned int)PrgId);
00245         break;
00246       }
00247     }
00248 }
00249 
00250 void cCardClientNewCamd::PrepareLoginKey(unsigned char *deskey, const unsigned char *rkey, const unsigned char *ckey)
00251 {
00252   unsigned char tmpkey[14];
00253   for (int i=0; i<(int)sizeof(tmpkey); i++) { tmpkey[i]=rkey[i]^ckey[i]; }
00254   Expand(deskey, tmpkey);
00255 }
00256 
00257 bool cCardClientNewCamd::SendMessage(const unsigned char *data, int len, bool UseMsgId, const struct CustomData *cd, comm_type_t commType)
00258 {
00259   if(len<3||len+cdLen+4>CWS_NETMSGSIZE) {
00260     PRINTF(L_CC_NEWCAMD,"bad message size %d in SendMessage",len);
00261     return false;
00262     }
00263   unsigned char netbuf[CWS_NETMSGSIZE];
00264   memset(&netbuf[2],0,cdLen+2);
00265   memcpy(&netbuf[cdLen+4],data,len);
00266   netbuf[cdLen+4+1]=(data[1]&0xf0)|(((len-3)>>8)&0x0f);
00267   netbuf[cdLen+4+2]=(len-3)&0xff;
00268   len+=4;
00269   if(cd) memcpy(&netbuf[4],cd,cdLen);
00270   len+=cdLen;
00271   if(UseMsgId) {
00272     if(commType==COMMTYPE_CLIENT) netMsgId++;
00273     netbuf[2]=netMsgId>>8;
00274     netbuf[3]=netMsgId&0xff;
00275     }
00276   if((len=cTripleDes::PadMessage(netbuf,len))<0) {
00277     PRINTF(L_CC_NEWCAMD,"PadMessage failed");
00278     return false;
00279     }
00280   if((data=cTripleDes::Encrypt(netbuf,len,netbuf))==0) {
00281     PRINTF(L_CC_NEWCAMD,"Encrypt failed");
00282     return false;
00283     }
00284   len+=sizeof(DES_cblock);
00285   netbuf[0]=(len-2)>>8;
00286   netbuf[1]=(len-2)&0xff;
00287   return cCardClient::SendMsg(netbuf,len);
00288 }
00289 
00290 int cCardClientNewCamd::ReceiveMessage(unsigned char *data, bool UseMsgId, struct CustomData *cd, comm_type_t commType)
00291 {
00292   unsigned char netbuf[CWS_NETMSGSIZE];
00293   if(cCardClient::RecvMsg(netbuf,2)<0) {
00294     PRINTF(L_CC_NEWCAMD,"failed to read message length");
00295     return 0;
00296     }
00297   int mlen=WORD(netbuf,0,0xFFFF);
00298   if(mlen>CWS_NETMSGSIZE-2) {
00299    PRINTF(L_CC_NEWCAMD,"receive message buffer overflow");
00300    return 0;
00301    }
00302   if(cCardClient::RecvMsg(netbuf+2,mlen,200)<0) {
00303     PRINTF(L_CC_NEWCAMD,"failed to read message");
00304     return 0;
00305     }
00306   mlen+=2;
00307   cTripleDes::Decrypt(netbuf,mlen); mlen-=sizeof(DES_cblock);
00308   if(XorSum(netbuf+2,mlen-2)) {
00309     PRINTF(L_CC_NEWCAMD,"checksum error");
00310     return 0;
00311     }
00312 
00313   int returnLen=WORD(netbuf,5+cdLen,0x0FFF)+3;
00314   if(cd) memcpy(cd,&netbuf[4],cdLen);
00315   if(UseMsgId) {
00316     switch(commType) {
00317       case COMMTYPE_SERVER:
00318         netMsgId=WORD(netbuf,2,0xFFFF);
00319         break;
00320       case COMMTYPE_CLIENT:
00321         if(netMsgId!=WORD(netbuf,2,0xFFFF)) {
00322           PRINTF(L_CC_NEWCAMD,"bad msgid %04x != %04x ",netMsgId,WORD(netbuf,2,0xFFFF));
00323           return -2;
00324           }
00325         break;
00326       default:
00327         PRINTF(L_CC_NEWCAMD,"unknown commType %x",commType);
00328         return -1;
00329       }
00330     }
00331   memcpy(data,netbuf+4+cdLen,returnLen);
00332   return returnLen;
00333 }
00334 
00335 bool cCardClientNewCamd::CmdSend(net_msg_type_t cmd, comm_type_t commType)
00336 {
00337   unsigned char buffer[3];
00338   buffer[0]=cmd; buffer[1]=buffer[2]=0;
00339   return SendMessage(buffer,sizeof(buffer),false,0,commType);
00340 }
00341 
00342 int cCardClientNewCamd::CmdReceive(comm_type_t commType)
00343 {
00344   unsigned char buffer[CWS_NETMSGSIZE];
00345   if(ReceiveMessage(buffer,false,0,commType)!=3) return -1;
00346   return buffer[0];
00347 }
00348 
00349 bool cCardClientNewCamd::CanHandle(unsigned short SysId)
00350 {
00351   return (caId>=0 && (SysId==caId || (caId==0x1234 && SysId==0x1801))) || cCardClient::CanHandle(SysId);
00352 }
00353 
00354 bool cCardClientNewCamd::Init(const char *config)
00355 {
00356   cMutexLock lock(this);
00357   Logout();
00358   int num=0;
00359   char key[29];
00360   const char *tmp=key;
00361   if(!ParseStdConfig(config,&num)
00362      || sscanf(&config[num],":%31[^:]:%31[^:]:%28[^:]",username,password,key)!=3
00363      || GetHex(tmp,configKey,sizeof(configKey),false)!=14) return false;
00364   char str[32];
00365   PRINTF(L_CC_CORE,"%s: username=%s password=%s key=%s",name,username,password,HexStr(str,configKey,14));
00366   return true;
00367 }
00368 
00369 bool cCardClientNewCamd::Login(void)
00370 {
00371   Logout();
00372   if(!so.Connect(hostname,port)) return false;
00373 
00374   InitVars();
00375   unsigned char randData[14];
00376   if(so.Read(randData,sizeof(randData))<0) {
00377     PRINTF(L_CC_NEWCAMD,"no connect answer from %s:%d",hostname,port);
00378     Logout();
00379     return false;
00380     }
00381 
00382   char *crPasswd=crypt(password,"$1$abcdefgh$");
00383   unsigned char buffer[CWS_NETMSGSIZE];
00384   const int userLen=strlen(username)+1;
00385   const int passLen=strlen(crPasswd)+1;
00386   
00387   // prepare the initial login message
00388   buffer[0] = MSG_CLIENT_2_SERVER_LOGIN;
00389   buffer[1] = 0;
00390   buffer[2] = userLen+passLen;
00391   memcpy(&buffer[3],username,userLen);
00392   memcpy(&buffer[3]+userLen,crPasswd,passLen);
00393 
00394   // XOR configKey with randData and expand the 14 byte result -> 16 byte
00395   PrepareLoginKey(desKey,randData,configKey);
00396   cTripleDes::ScheduleKey();
00397 
00398   // set NewCS client identification
00399   // this seems to conflict with other cardservers e.g. rqcs !!
00400   //struct CustomData cd;
00401   //InitCustomData(&cd,0x5644,0);
00402 
00403   if(!SendMessage(buffer,buffer[2]+3,true) || CmdReceive()!=MSG_CLIENT_2_SERVER_LOGIN_ACK) {
00404     PRINTF(L_CC_NEWCAMD,"failed to login to cardserver for username %s (proto %d)",username,protoVers);
00405     if(NextProto()) return Login();
00406     return false;
00407     }
00408 
00409   // create the session key (for usage later)
00410   unsigned char tmpkey[14];
00411   memcpy(tmpkey, configKey, sizeof(tmpkey));
00412   const int passStrLen=strlen(crPasswd);
00413   for(int i=0; i<passStrLen; ++i) tmpkey[i%14]^=crPasswd[i];
00414 
00415   cTripleDes::Expand(desKey,tmpkey); // expand 14 byte key -> 16 byte
00416   cTripleDes::ScheduleKey();
00417 
00418   if(!CmdSend(MSG_CARD_DATA_REQ) || ReceiveMessage(buffer,false)<=0) return false;
00419   if(buffer[0] == MSG_CARD_DATA) {
00420     int c=(buffer[4]<<8)+buffer[5];
00421     if(c!=caId) CaidsChanged();
00422     caId=c;
00423     LBSTARTF(L_CC_LOGIN);
00424     char str[32], str2[32];
00425     LBPUT("%s: CaID=%04x admin=%d srvUA=%s",name,caId,buffer[3]==1,HexStr(str,&buffer[6],8));
00426     if(!CheckNull(&buffer[6],8)) {
00427       emmProcessing=true;
00428       switch(caId>>8) {
00429         case 0x17:
00430         case 0x06: SetCard(new cCardIrdeto(buffer[6+4],&buffer[6+5])); break;
00431         case 0x01: SetCard(new cCardSeca(&buffer[6+2])); break;
00432         case 0x0b: SetCard(new cCardConax(&buffer[6+1])); break;
00433         case 0x09: SetCard(new cCardNDS(&buffer[6+4])); break;
00434         case 0x05: SetCard(new cCardViaccess(&buffer[6+3])); break;
00435         case 0x0d: SetCard(new cCardCryptoworks(&buffer[6+3])); break;
00436         case 0x12:
00437         case 0x18: if(caId>=0x1801 || caId==0x1234) {
00438                      SetCard(new cCardNagra2(&buffer[6+4]));
00439                      break;
00440                      }
00441                    // fall through to default
00442         default:
00443           LBPUT(" (unhandled)");
00444           break;
00445         }
00446       }
00447     LBPUT(" provider");
00448     for(int i=(buffer[14]-1)*11; i>=0; i-=11) {
00449       LBPUT(" %s/%s",HexStr(str2,&buffer[15+i],3),HexStr(str,&buffer[18+i],8));
00450       if(!CheckNull(&buffer[18+i],8)) {
00451         switch(caId>>8) {
00452           case 0x17:
00453           case 0x06: AddProv(new cProviderIrdeto(buffer[18+i+4],&buffer[18+i+5])); break;
00454           case 0x01: AddProv(new cProviderSeca(&buffer[15+i+1],&buffer[18+i+4])); break;
00455           case 0x0b: AddProv(new cProviderConax(&buffer[18+i+1])); break;
00456           case 0x09: AddProv(new cProviderNDS(&buffer[18+i+4])); break;
00457           case 0x05: AddProv(new cProviderViaccess(&buffer[15+i],&buffer[18+i+4])); break;
00458           case 0x0d: AddProv(new cProviderCryptoworks(&buffer[18+i+3])); break;
00459           default:
00460             LBPUT(" <unhandled>");
00461             break;
00462           }
00463         }
00464       }
00465     LBEND();
00466     if(emmProcessing && !emmAllowed)
00467       PRINTF(L_CC_EMM,"%s: EMM disabled from config",name);
00468     }
00469   loginOK=true;
00470   return true;
00471 }
00472 
00473 bool cCardClientNewCamd::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
00474 {
00475   cMutexLock lock(this);
00476   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
00477   so.Flush();
00478 
00479   struct CustomData cd;
00480   InitCustomData(&cd,(unsigned short)ecm->prgId,0);
00481   if(!SendMessage(data,SCT_LEN(data),true,&cd)) return false;
00482   unsigned char buffer[CWS_NETMSGSIZE];
00483   int n;
00484   while((n=ReceiveMessage(buffer,true))==-2)
00485     PRINTF(L_CC_NEWCAMD,"msg ID sync error. Retrying...");
00486   switch(n) {
00487     case 19: // ecm was decoded
00488       // check for zero cw, as newcs doesn't send both cw's every time
00489       if(!CheckNull(buffer+3+0,8)) memcpy(cw+0,buffer+3+0,8);
00490       if(!CheckNull(buffer+3+8,8)) memcpy(cw+8,buffer+3+8,8);
00491       return true;
00492     case 3:
00493       PRINTF(L_CC_ECM,"%s: card was not able to decode the channel",name);
00494       break;
00495     default:
00496       PRINTF(L_CC_NEWCAMD,"unexpected server response (code %d)",n);
00497       break;
00498     }
00499   return false;
00500 }
00501 
00502 bool cCardClientNewCamd::ProcessEMM(int caSys, const unsigned char *data)
00503 {
00504   if(emmProcessing && emmAllowed) {
00505     cMutexLock lock(this);
00506     cAssembleData ad(data);
00507     if(MatchAndAssemble(&ad,0,0)) {
00508       while((data=ad.Assembled())) {
00509         int len=SCT_LEN(data);
00510         int id=msEMM.Get(data,len,0);
00511         if(id>0 || emmAllowed>1) {
00512           if(SendMessage(data,len,true,0)) {
00513             unsigned char buffer[CWS_NETMSGSIZE];
00514             len=ReceiveMessage(buffer,true);
00515             if(len>=3) {
00516               if(!(buffer[1]&0x10))
00517                 PRINTF(L_CC_EMM,"EMM rejected by card");
00518               }
00519             else
00520               PRINTF(L_CC_NEWCAMD,"unexpected server response (code %d)",len);
00521             }
00522           msEMM.Cache(id,true,0);
00523           }
00524         }
00525       return true;
00526       }
00527     }
00528   return false;
00529 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines