|
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 <stdlib.h> 00021 #include <string.h> 00022 00023 #include "system-common.h" 00024 #include "data.h" 00025 #include "parse.h" 00026 #include "misc.h" 00027 00028 #include "irdeto.h" 00029 #include "log-irdeto.h" 00030 00031 // -- cIrdCardInfo ------------------------------------------------------------- 00032 00033 class cIrdCardInfo : public cStructItem, public cProviderIrdeto, public cCardIrdeto { 00034 public: 00035 unsigned char PMK[8], HMK[10]; 00036 bool haveHMK; 00037 // 00038 bool Parse(const char *line); 00039 virtual cString ToString(bool hide); 00040 }; 00041 00042 bool cIrdCardInfo::Parse(const char *line) 00043 { 00044 haveHMK=false; 00045 if(GetHex(line,hexSer,sizeof(hexSer)) && GetHex(line,HMK,sizeof(HMK))) haveHMK=true; 00046 return GetHex(line,&provBase,sizeof(provBase)) && 00047 GetHex(line,provId,sizeof(provId)) && 00048 GetHex(line,PMK,sizeof(PMK)); 00049 } 00050 00051 cString cIrdCardInfo::ToString(bool hide) 00052 { 00053 char s1[20], s2[24], s3[20], s4[20]; 00054 return cString::sprintf("%s %s %02x %s %s", 00055 HexStr(s1,hexSer,sizeof(hexSer)),HexStr(s2,HMK,sizeof(HMK)),provBase, 00056 HexStr(s3,provId,sizeof(provId)),HexStr(s4,PMK,sizeof(PMK))); 00057 } 00058 00059 // -- cIrdCardInfos ------------------------------------------------------------ 00060 00061 class cIrdCardInfos : public cCardInfos<cIrdCardInfo> { 00062 public: 00063 cIrdCardInfos(void); 00064 bool Update(cIrdCardInfo *ci, const unsigned char *pmk, const unsigned char *id); 00065 }; 00066 00067 static cIrdCardInfos Icards; 00068 00069 cIrdCardInfos::cIrdCardInfos(void) 00070 :cCardInfos<cIrdCardInfo>("Irdeto cards","Ird-Beta.KID",SL_READWRITE) 00071 {} 00072 00073 bool cIrdCardInfos::Update(cIrdCardInfo *ci, const unsigned char *pmk, const unsigned char *id) 00074 { 00075 bool res=false; 00076 char str[20], str2[12]; 00077 if(memcmp(ci->PMK,pmk,sizeof(ci->PMK))) { 00078 PRINTF(L_GEN_INFO,"new PMK for I card %s: %s",HexStr(str2,ci->hexSer,sizeof(ci->hexSer)),KeyStr(str,pmk)); 00079 memcpy(ci->PMK,pmk,sizeof(ci->PMK)); 00080 res=true; 00081 } 00082 if(id && memcmp(ci->provId,id,sizeof(ci->provId))) { 00083 PRINTF(L_GEN_INFO,"new PrvID for I card %s: %s",HexStr(str2,ci->hexSer,sizeof(ci->hexSer)),HexStr(str,id,sizeof(ci->provId))); 00084 memcpy(ci->provId,id,sizeof(ci->provId)); 00085 res=true; 00086 } 00087 if(res) Modified(); 00088 return res; 00089 } 00090 00091 // -- cIrdeto ------------------------------------------------------------------ 00092 00093 class cIrdeto { 00094 private: 00095 static const unsigned char T0[], T1[], T2[]; 00096 unsigned char tempKey[10]; 00097 // 00098 void Rotate(unsigned char *p); 00099 void MakeTempKey(const unsigned char *key, int date); 00100 protected: 00101 void SessionKeyCrypt(unsigned char *data, const unsigned char *key, int date); 00102 bool SignatureCheck(const unsigned char *data, int length, const unsigned char *key, int date, const unsigned char *signature, int keylen); 00103 void DecryptIrd(unsigned char *data, unsigned char *key, int rounds, int offset); 00104 }; 00105 00106 const unsigned char cIrdeto::T0[32] = { 00107 0,1,2,3,4,5,6,7, 0,1,2,3,4,5,6,7, 00108 0,1,2,3,4,5,6,7, 0,3,6,1,4,7,2,5 00109 }; 00110 00111 const unsigned char cIrdeto::T1[256] = { 00112 0xDA,0x26,0xE8,0x72,0x11,0x52,0x3E,0x46, 0x32,0xFF,0x8C,0x1E,0xA7,0xBE,0x2C,0x29, 00113 0x5F,0x86,0x7E,0x75,0x0A,0x08,0xA5,0x21, 0x61,0xFB,0x7A,0x58,0x60,0xF7,0x81,0x4F, 00114 0xE4,0xFC,0xDF,0xB1,0xBB,0x6A,0x02,0xB3, 0x0B,0x6E,0x5D,0x5C,0xD5,0xCF,0xCA,0x2A, 00115 0x14,0xB7,0x90,0xF3,0xD9,0x37,0x3A,0x59, 0x44,0x69,0xC9,0x78,0x30,0x16,0x39,0x9A, 00116 0x0D,0x05,0x1F,0x8B,0x5E,0xEE,0x1B,0xC4, 0x76,0x43,0xBD,0xEB,0x42,0xEF,0xF9,0xD0, 00117 0x4D,0xE3,0xF4,0x57,0x56,0xA3,0x0F,0xA6, 0x50,0xFD,0xDE,0xD2,0x80,0x4C,0xD3,0xCB, 00118 0xF8,0x49,0x8F,0x22,0x71,0x84,0x33,0xE0, 0x47,0xC2,0x93,0xBC,0x7C,0x3B,0x9C,0x7D, 00119 0xEC,0xC3,0xF1,0x89,0xCE,0x98,0xA2,0xE1, 0xC1,0xF2,0x27,0x12,0x01,0xEA,0xE5,0x9B, 00120 0x25,0x87,0x96,0x7B,0x34,0x45,0xAD,0xD1, 0xB5,0xDB,0x83,0x55,0xB0,0x9E,0x19,0xD7, 00121 0x17,0xC6,0x35,0xD8,0xF0,0xAE,0xD4,0x2B, 0x1D,0xA0,0x99,0x8A,0x15,0x00,0xAF,0x2D, 00122 0x09,0xA8,0xF5,0x6C,0xA1,0x63,0x67,0x51, 0x3C,0xB2,0xC0,0xED,0x94,0x03,0x6F,0xBA, 00123 0x3F,0x4E,0x62,0x92,0x85,0xDD,0xAB,0xFE, 0x10,0x2E,0x68,0x65,0xE7,0x04,0xF6,0x0C, 00124 0x20,0x1C,0xA9,0x53,0x40,0x77,0x2F,0xA4, 0xFA,0x6D,0x73,0x28,0xE2,0xCD,0x79,0xC8, 00125 0x97,0x66,0x8E,0x82,0x74,0x06,0xC7,0x88, 0x1A,0x4A,0x6B,0xCC,0x41,0xE9,0x9D,0xB8, 00126 0x23,0x9F,0x3D,0xBF,0x8D,0x95,0xC5,0x13, 0xB9,0x24,0x5A,0xDC,0x64,0x18,0x38,0x91, 00127 0x7F,0x5B,0x70,0x54,0x07,0xB6,0x4B,0x0E, 0x36,0xAC,0x31,0xE6,0xD6,0x48,0xAA,0xB4 00128 }; 00129 00130 const unsigned char cIrdeto::T2[256] = { 00131 0x8E,0xD5,0x32,0x53,0x4B,0x18,0x7F,0x95, 0xBE,0x30,0xF3,0xE0,0x22,0xE1,0x68,0x90, 00132 0x82,0xC8,0xA8,0x57,0x21,0xC5,0x38,0x73, 0x61,0x5D,0x5A,0xD6,0x60,0xB7,0x48,0x70, 00133 0x2B,0x7A,0x1D,0xD1,0xB1,0xEC,0x7C,0xAA, 0x2F,0x1F,0x37,0x58,0x72,0x88,0xFF,0x87, 00134 0x1C,0xCB,0x00,0xE6,0x4E,0xAB,0xEB,0xB3, 0xF7,0x59,0x71,0x6A,0x64,0x2A,0x55,0x4D, 00135 0xFC,0xC0,0x51,0x01,0x2D,0xC4,0x54,0xE2, 0x9F,0x26,0x16,0x27,0xF2,0x9C,0x86,0x11, 00136 0x05,0x29,0xA2,0x78,0x49,0xB2,0xA6,0xCA, 0x96,0xE5,0x33,0x3F,0x46,0xBA,0xD0,0xBB, 00137 0x5F,0x84,0x98,0xE4,0xF9,0x0A,0x62,0xEE, 0xF6,0xCF,0x94,0xF0,0xEA,0x1E,0xBF,0x07, 00138 0x9B,0xD9,0xE9,0x74,0xC6,0xA4,0xB9,0x56, 0x3E,0xDB,0xC7,0x15,0xE3,0x80,0xD7,0xED, 00139 0xEF,0x13,0xAC,0xA1,0x91,0xC2,0x89,0x5B, 0x08,0x0B,0x4C,0x02,0x3A,0x5C,0xA9,0x3B, 00140 0xCE,0x6B,0xA7,0xE7,0xCD,0x7B,0xA0,0x47, 0x09,0x6D,0xF8,0xF1,0x8B,0xB0,0x12,0x42, 00141 0x4A,0x9A,0x17,0xB4,0x7E,0xAD,0xFE,0xFD, 0x2C,0xD3,0xF4,0xB6,0xA3,0xFA,0xDF,0xB8, 00142 0xD4,0xDA,0x0F,0x50,0x93,0x66,0x6C,0x20, 0xD8,0x8A,0xDD,0x31,0x1A,0x8C,0x06,0xD2, 00143 0x44,0xE8,0x23,0x43,0x6E,0x10,0x69,0x36, 0xBC,0x19,0x8D,0x24,0x81,0x14,0x40,0xC9, 00144 0x6F,0x2E,0x45,0x52,0x41,0x92,0x34,0xFB, 0x5E,0x0D,0xF5,0x76,0x25,0x77,0x63,0x65, 00145 0xAF,0x4F,0xCC,0x03,0x9D,0x0C,0x28,0x39, 0x85,0xDE,0xB5,0x7D,0x67,0x83,0xBD,0xC3, 00146 0xDC,0x3C,0xAE,0x99,0x04,0x75,0x8F,0x97, 0xC1,0xA5,0x9E,0x35,0x0E,0x3D,0x1B,0x79 00147 }; 00148 00149 void cIrdeto::Rotate(unsigned char *p) 00150 { 00151 unsigned char c, t; 00152 c=p[9]<<7; 00153 t=*p; *p++=(t>>1) | c; c=t<<7; 00154 t=*p; *p++=(t>>1) | c; c=t<<7; 00155 t=*p; *p++=(t>>1) | c; c=t<<7; 00156 t=*p; *p++=(t>>1) | c; c=t<<7; 00157 t=*p; *p++=(t>>1) | c; c=t<<7; 00158 t=*p; *p++=(t>>1) | c; c=t<<7; 00159 t=*p; *p++=(t>>1) | c; c=t<<7; 00160 t=*p; *p++=(t>>1) | c; c=t<<7; 00161 t=*p; *p++=(t>>1) | c; c=t<<7; 00162 t=*p; *p++=(t>>1) | c; c=t<<7; 00163 } 00164 00165 void cIrdeto::MakeTempKey(const unsigned char *key, int date) 00166 { 00167 memcpy(tempKey,key,8); 00168 tempKey[8]=(unsigned char)(date >> 8) ^ key[0]; 00169 tempKey[9]=(unsigned char)date ^ key[1]; 00170 } 00171 00172 void cIrdeto::DecryptIrd(unsigned char *data, unsigned char *key, int rounds, int offset) 00173 { 00174 for(int count=0; count<rounds; count++) { 00175 int index=count % 10; 00176 if(index==0) Rotate(key); 00177 unsigned char k=key[index]; 00178 unsigned char d=data[T0[(count & 0x0f) + offset]] ^ k; 00179 d=(k&1) ? T1[d] : T2[d]; 00180 data[T0[((count+1) & 0x0f) + offset]] ^= d; 00181 } 00182 } 00183 00184 void cIrdeto::SessionKeyCrypt(unsigned char *data, const unsigned char *key, int date) 00185 { 00186 MakeTempKey(key,date); 00187 DecryptIrd(data,tempKey,128,16); 00188 } 00189 00190 bool cIrdeto::SignatureCheck(const unsigned char *data, int length, const unsigned char *key, int date, const unsigned char *signature, int keylen) 00191 { 00192 unsigned char buffer[256]; 00193 memcpy(buffer,data,length); 00194 int rounds; 00195 if((length%8)==0) rounds=40; 00196 else { 00197 int i=0x61; 00198 while((length%8)!=0) buffer[length++]=i++; 00199 rounds=104; 00200 } 00201 00202 if(keylen==10) memcpy(tempKey,key,10); 00203 else MakeTempKey(key,date); 00204 00205 int i=0; 00206 while(i<length-8) { 00207 DecryptIrd(buffer,tempKey,40,0); 00208 i+=8; 00209 for(int j=0; j<8; j++) buffer[j] ^= buffer[i+j]; 00210 Rotate(tempKey); 00211 } 00212 DecryptIrd(buffer,tempKey,rounds,0); 00213 return memcmp(buffer,signature,5)==0; 00214 } 00215 00216 // -- cSystemIrd --------------------------------------------------------------- 00217 00218 class cSystemIrd : public cSystem, private cIrdeto { 00219 private: 00220 unsigned char lastKey; 00221 public: 00222 cSystemIrd(void); 00223 virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *source); 00224 virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer); 00225 }; 00226 00227 cSystemIrd::cSystemIrd(void) 00228 :cSystem(SYSTEM_NAME,SYSTEM_PRI) 00229 { 00230 lastKey=0; 00231 hasLogger=true; 00232 } 00233 00234 bool cSystemIrd::ProcessECM(const cEcmInfo *ecm, unsigned char *source) 00235 { 00236 unsigned char *data=0; 00237 int date=-1, keynr=0; 00238 source+=6; 00239 int length=source[5]+6-5; // 6 header bytes - 5 signature bytes 00240 for(int index=6 ; index<length && (data==0 || date==-1) ;) { 00241 int param=source[index++]; 00242 int len =source[index++] & 0x3f; 00243 00244 switch(param) { 00245 case 0x78: 00246 keynr = source[index]; 00247 data = &source[index+2]; 00248 break; 00249 case 0x00: 00250 case 0x40: 00251 date = (source[index]<<8) | source[index+1]; 00252 break; 00253 } 00254 index+=len; 00255 } 00256 if(data==0 || date==-1) { 00257 if(doLog) PRINTF(L_SYS_ECM,"incomplete ECM structure"); 00258 return false; 00259 } 00260 00261 cKeySnoop ks(this,'I',source[2],KEYSET(0,TYPE_I1,keynr)); 00262 cPlainKey *pk=0; 00263 unsigned char key[8]; 00264 while((pk=keys.FindKey('I',source[2],KEYSET(0,TYPE_I1,keynr),sizeof(key),pk))) { 00265 unsigned char save[16]; 00266 memcpy(save,data,16); // save the encrypted data 00267 pk->Get(key); 00268 SessionKeyCrypt(&data[0],key,date); 00269 SessionKeyCrypt(&data[8],key,date); 00270 if(SignatureCheck(source,length,key,date,&source[length],8)) { 00271 memcpy(cw,&data[0],16); 00272 ks.OK(pk); 00273 return true; 00274 } 00275 memcpy(data,save,16); // put back the encrypted data if it didn't works 00276 } 00277 return false; 00278 } 00279 00280 void cSystemIrd::ProcessEMM(int pid, int caid, const unsigned char *data) 00281 { 00282 int i, numKeys=0, date=0; 00283 unsigned char adr[10], id[4], *pk[4], prov, *mk=0, prvId[3]={0,0,0}; 00284 00285 int n=SCT_LEN(data); 00286 unsigned char *buffer=AUTOMEM(n); 00287 memcpy(buffer,data,n); 00288 00289 int index=cParseIrdeto::AddrLen(buffer); 00290 memset(adr,0,sizeof(adr)); 00291 memcpy(adr,&buffer[3],index+1); 00292 index+=4+4; // 3 header + adr type + 4 {0x01 0x00 0x00 len} 00293 00294 int sindex=index; // save index for sig. check 00295 int slen=buffer[index-1]-5; // save packet length, 5 signature bytes 00296 int maxIndex=index+slen; 00297 if(maxIndex>n-5) { 00298 PRINTF(L_SYS_EMM,"bad packet length (%d > %d)",maxIndex,n-5); 00299 maxIndex=n-5; 00300 } 00301 bool badnano=false; 00302 while(!badnano && index<maxIndex) { 00303 unsigned char nlen=buffer[index+1] & 0x3F; 00304 //unsigned char prio=buffer[index] & 0x40; 00305 unsigned char nano=buffer[index] & ~0x40; 00306 switch(nano) { 00307 case 0x10: // key update 00308 { 00309 int k=(buffer[index+1]>>6)+1; // key counter 00310 if(nlen!=k*9) { badnano=true; break; } 00311 for(i=0 ; i<k ; i++) { 00312 id[i]= buffer[index+2+0+i*9]; 00313 pk[i]=&buffer[index+2+1+i*9]; 00314 numKeys++; 00315 } 00316 } 00317 break; 00318 case 0x00: // date 00319 if(nlen<2) { badnano=true; break; } 00320 date=WORD(buffer,index+2,0xFFFF); 00321 break; 00322 case 0x28: // pmk & provid update 00323 if(nlen!=13) { badnano=true; break; } 00324 prov= buffer[index+2+0]; 00325 mk= &buffer[index+2+2]; 00326 prvId[0]=buffer[index+2+10]; 00327 prvId[1]=buffer[index+2+11]; 00328 prvId[2]=buffer[index+2+12]; 00329 break; 00330 case 0x29: // pmk update 00331 if(nlen!=10) { badnano=true; break; } 00332 prov= buffer[index+2+0]; 00333 mk= &buffer[index+2+2]; 00334 break; 00335 case 0x11: // channel id 00336 if(nlen!=6) { badnano=true; break; } 00337 //chId[0]=buffer[index+2+0]; 00338 //chId[1]=buffer[index+2+1]; 00339 break; 00340 case 0x91: // erase channel id 00341 if(nlen!=6) { badnano=true; break; } 00342 //eraseChId[0]=buffer[index+2+0]; 00343 //eraseChId[1]=buffer[index+2+1]; 00344 break; 00345 case 0x8B: // CB20-matrix 00346 if(nlen!=0x20) { badnano=true; break; } 00347 //cb20ptr=&buffer[index+2]; 00348 break; 00349 case 0x22: // set country code 00350 if(nlen!=3) { badnano=true; break; } 00351 // 00352 break; 00353 case 0x95: // unknown 00354 if(nlen!=2) { badnano=true; break; } 00355 // 00356 break; 00357 case 0x1E: // unknown 00358 if(nlen!=15) { badnano=true; break; } 00359 // 00360 break; 00361 case 0x1F: // unknown 00362 if(nlen!=3) { badnano=true; break; } 00363 // 00364 break; 00365 case 0x16: // unknown 00366 if(nlen!=2) { badnano=true; break; } 00367 // 00368 break; 00369 case 0x12: // unknown 00370 if(nlen!=6) { badnano=true; break; } 00371 // 00372 break; 00373 00374 default: 00375 PRINTF(L_SYS_EMM,"unhandled nano 0x%02x",nano); 00376 break; 00377 } 00378 index+=nlen+2; 00379 } 00380 if(badnano || index!=maxIndex) { 00381 PRINTF(L_SYS_EMM,"bad nano/bad paket"); 00382 return; 00383 } 00384 00385 // lastKey: save cpu time if we get bursts of the same key 00386 if((numKeys>0 && (id[0]!=lastKey || numKeys>1)) || mk) { 00387 cIrdCardInfo *ci=Icards.First(); 00388 unsigned char *chkkey=AUTOMEM(max(sizeof(ci->PMK),sizeof(ci->HMK))); 00389 while(ci) { 00390 ci->hexBase=cParseIrdeto::AddrBase(buffer); 00391 if((numKeys>0 && (ci->cProviderIrdeto::MatchEMM(buffer) || CheckNull(ci->provId,sizeof(ci->provId)) )) || 00392 (mk && ci->haveHMK && (ci->cCardIrdeto::MatchEMM(buffer)))) { 00393 LBSTARTF(L_SYS_EMM); 00394 LBPUT("%02x %02x%02x%02x",buffer[3],buffer[4],buffer[5],buffer[6]); 00395 00396 for(i=0 ; i<numKeys ; i++) { 00397 lastKey=id[i]; 00398 SessionKeyCrypt(pk[i],ci->PMK,date); 00399 } 00400 int keylen; 00401 if(mk) { 00402 memcpy(chkkey,ci->HMK,sizeof(ci->HMK)); // key is modified in decryptIrd() 00403 DecryptIrd(mk,chkkey,128,16); 00404 keylen=sizeof(ci->HMK); 00405 memcpy(chkkey,ci->HMK,sizeof(ci->HMK)); // signature check with HMK 00406 } 00407 else { 00408 keylen=sizeof(ci->PMK); 00409 memcpy(chkkey,ci->PMK,sizeof(ci->PMK)); // signature check with PMK 00410 } 00411 00412 memcpy(&buffer[sindex-6],adr,5); 00413 if(SignatureCheck(&buffer[sindex-6],slen+6,chkkey,date,&buffer[sindex+slen],keylen)) 00414 { 00415 char str[20]; 00416 LBPUT(" - OK"); 00417 for(i=0 ; i<numKeys ; i++) LBPUT(" - PK %02x %s",id[i],KeyStr(str,pk[i])); 00418 if(mk) LBPUT(" - PMK %s",KeyStr(str,mk)); 00419 00420 for(i=0 ; i<numKeys ; i++) { 00421 FoundKey(); 00422 if(keys.NewKey('I',ci->provBase,id[i],pk[i],8)) NewKey(); 00423 } 00424 if(mk) { 00425 FoundKey(); 00426 if(Icards.Update(ci,mk,prvId[0]?prvId:0)) NewKey(); 00427 } 00428 break; 00429 } 00430 else { 00431 LBPUT(" - FAIL"); 00432 } 00433 LBEND(); 00434 00435 memcpy(buffer,data,n); // restore the buffer 00436 } 00437 ci=Icards.Next(ci); 00438 } 00439 } 00440 } 00441 00442 // -- cSystemLinkIrd ----------------------------------------------------------- 00443 00444 class cSystemLinkIrd : public cSystemLink { 00445 public: 00446 cSystemLinkIrd(void); 00447 virtual bool CanHandle(unsigned short SysId); 00448 virtual cSystem *Create(void) { return new cSystemIrd; } 00449 }; 00450 00451 static cSystemLinkIrd staticInit; 00452 00453 cSystemLinkIrd::cSystemLinkIrd(void) 00454 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI) 00455 { 00456 Feature.NeedsKeyFile(); 00457 } 00458 00459 bool cSystemLinkIrd::CanHandle(unsigned short SysId) 00460 { 00461 return (SysId&SYSTEM_MASK)==SYSTEM_IRDETO || (SysId&SYSTEM_MASK)==SYSTEM_BETA; 00462 }