📄 seca.cpp
字号:
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)) {
dse(printf("system-seca: signature check failed after decrypt\n"))
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)) {
dse(printf("system-seca: crypted CW :"); HexDump(cCW,16))
Decrypt(&cCW[0],PK,T1,T2); Decrypt(&cCW[8],PK,T1,T2);
dse(printf("system-seca: decrypted CW :"); HexDump(cCW,16))
if(SE) {
dse(printf("system-seca: decrypted CW before modification :"); HexDump(cCW,16))
sp->PostCW(cCW);
dse(printf("system-seca: decrypted CW after modification :"); HexDump(cCW,16))
}
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];
dse(printf("0f: initial hashDW:"); HexDump(hashDW,16))
dse(printf("0f: PK:"); HexDump(PK,16))
while(count--) {
unsigned char buffA[8];
swap8_4(hashDW);
memcpy(buffA,hashDW,8);
Decrypt(hashDW,PK,sp->T1(0),sp->T2(0));
dse(printf("0f: hashDW:"); HexDump(hashDW,16))
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);
dse(printf("0f: buffE:"); HexDump(buffE,8))
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);
dse(printf("0f: buffC:"); HexDump(buffC,16))
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;
}
dse(printf("0f: off=%04x\n",off))
memcpy(buffB,buffE,8);
Decrypt(buffB,buffC,&MT[off],&MT[off+256]);
dse(printf("0f: buffB after 1st decr:"); HexDump(buffB,8))
xxor(buffB,8,buffB,buffE);
dse(printf("0f: buffB after xor:"); HexDump(buffB,8))
Decrypt(buffB,PK,T1,T2);
dse(printf("0f: buffB after 2nd decr:"); HexDump(buffB,8))
xxor(hashDW,8,buffA,buffB);
}
for(int i=0; i<8; ++i) {
PK[i] = buffB[i];
PK[i+8] = ~sn8(buffB[i]);
}
dse(printf("0f: hashDW:"); HexDump(hashDW,16))
dse(printf("0f: new PK:"); HexDump(PK,16))
return true;
}
void cSystemSeca::Crypto51Nano(unsigned char *data, const unsigned char *key, const unsigned char crypto, const unsigned char mode)
{
dse(printf("51: "));
switch(crypto) {
case 0: // Xor
dse(printf("XOR crypto selected\n"))
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);
dse(printf("SECA crypto selected: %s\n",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)
dse(printf("DES crypto selected: %s\n",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
dse(printf("Additional crypto selected: %s\n",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) {
dse(printf("51: failed to get permutation table\n"))
return false;
}
unsigned char buffF[8], buffG[8];
switch(pMode) {
case 0x00:
case 0x01:
{
// Permutation 1
Permute(buffF,PermData,PT->P1);
dse(printf("51: buffF:"); HexDump(buffF,8))
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);
dse(printf("51: buffG:"); HexDump(buffG,8))
// 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];
dse(printf("51: permuted hashDW:"); HexDump(buff1,20))
for(int i=0; i<20; i++)
buff1[i+24]=buff1[i+44]=buff1[i+68]=buff1[i+88]=buff1[i+108]=buff1[i];
dse(printf("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;
dse(printf(" %02x",t))
}
dse(printf("\n"))
dse(printf("51: buff1:"); HexDump(buff1,128))
dse(printf("51: buff2:"); HexDump(buff2,64))
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;
}
dse(printf("51: buff1 rsa prepped:"); HexDump(buff1,128))
// RSA decrypt
{
cBN exp, mod;
cPlainKey *pk;
if(!(pk=keys.FindKey('S',provId,MBC3('E','9',N51_MAGIC),-1))) {
if(doLog) d(printf("system-seca: missing %04x N51 E9 key\n",provId))
return false;
}
pk->Get(exp);
if(!(pk=keys.FindKey('S',provId,MBC3('M','9',N51_MAGIC),-1))) {
if(doLog) d(printf("system-seca: missing %04x N51 M9 key\n",provId))
return false;
}
pk->Get(mod);
if(rsa.RSA(buff1,buff1,128,exp,mod)<9) return false;
dse(printf("51: buff1 rsa decrypted:"); HexDump(buff1,128))
}
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;
}
dse(printf("51: buff1 after sumalgo:"); HexDump(buff1,9))
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:
dse(printf("51: data incorrect or proccessing not needed\n"))
return false;
}
dse(printf("51: cryptokey:"); HexDump(buffG,8))
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);
dse(printf("51: cryptokey:"); HexDump(hashDW,8))
Crypto51Nano(CW,hashDW,(PermData[1]>>4)&0x03,PermData[0]&0x40);
dse(printf("51: new encrypted CW:"); HexDump(CW,16))
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)
dl(printf("system-seca: length of EMM does not match (%02x <> 55/63)%s\n",msgLen,emmLenCnt==5 ? " ....":""))
return;
}
ds(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;
}
}
#ifdef DEBUG_LOG
bool first=true;
#endif
for(cSecaCardInfo *ci=Scards.First(); ci; ci=Scards.Next(ci)) {
if(ci->MatchEMM(buffer) || (CheckNull(ci->sa,sizeof(ci->sa)) && ci->MatchID(buffer))) {
#ifdef DEBUG_LOG
char str[20],str2[20],str3[20];
if(first) {
printf("\rID %s SA %s",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3));
first=false;
}
#endif
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[256], 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],sizeof(signature))) 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;
}
}
if(sigOk) {
dl(printf(" - OK (CI ID %s SA %s KEY01 %s)",HexStr(str,ci->provId,2),HexStr(str2,ci->sa,3),HexStr(str3,ci->key,8)))
#ifdef DEBUG_LOG_FILE
FILE *f=LogStart();
if(f) {
char str[64],str2[20],str3[20];
fprintf(f,"ID %s SA %s - OK ",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3));
fprintf(f," with CI ID %s SA %s KEY01 %s\n",HexStr(str,ci->provId,2),HexStr(str2,ci->sa,3),HexStr(str3,ci->key,8));
fprintf(f," cmds:");
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;
}
fprintf(f," 0x%02x/%d",cmd,len);
}
fprintf(f,"\n");
for(int i=0 ; i<(decrLen+2) ; i+=16)
fprintf(f," %02x %s\n",i,HexStr(str,&buff[i],i+16>decrLen?decrLen-i:16));
LogEnd(f);
}
#endif
for(unsigned int i=0 ; i<numKeys ; i++) {
Decrypt(key[i],MK,T1,T2);
dl(printf(" KEY %02x %s",keyN[i],HexStr(str,key[i],8)))
cSoftCAM::FoundKey();
if(keys.NewKey('S',provId,keyN[i],key[i],8)) {
cSoftCAM::NewKey();
#ifdef DEBUG_LOG_FILE
FILE *f=LogStart();
if(f) {
char str[20];
fprintf(f,"New key %02x %s\n",keyN[i],HexStr(str,key[i],8));
LogEnd(f);
}
#endif
}
}
cSoftCAM::Save();
dl(printf("\n"))
break;
}
else if(!CheckNull(ci->sa,sizeof(ci->sa))) {
#ifdef DEBUG_LOG
printf(" - FAIL\n");
first=true;
#endif
#ifdef DEBUG_LOG_FILE
FILE *f=LogStart();
if(f) {
char str[20],str2[20],str3[20];
fprintf(f,"ID %s SA %s - FAIL",HexStr(str,SID(buffer),2),HexStr(str2,SA(buffer),3));
fprintf(f," with CI ID %s SA %s KEY01 %s\n",HexStr(str,ci->provId,2),HexStr(str2,ci->sa,3),HexStr(str3,ci->key,8));
LogEnd(f);
}
#endif
}
dl(fflush(stdout))
}
}
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 + -