📄 seca.c
字号:
} HEXDUMP(L_SYS_VERBOSE,buff+2,msgLen-2,"ECM before SE decrypt :"); if(!sp->DecryptSE(buff+2,PK,msgLen-2,8,T1,T2)) { PRINTF(L_SYS_VERBOSE,"SE decrypt failed"); continue; } HEXDUMP(L_SYS_VERBOSE,buff+2,msgLen-2,"ECM after SE decrypt :"); } else { CalcSignature(buff,decrLen-8,signature,PK,T1,T2); } unsigned char hashDW[28]; // actually 16 bytes used for processing, but SHA needs more unsigned char *cCW=0; const unsigned char *nano51Data=0; int nr0F=0; for(int i=0 ; i<decrLen; ) { int param=buff[i++]; int extra=(param >> 4) & 0x0f; switch(extra) { case 0x0d: extra=0x10; break; case 0x0e: extra=0x18; break; case 0x0f: extra=0x20; break; } switch(param) { case 0x0f: if(SE) nr0F++; break; case 0x51: if(SE) nano51Data=&buff[i]; break; case 0xd1: cCW=&buff[i]; if(SE) { sp->CalcSHASignature(buff,i,hashDW,false); memcpy(&hashDW[20],hashDW,8); Decrypt(&hashDW[20],PK,sp->T1(0),sp->T2(0)); sp->CalcSHASignature(hashDW,28,hashDW,false); } break; case 0x82: if((!SE || sp->DoSigCheck()) && memcmp(&buff[i],signature,8)) { PRINTF(L_SYS_VERBOSE,"signature check failed after decrypt"); cCW=0; i=decrLen; } break; } i+=extra; } if(cCW) { if(!nr0F || Process0FNano(nr0F,hashDW,PK,T1,T2)) { if(SE) sp->PreCW(cCW); if(!nano51Data || Process51Nano(cCW,nano51Data,hashDW,T1,T2,ecmD->provId)) { LDUMP(L_SYS_VERBOSE,cCW,16,"crypted CW :"); Decrypt(&cCW[0],PK,T1,T2); Decrypt(&cCW[8],PK,T1,T2); LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW :"); if(SE) { LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW before modification :"); sp->PostCW(cCW); LDUMP(L_SYS_VERBOSE,cCW,16,"decrypted CW after modification :"); } memcpy(cw,cCW,16); ks.OK(pk); return true; } } } } return false;}bool cSystemSeca::Process0FNano(int count, unsigned char *hashDW, unsigned char *PK, const unsigned char *T1, const unsigned char *T2){ const unsigned char *MT=sp->MT(); unsigned char buffB[8]; LDUMP(L_SYS_VERBOSE,hashDW,16,"0f: initial hashDW:"); LDUMP(L_SYS_VERBOSE,PK,16,"0f: PK:"); while(count--) { unsigned char buffA[8]; swap8_4(hashDW); memcpy(buffA,hashDW,8); Decrypt(hashDW,PK,sp->T1(0),sp->T2(0)); LDUMP(L_SYS_VERBOSE,hashDW,16,"0f: hashDW:"); unsigned char buffE[8]; int off=WORD(hashDW,0,0x3FFF); xxor(buffE,8,&MT[off],&MT[0x3FFF-off]); xxor(buffE,8,&MT[( ((buffE[0] ^ hashDW[6])<<8) + buffE[7] ^ hashDW[7] )&0x3FFF],buffE); LDUMP(L_SYS_VERBOSE,buffE,8,"0f: buffE:"); unsigned char buffC[16]; off=WORD(hashDW,2,0x3FFF); xxor(buffC,16,&MT[off],&MT[0x3FFF-off]); xxor(buffC,16,&MT[( ((hashDW[6] ^ buffC[0])<<8) + (hashDW[7] ^ buffC[15]) )&0x3FFF],buffC); LDUMP(L_SYS_VERBOSE,buffC,16,"0f: buffC:"); off=WORD(hashDW,4,0x3FFF); for(int i=0; i<16; ++i) off=WORD(MT,off,0x3FFF); if(off+512 >= sp->MTSize()) { printf("BUG!!!: error: masking table overflow\n"); return false; } PRINTF(L_SYS_VERBOSE,"0f: off=%04x",off); memcpy(buffB,buffE,8); Decrypt(buffB,buffC,&MT[off],&MT[off+256]); LDUMP(L_SYS_VERBOSE,buffB,8,"0f: buffB after 1st decr:"); xxor(buffB,8,buffB,buffE); LDUMP(L_SYS_VERBOSE,buffB,8,"0f: buffB after xor:"); Decrypt(buffB,PK,T1,T2); LDUMP(L_SYS_VERBOSE,buffB,8,"0f: buffB after 2nd decr:"); xxor(hashDW,8,buffA,buffB); } for(int i=0; i<8; ++i) { PK[i] = buffB[i]; PK[i+8] = ~sn8(buffB[i]); } LDUMP(L_SYS_VERBOSE,hashDW,16,"0f: hashDW:"); LDUMP(L_SYS_VERBOSE,PK,16,"0f: new PK:"); return true;}void cSystemSeca::Crypto51Nano(unsigned char *data, const unsigned char *key, const unsigned char crypto, const unsigned char mode){ switch(crypto) { case 0: // Xor PRINTF(L_SYS_VERBOSE,"51: XOR crypto selected"); xxor(data+0,8,key,data+0); xxor(data+8,8,key,data+8); break; case 1: // Seca crypto, with 9x table, always! { unsigned char PK[16]; const unsigned char *T1 = sp->T1(0); const unsigned char *T2 = sp->T2(0); memcpy(PK+0,key,8); memcpy(PK+8,key,8); PRINTF(L_SYS_VERBOSE,"51: SECA crypto selected: %s",mode?"decrypt":"encrypt"); if(mode) { Decrypt(data,PK,T1,T2); Decrypt(data+8,PK,T1,T2); } else { Encrypt(data,PK,T1,T2); Encrypt(data+8,PK,T1,T2); } break; } case 2: // DES crypto (Modified PC1,PC2) PRINTF(L_SYS_VERBOSE,"51: DES crypto selected: %s",mode?"decrypt":"encrypt"); if(mode) { des.Des(data,key,SECA_DES_DECR); des.Des(data+8,key,SECA_DES_DECR); } else { des.Des(data,key,SECA_DES_ENCR); des.Des(data+8,key,SECA_DES_ENCR); } break; case 3: // Additional Algo PRINTF(L_SYS_VERBOSE,"51: Additional crypto selected: %s",mode?"decrypt":"encrypt"); AdditionalAlgo(data,key,mode); AdditionalAlgo(data+8,key,mode); break; }}bool cSystemSeca::Process51Nano(unsigned char *CW, const unsigned char *PermData, const unsigned char *hashDW, const unsigned char *T1, const unsigned char *T2, int provId){ const int pMode=(PermData[0]&0x3F)-1; const struct Perm *PT=sp->P(pMode); if(!PT) { PRINTF(L_SYS_VERBOSE,"51: failed to get permutation table"); return false; } unsigned char buffF[8], buffG[8]; switch(pMode) { case 0x00: case 0x01: { // Permutation 1 Permute(buffF,PermData,PT->P1); LDUMP(L_SYS_VERBOSE,buffF,8,"51: buffF:"); xxor(buffG,8,buffF,hashDW); const int addAlgoMode=(PermData[0]&1)^1; for(int i=(PermData[1]&0x0f); i>0; i--) AdditionalAlgo(buffG,hashDW+8,addAlgoMode); // Permutation 2 Permute(buffF,PermData,PT->P2); xxor(buffG,8,buffF,buffG); LDUMP(L_SYS_VERBOSE,buffG,8,"51: buffG:"); // Permutation 3 Permute(buffF,PermData,PT->P3); xxor(buffG,8,buffF,buffG); // Permutation 4 Permute(buffF,PermData,PT->P4); xxor(buffG,8,buffF,buffG); break; } case 0x08: { unsigned char buff1[128], buff2[64], buff3[9]; // prepare buffers for rsa data for(int i=0; i<20; i++) buff1[i]=buff2[i]=buff2[i+20]=buff2[i+40]=hashDW[i]; memcpy(buff3,PermData+2,3); for(int i=0; i<8; i++) buff1[i] = buff3[PT->P1[i]-2] ^= buff1[i]; LDUMP(L_SYS_VERBOSE,buff1,20,"51: permuted hashDW:"); for(int i=0; i<20; i++) buff1[i+24]=buff1[i+44]=buff1[i+68]=buff1[i+88]=buff1[i+108]=buff1[i]; LBSTARTF(L_SYS_VERBOSE); LBPUT("51: nano51Data:"); for(int i=0; i<4; i++) { unsigned char t=PermData[PT->P3[i]]; if(PT->P3[i]==1) t&=0x0F; buff1[i+20]=buff1[i+64]=buff2[i+60]=t; LBPUT(" %02x",t); } LBEND(); HEXDUMP(L_SYS_VERBOSE,buff1,128,"51: buff1:"); HEXDUMP(L_SYS_VERBOSE,buff2,64,"51: buff2:"); memcpy(buff3,buff1,9); for(int j=0; j<64; j++) { // XOR even with buff2, odd with 0xFF buff1[ j*2 ] ^= buff2[j]; buff1[(j*2)+1] ^= 0xFF; } HEXDUMP(L_SYS_VERBOSE,buff1,128,"51: buff1 rsa prepped:"); // RSA decrypt { cBN exp, mod; cPlainKey *pk; if(!(pk=keys.FindKey('S',provId,MBC3('E','9',N51_MAGIC),-1))) { if(doLog) PRINTF(L_SYS_KEY,"missing %04x N51 E9 key",provId); return false; } pk->Get(exp); if(!(pk=keys.FindKey('S',provId,MBC3('M','9',N51_MAGIC),-1))) { if(doLog) PRINTF(L_SYS_KEY,"missing %04x N51 M9 key",provId); return false; } pk->Get(mod); if(rsa.RSA(buff1,buff1,128,exp,mod)<9) return false; HEXDUMP(L_SYS_VERBOSE,buff1,128,"51: buff1 rsa decrypted:"); } unsigned int sum=0; for(int j=0; j<9; j++) { unsigned int nextSum=(buff1[j]&0x80) ? 1:0; buff1[j]=(sum+2*buff1[j])^buff3[j]; sum=nextSum; } LDUMP(L_SYS_VERBOSE,buff1,9,"51: buff1 after sumalgo:"); memcpy(buffG,buff1,8); memcpy(buff3,PermData+2,3); for(int i=0; i<8; i++) buffG[i] = buff3[PT->P2[i]-2] ^= buffG[i]; break; } default: PRINTF(L_SYS_VERBOSE,"51: data incorrect or proccessing not needed"); return false; } LDUMP(L_SYS_VERBOSE,buffG,8,"51: cryptokey:"); Crypto51Nano(CW,buffG,(PermData[1]>>6)&3,PermData[0]&0x80); // Final Permutation Permute(buffF,PermData,sp->FP()); xxor(CW+0,8,CW+0,buffF); xxor(CW+8,8,CW+8,buffF); LDUMP(L_SYS_VERBOSE,hashDW,8,"51: cryptokey:"); Crypto51Nano(CW,hashDW,(PermData[1]>>4)&0x03,PermData[0]&0x40); LDUMP(L_SYS_VERBOSE,CW,16,"51: new encrypted CW:"); return true;}void cSystemSeca::Permute(unsigned char *data, const unsigned char *pdata, const unsigned char *P){ for(int i=7; i>=0; i--) data[i] = P[i] ? pdata[P[i]] : 0;}void cSystemSeca::ProcessEMM(int pid, int caid, unsigned char *buffer){ if(buffer[0]!=0x84) return; // we only support shared updates int msgLen=cParseSeca::CmdLen(buffer); if(msgLen!=0x55 && msgLen!=0x63) { if(++emmLenCnt<=5) PRINTF(L_SYS_EMM,"length of EMM does not match (%02x <> 55/63)%s",msgLen,emmLenCnt==5 ? " ....":""); return; } emmLenCnt=0; unsigned char *emm; msgLen=cParseSeca::Payload(buffer,(const unsigned char **)&emm); int provId=cParseSeca::ProvId(buffer); bool SE=false; const unsigned char *T1=T1_S1, *T2=T2_S1; int decrLen=msgLen; if(emm[0]==0x10) { // de-SSE const int rsaKeynr = emm[1]+'0'; cPlainKey *pk; cBN exp, mod; if(!(pk=keys.FindKey('S',provId,MBC3('E',rsaKeynr,EMM_MAGIC),-1))) return; pk->Get(exp); if(!(pk=keys.FindKey('S',provId,MBC3('M',rsaKeynr,EMM_MAGIC),-1))) return; pk->Get(mod); if(rsa.RSA(emm+2,emm+2,msgLen-2,exp,mod)!=msgLen-2) return; const int keyNr=cParseSeca::KeyNr(buffer); if(keyNr&0x80) { SE=true; decrLen-=emm[msgLen-1]; if(!GetSeca2Prov(provId,spL) || !(T1=spL->T1(KEY2INDEX(keyNr))) || !(T2=spL->T2(KEY2INDEX(keyNr))) || decrLen<8) return; } } for(cSecaCardInfo *ci=Scards.First(); ci; ci=Scards.Next(ci)) { if(ci->MatchEMM(buffer) || (CheckNull(ci->sa,sizeof(ci->sa)) && ci->MatchID(buffer))) { unsigned char MK[16]; if(cParseSeca::SysMode(buffer)&0x10) { if(ci->KeySize()!=16) continue; // don't bother memcpy(&MK[0],ci->key,16); } else { memcpy(&MK[0],ci->key,8); memcpy(&MK[8],ci->key,8); } unsigned char buff[msgLen], signature[20]; memcpy(buff,emm,sizeof(buff)); // if decoding fails we need the original de-sse'd data if(!SE) { for(int i=0 ; i<=64 && i<msgLen-8; i+=8) Decrypt(&buff[i],MK,T1,T2); CalcSignature(buff,decrLen-8,signature,MK,T1,T2); } else { spL->CalcSHASignature(buff,decrLen-8,signature); Encrypt(signature,MK,T1,T2); if(memcmp(signature,&buff[decrLen-8],8) || !spL->DecryptSE(buff+2,MK,msgLen-2,0,T1,T2)) continue; } unsigned char keyN[4], *key[4]; int pos, len; unsigned int numKeys=0; bool sigOk=false; for(pos=0 ; pos<decrLen ; pos+=len) { int cmd=buff[pos++]; len=(cmd>>4)&0x0f; switch(len) { case 0x0b: len=0x0e; break; case 0x0d: len=0x10; break; case 0x0e: len=0x18; break; case 0x0f: len=0x20; break; } switch(cmd) { case 0x82: // signature if(!memcmp(signature,&buff[pos],8)) sigOk=true; pos=decrLen; break; case 0x90: // new primary key if(numKeys<sizeof(keyN)) { keyN[numKeys]=buff[pos] & 0x0f; key[numKeys]=&buff[pos+1]; numKeys++; } break; } } char str[20],str2[20],str3[20]; if(sigOk) { LBSTARTF(L_SYS_EMM); LBPUT("ID %s SA %s",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3)); LBPUT(" - OK (CI ID %s SA %s KEY01 %s)",HexStr(str,ci->provId,2),HexStr(str2,ci->sa,3),HexStr(str3,ci->key,8)); for(unsigned int i=0 ; i<numKeys ; i++) { Decrypt(key[i],MK,T1,T2); LBPUT(" KEY %02x %s",keyN[i],HexStr(str,key[i],8)); FoundKey(); if(keys.NewKey('S',provId,keyN[i],key[i],8)) NewKey(); } LBEND(); cLoaders::SaveCache(); break; } else if(!CheckNull(ci->sa,sizeof(ci->sa))) PRINTF(L_SYS_EMM,"ID %s SA %s - FAIL",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3)); } } return;}// -- cSystemLinkSeca ----------------------------------------------------------class cSystemLinkSeca : public cSystemLink {public: cSystemLinkSeca(void); virtual bool CanHandle(unsigned short SysId); virtual cSystem *Create(void) { return new cSystemSeca; } virtual bool Init(const char *cfgdir); };static cSystemLinkSeca staticInit;cSystemLinkSeca::cSystemLinkSeca(void):cSystemLink(SYSTEM_NAME,SYSTEM_PRI){ Feature.NeedsKeyFile();}bool cSystemLinkSeca::CanHandle(unsigned short SysId){ SysId&=SYSTEM_MASK; return SYSTEM_CAN_HANDLE(SysId);}bool cSystemLinkSeca::Init(const char *cfgdir){ Scards.Load(cfgdir,SYSTEM_NAME,"Seca.KID"); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -