|
SASC
DVBSoftCAM
|
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 }