|
SASC-NG
DVBSoftCAM
|
Inheritance diagram for cSystemSeca:Public Member Functions | |
| cSystemSeca (void) | |
| virtual | ~cSystemSeca () |
| virtual bool | ProcessECM (const cEcmInfo *ecm, unsigned char *data) |
| virtual void | ProcessEMM (int pid, int caid, const unsigned char *buffer) |
| cSystemSeca::cSystemSeca | ( | void | ) |
Definition at line 1183 of file seca.c.
References cSystem::hasLogger.
:cSystem(SYSTEM_NAME,SYSTEM_PRI), des(secaPC1,secaPC2) { sp=spL=0; emmLenCnt=0; hasLogger=true; }
| cSystemSeca::~cSystemSeca | ( | ) | [virtual] |
| bool cSystemSeca::ProcessECM | ( | const cEcmInfo * | ecm, |
| unsigned char * | data | ||
| ) | [virtual] |
Implements cSystem.
Definition at line 1206 of file seca.c.
References AUTOMEM, cSeca2Prov::CalcSHASignature(), cSeca::CalcSignature(), cSystem::cw, cSeca::Decrypt(), cSeca2Prov::DecryptSE(), cSystem::doLog, cSeca2Prov::DoSigCheck(), cSeca::Encrypt(), exp, cPlainKeys::FindKey(), cPlainKey::Get(), HEXDUMP, i, KEY2INDEX, cParseSeca::KeyNr(), keys, L_SYS_CRYPTO, L_SYS_ECM, L_SYS_KEY, L_SYS_VERBOSE, LDUMP, MBC, mod, cKeySnoop::OK(), cParseSeca::Payload(), PK, cSeca2Prov::PostCW(), cSeca2Prov::PostSSE(), cSeca2Prov::PreCW(), cSeca2Prov::PreSSE(), PRINTF, cEcmInfo::provId, cRSA::RSA(), SCT_LEN, cSeca2Prov::SignatureMod(), cParseSeca::SysMode(), cSeca2Prov::T1(), cSeca::T1_S1, cSeca2Prov::T2(), and cSeca::T2_S1.
{
bool SE=false;
unsigned char *ecm;
const int msgLen=cParseSeca::Payload(data,(const unsigned char **)&ecm);
const int keyNr=cParseSeca::KeyNr(data);
if(keyNr&0x80) {
PRINTF(L_SYS_VERBOSE,"Super Encryption enabled");
SE=true;
if(!GetSeca2Prov(ecmD->provId,sp)) {
if(doLog) PRINTF(L_SYS_ECM,"Seca2 provider %04x not supported",ecmD->provId);
return false;
}
}
HEXDUMP(L_SYS_VERBOSE,data,SCT_LEN(data),"ECM:");
if(ecm[0]==0x10) {
if(msgLen<0x5c) {
if(doLog) PRINTF(L_SYS_ECM,"ECM length too small (%d)",msgLen);
return false;
}
if(SE) {
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before SSE data modification :");
sp->PreSSE(ecm,msgLen-0x5a);
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after SSE data modification :");
}
const int rsaKeynr=(ecm[1]&0x0F)+'0';
cBN exp, mod;
cPlainKey *rsaKey;
if(!(rsaKey=keys.FindKey('S',ecmD->provId,MBC('E',rsaKeynr),-1))) {
if(doLog) PRINTF(L_SYS_KEY,"missing %04x E%c key",ecmD->provId,rsaKeynr);
return false;
}
rsaKey->Get(exp);
if(!(rsaKey=keys.FindKey('S',ecmD->provId,MBC('M',rsaKeynr),-1))) {
if(doLog) PRINTF(L_SYS_KEY,"missing %04x M%c key",ecmD->provId,rsaKeynr);
return false;
}
rsaKey->Get(mod);
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before RSA decrypt :");
if(rsa.RSA(ecm+(msgLen-0x5a),ecm+(msgLen-0x5a),0x5a,exp,mod)!=0x5a) {
PRINTF(L_SYS_CRYPTO,"RSA decrypt failed (ECM)");
return false;
}
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after RSA decrypt :");
if(SE) { // PostSSE needed
const int hashPtr=msgLen-ecm[msgLen-1]-9;
if(hashPtr>=msgLen-9 || ecm[hashPtr]!=0x82) {
PRINTF(L_SYS_CRYPTO,"RSA decrypt failed, signature pointer not found");
return false;
}
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM before SSE result modification :");
sp->PostSSE(ecm,hashPtr);
HEXDUMP(L_SYS_VERBOSE,ecm+(msgLen-0x5a),0x5a,"ECM after SSE result modification :");
}
}
const unsigned char *T1=T1_S1, *T2=T2_S1;
int decrLen=msgLen;
if(SE) {
if(!(T1=sp->T1(KEY2INDEX(keyNr))) ||
!(T2=sp->T2(KEY2INDEX(keyNr)))) return false;
decrLen-=ecm[msgLen-1]; if(decrLen<8) return false;
}
bool key8=!(cParseSeca::SysMode(data)&0x10);
cPlainKey *pk=0;
cKeySnoop ks(this,'S',ecmD->provId,keyNr&0x0F);
unsigned char *buff=AUTOMEM(msgLen);
while((pk=keys.FindKey('S',ecmD->provId,keyNr&0x0F,key8?8:16,pk))) {
memcpy(buff,ecm,msgLen); // if decoding fails we need the original data
unsigned char PK[16], signature[20];
pk->Get(PK);
if(key8) memcpy(&PK[8],&PK[0],8); // duplicate key
if(SE) {
sp->CalcSHASignature(buff,decrLen-8,signature);
LDUMP(L_SYS_VERBOSE,signature,8,"signature before encrypt :");
sp->SignatureMod(signature,PK);
Encrypt(signature,PK,T1,T2);
LDUMP(L_SYS_VERBOSE,signature,8,"signature after encrypt :");
if(sp->DoSigCheck() && memcmp(signature,&buff[decrLen-8],8)) {
PRINTF(L_SYS_VERBOSE,"signature check failed before SE decrypt");
continue;
}
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;
}
| void cSystemSeca::ProcessEMM | ( | int | pid, |
| int | caid, | ||
| const unsigned char * | buffer | ||
| ) | [virtual] |
Reimplemented from cSystem.
Definition at line 1564 of file seca.c.
References AUTOMEM, cSeca2Prov::CalcSHASignature(), cSeca::CalcSignature(), CheckNull(), cmd, cParseSeca::CmdLen(), cSeca::Decrypt(), cSeca2Prov::DecryptSE(), EMM_MAGIC, cSeca::Encrypt(), exp, cPlainKeys::FindKeyNoTrig(), cStructList< T >::First(), cSystem::FoundKey(), cPlainKey::Get(), HexStr(), KEY2INDEX, cParseSeca::KeyNr(), keys, L_SYS_EMM, LBEND, LBPUT, LBSTARTF, MBC3, mod, cSystem::NewKey(), cPlainKeys::NewKey(), cStructList< T >::Next(), cParseSeca::Payload(), PRINTF, cParseSeca::ProvId(), cRSA::RSA(), SA, SID, cParseSeca::SysMode(), cSeca2Prov::T1(), cSeca::T1_S1, cSeca2Prov::T2(), and cSeca::T2_S1.
{
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.FindKeyNoTrig('S',provId,MBC3('E',rsaKeynr,EMM_MAGIC),-1))) return;
pk->Get(exp);
if(!(pk=keys.FindKeyNoTrig('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;
}
}
unsigned char *buff=AUTOMEM(msgLen);
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 signature[20];
memcpy(buff,emm,msgLen); // 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();
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;
}