|
SASC-NG
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 "helper.h" 00027 #include "misc.h" 00028 00029 #include <openssl/des.h> 00030 #include "openssl-compat.h" 00031 00032 #include "irdeto.h" 00033 #include "log-irdeto.h" 00034 00035 // -- cIrdeto2 ----------------------------------------------------------------- 00036 00037 class cIrdeto2 { 00038 private: 00039 DES_key_schedule ks1, ks2; 00040 // 00041 void ScheduleKey(const unsigned char *key); 00042 void DES3(unsigned char *data, int mode); 00043 protected: 00044 void Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len); 00045 void Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len); 00046 bool CalculateHash(const unsigned char *key, const unsigned char *iv, const unsigned char *data, int len); 00047 }; 00048 00049 void cIrdeto2::ScheduleKey(const unsigned char *key) 00050 { 00051 DES_key_sched((DES_cblock *)key,&ks1); 00052 DES_key_sched((DES_cblock *)(key+8),&ks2); 00053 } 00054 00055 void cIrdeto2::DES3(unsigned char *data, int mode) 00056 { 00057 int m1, m2; 00058 if(mode) { m1=DES_DECRYPT; m2=DES_ENCRYPT; } 00059 else { m1=DES_ENCRYPT; m2=DES_DECRYPT; } 00060 DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks1,m1); 00061 DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks2,m2); 00062 DES_ecb_encrypt((DES_cblock *)data,(DES_cblock *)data,&ks1,m1); 00063 } 00064 00065 void cIrdeto2::Encrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len) 00066 { 00067 ScheduleKey(key); 00068 len&=~7; 00069 const unsigned char *tmp=seed; 00070 for(int i=0; i<len; i+=8) { 00071 xxor(&data[i],8,&data[i],tmp); tmp=&data[i]; 00072 DES3(&data[i],0); 00073 } 00074 } 00075 00076 void cIrdeto2::Decrypt(unsigned char *data, const unsigned char *seed, const unsigned char *key, int len) 00077 { 00078 ScheduleKey(key); 00079 len&=~7; 00080 unsigned char buf[2][8]; 00081 int n=0; 00082 memcpy(buf[n],seed,8); 00083 for(int i=0; i<len; i+=8,data+=8,n^=1) { 00084 memcpy(buf[1-n],data,8); 00085 DES3(data,1); 00086 xxor(data,8,data,buf[n]); 00087 } 00088 } 00089 00090 bool cIrdeto2::CalculateHash(const unsigned char *key, const unsigned char *iv, const unsigned char *data, int len) 00091 { 00092 ScheduleKey(key); 00093 unsigned char cbuff[8]; 00094 memset(cbuff,0,sizeof(cbuff)); 00095 len-=8; 00096 for(int y=0; y<len; y+=8) { 00097 if(y<len-8) { 00098 xxor(cbuff,8,cbuff,&data[y]); 00099 LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES XOR in:"); 00100 } 00101 else { 00102 int l=len-y; 00103 xxor(cbuff,l,cbuff,&data[y]); 00104 xxor(cbuff+l,8-l,cbuff+l,iv+8); 00105 LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES XOR(%d) in:",8-l); 00106 } 00107 DES3(cbuff,0); 00108 LDUMP(L_SYS_VERBOSE,cbuff,8,"3DES out:"); 00109 } 00110 LDUMP(L_SYS_VERBOSE,cbuff,8,"CryptBuffer:"); 00111 LDUMP(L_SYS_VERBOSE,&data[len],8,"MACBuffer:"); 00112 return memcmp(cbuff,&data[len],8)==0; 00113 } 00114 00115 // -- cSystemIrd2 -------------------------------------------------------------- 00116 00117 #define NANOLEN(_a) ((_a) ? ((_a)&0x3F)+2 : 1) 00118 00119 class cSystemIrd2 : public cSystem, private cIrdeto2 { 00120 private: 00121 void PrepareSeed(unsigned char *seed, const unsigned char *key); 00122 void NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv); 00123 public: 00124 cSystemIrd2(void); 00125 virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data); 00126 virtual void ProcessEMM(int pid, int caid, const unsigned char *data); 00127 }; 00128 00129 cSystemIrd2::cSystemIrd2(void) 00130 :cSystem(SYSTEM_NAME2,SYSTEM_PRI2) 00131 { 00132 hasLogger=true; 00133 } 00134 00135 void cSystemIrd2::PrepareSeed(unsigned char *seed, const unsigned char *key) 00136 { 00137 unsigned char blank[16]; 00138 memset(blank,0,16); 00139 Encrypt(seed,blank,key,16); 00140 } 00141 00142 void cSystemIrd2::NanoDecrypt(unsigned char *data, int i, int len, const unsigned char *key, const unsigned char *iv) 00143 { 00144 while(i<len) { 00145 int l=NANOLEN(data[i+1]); 00146 switch(data[i]) { 00147 case 0x10: 00148 case 0x50: if(l==0x13 && i<=len-l) Decrypt(&data[i+3],iv,key,16); break; 00149 case 0x78: if(l==0x14 && i<=len-l) Decrypt(&data[i+4],iv,key,16); break; 00150 } 00151 i+=l; 00152 } 00153 } 00154 00155 bool cSystemIrd2::ProcessECM(const cEcmInfo *ecm, unsigned char *data) 00156 { 00157 int len=data[11]; 00158 if(len!=0x28 || SCT_LEN(data)<len+12) { 00159 if(doLog) PRINTF(L_SYS_ECM,"bad ECM length"); 00160 return false; 00161 } 00162 int prov=data[8]; 00163 cPlainKey *pk; 00164 unsigned char ECM_IV[16]; 00165 if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_IV,0),16))) { 00166 if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x IV key",ecm->caId,prov); 00167 return false; 00168 } 00169 pk->Get(ECM_IV); 00170 00171 unsigned char ECM_Seed[16]; 00172 if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_SEED,0),16))) { 00173 if(doLog) PRINTF(L_SYS_KEY,"missing %04x %02x ECM key",ecm->caId,prov); 00174 return false; 00175 } 00176 pk->Get(ECM_Seed); 00177 00178 cKeySnoop ks(this,'I',ecm->caId,KEYSET(prov,TYPE_OP,data[9])); 00179 unsigned char key[16]; 00180 if(!(pk=keys.FindKey('I',ecm->caId,KEYSET(prov,TYPE_OP,data[9]),16))) return false; 00181 pk->Get(key); 00182 PrepareSeed(ECM_Seed,key); 00183 00184 data+=12; 00185 Decrypt(data,ECM_IV,ECM_Seed,len); 00186 int i=(data[0]&7)+1; 00187 NanoDecrypt(data,i,len-8,key,ECM_IV); 00188 if(CalculateHash(ECM_Seed,ECM_IV,data-6,len+6)) { 00189 HEXDUMP(L_SYS_RAWECM,data-12,len+12,"Irdeto2 RAWECM"); 00190 while(i<len-8) { 00191 int l=NANOLEN(data[i+1]); 00192 switch(data[i]) { 00193 case 0x78: 00194 memcpy(cw,&data[i+4],16); 00195 ks.OK(pk); 00196 return true; 00197 } 00198 i+=l; 00199 } 00200 } 00201 else { 00202 if(doLog) PRINTF(L_SYS_ECM,"hash failed"); 00203 } 00204 return false; 00205 } 00206 00207 void cSystemIrd2::ProcessEMM(int pid, int caid, const unsigned char *data) 00208 { 00209 int prov=0; //XXX how to get provider here?? 00210 00211 int len=SCT_LEN(data); 00212 unsigned char *emm=AUTOMEM(len); 00213 00214 cPlainKey *pk; 00215 if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_IV,0),16))) { 00216 PRINTF(L_SYS_EMM,"missing %04x %02x IV key",caid,prov); 00217 return; 00218 } 00219 unsigned char EMM_IV[16]; 00220 pk->Get(EMM_IV); 00221 00222 for(int keyno=0; keyno<2; keyno++) { 00223 if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_PMK,keyno),16))) { 00224 PRINTF(L_SYS_EMM,"missing %04x %02x MK%d key",caid,prov,keyno); 00225 continue; 00226 } 00227 unsigned char PMK[16]; 00228 pk->Get(PMK); 00229 00230 if(!(pk=keys.FindKey('I',caid,KEYSET(prov,TYPE_SEED,1),16))) { 00231 PRINTF(L_SYS_EMM,"missing %04x %02x EMM key",caid,prov); 00232 return; 00233 } 00234 unsigned char EMM_Seed[16]; 00235 pk->Get(EMM_Seed); 00236 PrepareSeed(EMM_Seed,PMK); 00237 00238 memcpy(emm,data,len); 00239 Decrypt(&emm[10],EMM_IV,EMM_Seed,len-10); 00240 NanoDecrypt(emm,16,len-8,PMK,EMM_IV); 00241 memmove(emm+6,emm+7,len-7); // removing padding byte 00242 if(CalculateHash(EMM_Seed,EMM_IV,emm+3,len-4)) { 00243 HEXDUMP(L_SYS_RAWEMM,emm,len,"Irdeto2 RAWEMM"); 00244 for(int i=15; i<len-9;) { 00245 int l=NANOLEN(emm[i+1]); 00246 switch(emm[i]) { 00247 case 0x10: 00248 case 0x50: 00249 if(l==0x13 && i+l<=len-9) { 00250 FoundKey(); 00251 if(keys.NewKey('I',caid,KEYSET(prov,TYPE_OP,emm[i+2]>>2),&emm[i+3],16)) NewKey(); 00252 } 00253 break; 00254 } 00255 i+=l; 00256 } 00257 break; 00258 } 00259 else 00260 PRINTF(L_SYS_EMM,"hash failed MK%d",keyno); 00261 } 00262 } 00263 00264 // -- cSystemLinkIrd ----------------------------------------------------------- 00265 00266 class cSystemLinkIrd2 : public cSystemLink { 00267 public: 00268 cSystemLinkIrd2(void); 00269 virtual bool CanHandle(unsigned short SysId); 00270 virtual cSystem *Create(void) { return new cSystemIrd2; } 00271 }; 00272 00273 static cSystemLinkIrd2 staticInit2; 00274 00275 cSystemLinkIrd2::cSystemLinkIrd2(void) 00276 :cSystemLink(SYSTEM_NAME2,SYSTEM_PRI2) 00277 { 00278 Feature.NeedsKeyFile(); 00279 } 00280 00281 bool cSystemLinkIrd2::CanHandle(unsigned short SysId) 00282 { 00283 return SysId!=SYSTEM_IRDETO && (SysId&SYSTEM_MASK)==SYSTEM_IRDETO; 00284 }