static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp; char tmp_dbg[256]; struct dre_data *csystem_data = reader->csystem_data; if(reader->caid == 0x4ae0) { uchar ecmcmd41[] = { 0x41, 0x58, 0x1f, 0x00, //fixed part, dont change 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, //0x01 - 0x08: next key 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, //0x11 - 0x18: current key 0x3b, 0x59, 0x11 //0x3b = keynumber, can be a value 56 ;; 0x59 number of package = 58+1 - Pay Package ;; 0x11 = provider }; ecmcmd41[22] = csystem_data->provider; memcpy(ecmcmd41 + 4, er->ecm + 8, 16); ecmcmd41[20] = er->ecm[6]; //keynumber ecmcmd41[21] = 0x58 + er->ecm[25]; //package number rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 8, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 24, er->ecm[2] + 2 - 24, tmp_dbg, sizeof(tmp_dbg))); if((dre_cmd(ecmcmd41))) //ecm request { if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } //exit if response is not 90 00 memcpy(ea->cw, cta_res + 11, 8); memcpy(ea->cw + 8, cta_res + 3, 8); return OK; } } else { uchar ecmcmd51[] = { 0x51, 0x02, 0x56, 0x05, 0x00, 0x4A, 0xE3, //fixed header? 0x9C, 0xDA, //first three nibbles count up, fourth nibble counts down; all ECMs sent twice 0xC1, 0x71, 0x21, 0x06, 0xF0, 0x14, 0xA7, 0x0E, //next key? 0x89, 0xDA, 0xC9, 0xD7, 0xFD, 0xB9, 0x06, 0xFD, //current key? 0xD5, 0x1E, 0x2A, 0xA3, 0xB5, 0xA0, 0x82, 0x11, //key or signature? 0x14 //provider }; memcpy(ecmcmd51 + 1, er->ecm + 5, 0x21); rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg))); ecmcmd51[33] = csystem_data->provider; //no part of sig if((dre_cmd(ecmcmd51))) //ecm request { if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } //exit if response is not 90 00 DREover(er->ecm, cta_res + 3); memcpy(ea->cw, cta_res + 11, 8); memcpy(ea->cw + 8, cta_res + 3, 8); return OK; } } return ERROR; }
static int32_t dre_set_provider_info(struct s_reader *reader) { def_resp; int32_t i; uchar cmd59[] = { 0x59, 0x14 }; // subscriptions uchar cmd5b[] = { 0x5b, 0x00, 0x14 }; //validity dates struct dre_data *csystem_data = reader->csystem_data; cs_clear_entitlement(reader); cmd59[1] = csystem_data->provider; if((dre_cmd(cmd59))) //ask subscription packages, returns error on 0x11 card { uchar pbm[32]; char tmp_dbg[65]; memcpy(pbm, cta_res + 3, cta_lr - 6); rdr_log_dbg(reader, D_READER, "pbm: %s", cs_hexdump(0, pbm, 32, tmp_dbg, sizeof(tmp_dbg))); if(pbm[0] == 0xff) { rdr_log(reader, "no active packages"); } else for(i = 0; i < 32; i++) if(pbm[i] != 0xff) { cmd5b[1] = i; cmd5b[2] = csystem_data->provider; dre_cmd(cmd5b); //ask for validity dates time_t start; time_t end; start = (cta_res[3] << 24) | (cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]; end = (cta_res[7] << 24) | (cta_res[8] << 16) | (cta_res[9] << 8) | cta_res[10]; struct tm temp; localtime_r(&start, &temp); int32_t startyear = temp.tm_year + 1900; int32_t startmonth = temp.tm_mon + 1; int32_t startday = temp.tm_mday; localtime_r(&end, &temp); int32_t endyear = temp.tm_year + 1900; int32_t endmonth = temp.tm_mon + 1; int32_t endday = temp.tm_mday; rdr_log(reader, "active package %i valid from %04i/%02i/%02i to %04i/%02i/%02i", i, startyear, startmonth, startday, endyear, endmonth, endday); cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, 0, start, end, 1, 1); } } return OK; }
static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp; uint16_t overcryptId; uint8_t tmp[16]; char tmp_dbg[256]; struct dre_data *csystem_data = reader->csystem_data; if(reader->caid == 0x4ae0) { uchar ecmcmd41[] = { 0x41, 0x58, 0x1f, 0x00, //fixed part, dont change 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, //0x01 - 0x08: next key 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, //0x11 - 0x18: current key 0x3b, 0x59, 0x11 //0x3b = keynumber, can be a value 56 ;; 0x59 number of package = 58+1 - Pay Package ;; 0x11 = provider }; ecmcmd41[22] = csystem_data->provider; memcpy(ecmcmd41 + 4, er->ecm + 8, 16); ecmcmd41[20] = er->ecm[6]; //keynumber ecmcmd41[21] = 0x58 + er->ecm[25]; //package number rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 8, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 24, er->ecm[2] + 2 - 24, tmp_dbg, sizeof(tmp_dbg))); if((dre_cmd(ecmcmd41))) //ecm request { if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } //exit if response is not 90 00 memcpy(ea->cw, cta_res + 11, 8); memcpy(ea->cw + 8, cta_res + 3, 8); return OK; } } else if(reader->caid == 0x4ae1) { if(csystem_data->provider == 0x11 || csystem_data->provider == 0x14) { uchar ecmcmd51[] = { 0x51, 0x02, 0x56, 0x05, 0x00, 0x4A, 0xE3, //fixed header? 0x9C, 0xDA, //first three nibbles count up, fourth nibble counts down; all ECMs sent twice 0xC1, 0x71, 0x21, 0x06, 0xF0, 0x14, 0xA7, 0x0E, //next key? 0x89, 0xDA, 0xC9, 0xD7, 0xFD, 0xB9, 0x06, 0xFD, //current key? 0xD5, 0x1E, 0x2A, 0xA3, 0xB5, 0xA0, 0x82, 0x11, //key or signature? 0x14 //provider }; memcpy(ecmcmd51 + 1, er->ecm + 5, 0x21); rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg))); ecmcmd51[33] = csystem_data->provider; //no part of sig if((dre_cmd(ecmcmd51))) //ecm request { if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } //exit if response is not 90 00 if(er->ecm[2] >= 46 && er->ecm[43] == 1 && csystem_data->provider == 0x11) { memcpy(tmp, cta_res + 11, 8); memcpy(tmp + 8, cta_res + 3, 8); overcryptId = b2i(2, &er->ecm[44]); rdr_log_dbg(reader, D_READER, "ICG ID: %04X", overcryptId); Drecrypt2OverCW(overcryptId,tmp); if(isValidDCW(tmp)) { memcpy(ea->cw, tmp, 16); return OK; } return ERROR; } DREover(reader, er->ecm, cta_res + 3); if(isValidDCW(cta_res + 3)) { memcpy(ea->cw, cta_res + 11, 8); memcpy(ea->cw + 8, cta_res + 3, 8); return OK; } } } else if((csystem_data->provider == 0x02 || csystem_data->provider == 0x03) && er->ecm[3] == 3) { // DRE 3 if (er->ecm[4] == 2) { memcpy( ea->cw , &er->ecm[42], 8); memcpy(&ea->cw[8], &er->ecm[34], 8); return OK; } uchar cmdlen; uchar crypted = er->ecm[8] & 1; uchar cryptkey = (er->ecm[8] & 6) >> 1; if (crypted == 0) { cmdlen = 50; } else { cmdlen = 57; } uchar ecmcmd[cmdlen]; memcpy(ecmcmd, &er->ecm[17], cmdlen-1); ecmcmd[cmdlen-1] = csystem_data->provider; dre_cmd_c(ecmcmd, crypted, cryptkey); if(cta_res[2] == 0xD2 && isValidDCW(cta_res + 3)) { memcpy(ea->cw, cta_res+11, 8); memcpy(ea->cw+8, cta_res+3, 8); return OK; } } } else if(reader->caid == 0x2710 && er->ecm[3] == 4)
/* static void cmd_test(struct s_reader *reader) { def_resp; int i; uchar drecmd[] = { 0x00, 0x02 }; char tmp[64]; for(i = 0; i <= 0xFF; i++) { if(i == 0x45) continue; drecmd[0] = i; dre_cmd(drecmd); if(cta_res[2] == 0xE2) { if(cta_res[3] != 0xE3) rdr_log(reader, "cmd %02X error %02X",i ,cta_res[3]); } else { rdr_log(reader, "cmd %02X answer %s",i ,cs_hexdump(0, cta_res, cta_res[1]+2, tmp, sizeof(tmp))); } } uchar drecmd[64]; //memset(drecmd, 0, 64); //drecmd[0] = 0x71; for(i = 2; i <= 64; i++) { memset(drecmd, 0, 64); drecmd[i-1] = 0x02; drecmd[0] = 0x71; dre_script(drecmd, i, 0, 0, 0); if(cta_res[2] == 0xE2) { if((cta_res[3] != 0xE2) & (cta_res[3] != 0xED)) rdr_log(reader, "Len %02X error %02X",i ,cta_res[3]); if((cta_res[3] & 0xF0) != 0xE0) rdr_log(reader, "Len %02X answer %s",i ,cs_hexdump(0, cta_res, cta_res[1]+2, tmp, sizeof(tmp))); } else { rdr_log(reader, "Len %02X answer %s",i ,cs_hexdump(0, cta_res, cta_res[1]+2, tmp, sizeof(tmp))); } } } */ static int32_t dre_card_init(struct s_reader *reader, ATR *newatr) { get_atr; def_resp; uchar ua[] = { 0x43, 0x15 }; // get serial number (UA) uchar providers[] = { 0x49, 0x15 }; // get providers uchar cmd56[] = { 0x56, 0x00 }; int32_t i; char *card; char tmp[9]; if((atr[0] != 0x3b) || (atr[1] != 0x15) || (atr[2] != 0x11) || (atr[3] != 0x12) || ( ((atr[4] != 0x01) || (atr[5] != 0x01)) && ((atr[4] != 0xca) || (atr[5] != 0x07)) && ((atr[4] != 0xcb) || (atr[5] != 0x07)) && ((atr[4] != 0xcc) || (atr[5] != 0x07)) && ((atr[4] != 0xcd) || (atr[5] != 0x07)) )) { return ERROR; } if(!cs_malloc(&reader->csystem_data, sizeof(struct dre_data))) { return ERROR; } struct dre_data *csystem_data = reader->csystem_data; csystem_data->provider = atr[6]; uchar checksum = xor(atr + 1, 6); if(checksum != atr[7]) { rdr_log(reader, "warning: expected ATR checksum %02x, smartcard reports %02x", checksum, atr[7]); } switch(atr[6]) { case 0: if(!(dre_cmd(cmd56))) { return ERROR; } if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } switch(cta_res[4]) { case 0x02: card = "Tricolor Centr DRE3"; reader->caid = 0x4ae1; break; case 0x03: card = "Tricolor Syberia DRE3"; reader->caid = 0x4ae1; break; case 0x18: case 0x19: card = "Tricolor Centr DRE4"; reader->caid = 0x2710; break; case 0x1A: card = "Tricolor Syberia DRE4"; reader->caid = 0x2710; break; default: return ERROR; } csystem_data->provider = cta_res[4]; providers[0] = 0x83; break; case 0x11: card = "Tricolor Centr DRE2"; reader->caid = 0x4ae1; break; //59 type card = MSP (74 type = ATMEL) case 0x12: card = "Cable TV"; reader->caid = 0x4ae1; //TODO not sure about this one break; case 0x14: card = "Tricolor Syberia DRE2"; reader->caid = 0x4ae1; break; //59 type card case 0x15: card = "Platforma HD / DW old"; reader->caid = 0x4ae1; break; //59 type card default: return ERROR; } memset(reader->prid, 0x00, 8); if(atr[6] > 0) { reader->prid[0][3] = atr[6]; } else { reader->prid[0][3] = csystem_data->provider; } uchar cmd54[] = { 0x54, 0x14 }; // geocode cmd54[1] = csystem_data->provider; uchar geocode = 0; if((dre_cmd(cmd54))) //error would not be fatal, like on 0x11 cards { geocode = cta_res[3]; } providers[1] = csystem_data->provider; if(!(dre_cmd(providers))) { return ERROR; } //fatal error if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; } uchar provname[128]; for(i = 0; ((i < cta_res[2] - 6) && (i < 128)); i++) { provname[i] = cta_res[6 + i]; if(provname[i] == 0x00) { break; } } int32_t major_version = cta_res[3]; int32_t minor_version = cta_res[4]; ua[1] = csystem_data->provider; dre_cmd(ua); //error would not be fatal int32_t hexlength = cta_res[1] - 2; //discard first and last byte, last byte is always checksum, first is answer code if(reader->force_ua) { rdr_log(reader, "WARNING!!!! used UA from force_ua %08X", reader->force_ua); memcpy(cta_res + 3, &reader->force_ua, 4); } reader->hexserial[0] = 0; reader->hexserial[1] = 0; memcpy(reader->hexserial + 2, cta_res + 3, hexlength); int32_t low_dre_id, dre_chksum; uchar buf[32]; if(major_version < 0x3) { low_dre_id = ((cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]) - 48608; dre_chksum = 0; snprintf((char *)buf, sizeof(buf), "%i%i%08i", csystem_data->provider - 16, major_version + 1, low_dre_id); for(i = 0; i < 32; i++) { if(buf[i] == 0x00) { break; } dre_chksum += buf[i] - 48; } if(major_version < 2) { reader->caid = 0x4ae0; card = csystem_data->provider == 0x11 ? "Tricolor Centr DRE1" : "Tricolor Syberia DRE1"; } rdr_log(reader, "type: DRE Crypt, caid: %04X, serial: {%s}, dre id: %i%i%i%08i, geocode %i, card: %s v%i.%i", reader->caid, cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)), dre_chksum, csystem_data->provider - 16, major_version + 1, low_dre_id, geocode, card, major_version, minor_version); } else { low_dre_id = ((cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]); dre_chksum = 0; snprintf((char *)buf, sizeof(buf), "%i%i%08i", csystem_data->provider, major_version, low_dre_id); for(i = 0; i < 32; i++) { if(buf[i] == 0x00) { break; } dre_chksum += buf[i] - 48; } rdr_log(reader, "type: DRE Crypt, caid: %04X, serial: {%s}, dre id: %i%03i%i%08i, geocode %i, card: %s v%i.%i", reader->caid, cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)), dre_chksum, csystem_data->provider, major_version, low_dre_id, geocode, card, major_version, minor_version); } rdr_log(reader, "Provider name:%s.", provname); memset(reader->sa, 0, sizeof(reader->sa)); memcpy(reader->sa[0], reader->hexserial + 2, 1); //copy first byte of unique address also in shared address, because we dont know what it is... rdr_log_sensitive(reader, "SA = %02X%02X%02X%02X, UA = {%s}", reader->sa[0][0], reader->sa[0][1], reader->sa[0][2], reader->sa[0][3], cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp))); reader->nprov = 1; // cmd_test(reader); // exec user script, wicardd format if(reader->userscript != NULL) { uint8_t *usercmd = NULL; int cmd_len; int n; char *tempbuf = malloc(2048); trim2(reader->userscript); FILE *pFile = fopen(reader->userscript, "rt"); if(pFile != NULL) { uchar ignoreProvid = 0; uchar crypted = 0; uchar cryptkey = 0; do { tempbuf[0] = '\0'; if(usercmd != NULL) free(usercmd); if(fgets(tempbuf, 2048, pFile) == NULL) continue; if(strlen(tempbuf) < 10) continue; trim2(tempbuf); ignoreProvid = 0; crypted = 0; cryptkey = 0; if(tempbuf[0] == '8' && tempbuf[1] == '6' && csystem_data->provider == 0x11) ignoreProvid = 1; else if(strncmp(tempbuf ,"REG2" ,4) == 0) { dre_read_ee(reader, &tempbuf[4] ,csystem_data->provider); continue; } else if(strncmp(tempbuf ,"CR" ,2) == 0) { crypted = 1; cryptkey = ((tempbuf[2] - (tempbuf[2] > 0x39 ? 0x37:0x30)) << 4) + ((tempbuf[3] - (tempbuf[3] > 0x39 ? 0x37:0x30)) & 0xF); } else if(tempbuf[0] != '5' && tempbuf[1] != '9') continue; strtoupper(tempbuf); cmd_len = strlen(tempbuf) / 2 - 3 + ignoreProvid - (crypted * 2); usercmd = malloc(cmd_len); for(i=0,n= 4+(crypted * 4);i<cmd_len;i++,n+=2) { usercmd[i] = ((tempbuf[n] - (tempbuf[n] > 0x39 ? 0x37:0x30)) << 4) + ((tempbuf[n+1] - (tempbuf[n+1] > 0x39 ? 0x37:0x30)) & 0xF); } /*if(usercmd[cmd_len-1] != csystem_data->provider && !ignoreProvid) { rdr_log(reader, "Skip script: current provid %02X , script provid %02X", csystem_data->provider, usercmd[cmd_len-1]); continue; } */ rdr_log(reader, "User script: %s", tempbuf); /*ret =*/ rdr_log(reader, "Script %s", (dre_script(usercmd, cmd_len, ignoreProvid, crypted, cryptkey)) ? "done" : "error"); } while(!feof(pFile)); } else { rdr_log(reader, "Can't open script file (%s)", reader->userscript); } //if(usercmd != NULL) free(usercmd); if(tempbuf != NULL) free(tempbuf); } if(csystem_data->provider == 0x11) { memset(reader->prid[1], 0x00, 8); reader->prid[1][3] = 0xFE; reader->nprov = 2; } if(!dre_set_provider_info(reader)) { return ERROR; } //fatal error rdr_log(reader, "ready for requests"); return OK; }
static int32_t dre_set_provider_info(struct s_reader *reader) { def_resp; int32_t i; int subscr_cmd_len = 4; uchar subscr[4];// = { 0x59, 0x14 }; // subscriptions uchar dates[] = { 0x5b, 0x00, 0x14 }; //validity dates uchar subscr_len = 0, n = 0; struct dre_data *csystem_data = reader->csystem_data; cs_clear_entitlement(reader); switch(csystem_data->provider) { case 0x02: case 0x03: subscr[0] = 0x84; subscr[1] = 0; subscr[2] = 0x5F; subscr[3] = csystem_data->provider; dates[0] = 0x85; subscr_len = 0x5F; break; case 0x18: case 0x19: case 0x1A: subscr[0] = 0x94; subscr[1] = 0; subscr[2] = 0x5F; subscr[3] = csystem_data->provider; dates[0] = 0x95; subscr_len = 0x5F; break; default: subscr[0] = 0x59; subscr[1] = csystem_data->provider; subscr_len = 0x20; subscr_cmd_len = 2; } chk_subscr: if((dre_script(subscr, subscr_cmd_len, 0, 0, 0))) //ask subscription packages, returns error on 0x11 card { uchar pbm[subscr_len]; char tmp_dbg[subscr_len*2+1]; memcpy(pbm, cta_res + 3, cta_lr - 6); rdr_log_dbg(reader, D_READER, "pbm: %s", cs_hexdump(0, pbm, subscr_len, tmp_dbg, sizeof(tmp_dbg))); for(i = 0; i < subscr_len; i++) if(pbm[i] != 0xff) { dates[1] = i; dates[2] = csystem_data->provider; dre_cmd(dates); //ask for validity dates time_t start; time_t end; start = (cta_res[3] << 24) | (cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]; end = (cta_res[7] << 24) | (cta_res[8] << 16) | (cta_res[9] << 8) | cta_res[10]; struct tm temp; localtime_r(&start, &temp); int32_t startyear = temp.tm_year + 1900; int32_t startmonth = temp.tm_mon + 1; int32_t startday = temp.tm_mday; localtime_r(&end, &temp); int32_t endyear = temp.tm_year + 1900; int32_t endmonth = temp.tm_mon + 1; int32_t endday = temp.tm_mday; rdr_log(reader, "active package %i valid from %04i/%02i/%02i to %04i/%02i/%02i", i+n, startyear, startmonth, startday, endyear, endmonth, endday); cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, i+n, start, end, 5, 1); } } if(subscr_len == 0x5F) // read second part subscription packages, for DRE3 and DRE4 { subscr[1] = 0x5F; subscr[2] = 0x21; subscr_len = 0x21; n = 0x5F; goto chk_subscr; } return OK; }
static int32_t dre_do_emm (struct s_reader * reader, EMM_PACKET * ep) { def_resp; if (reader->caid == 0x4ae1) { if(ep->type == UNIQUE && ep->emm[39] == 0x3d) { /* For new package activation. */ uchar emmcmd58[26]; emmcmd58[0] = 0x58; memcpy(&emmcmd58[1], &ep->emm[40], 24); emmcmd58[25] = 0x15; if ((dre_cmd (emmcmd58))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; } else { uchar emmcmd52[0x3a]; emmcmd52[0] = 0x52; int32_t i; for (i = 0; i < 2; i++) { memcpy (emmcmd52 + 1, ep->emm + 5 + 32 + i * 56, 56); // check for shared address if(ep->emm[3]!=reader->sa[0][0]) return OK; // ignore, wrong address emmcmd52[0x39] = reader->provider; if ((dre_cmd (emmcmd52))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } else { uchar emmcmd42[] = { 0x42, 0x85, 0x58, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0C, 0xBD, 0x7B, 0x07, 0x04, 0xC8, 0x77, 0x31, 0x95, 0xF2, 0x30, 0xB7, 0xE9, 0xEE, 0x0F, 0x81, 0x39, 0x1C, 0x1F, 0xA9, 0x11, 0x3E, 0xE5, 0x0E, 0x8E, 0x50, 0xA4, 0x31, 0xBB, 0x01, 0x00, 0xD6, 0xAF, 0x69, 0x60, 0x04, 0x70, 0x3A, 0x91, 0x56, 0x58, 0x11 }; int32_t i; switch (ep->type) { case UNIQUE: for (i = 0; i < 2; i++) { memcpy (emmcmd42 + 1, ep->emm + 42 + i*49, 48); emmcmd42[49] = ep->emm[i*49 + 41]; //keynr emmcmd42[50] = 0x58 + ep->emm[40]; //package nr emmcmd42[51] = reader->provider; if ((dre_cmd (emmcmd42))) { if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } break; case SHARED: default: memcpy (emmcmd42 + 1, ep->emm + 6, 48); emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[5]; //keynr /* response: 59 05 A2 02 05 01 5B 90 00 */ if ((dre_cmd (emmcmd42))) { //first emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 memcpy (emmcmd42 + 1, ep->emm + 55, 7); //TODO OR next two lines? /*memcpy (emmcmd42 + 1, ep->emm + 55, 7); //FIXME either I cant count or my EMM log contains errors memcpy (emmcmd42 + 8, ep->emm + 67, 41); */ emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[54]; //keynr if ((dre_cmd (emmcmd42))) { //second emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } } return OK; //success }
static int32_t dre_card_init (struct s_reader * reader, ATR *newatr) { get_atr; def_resp; uchar ua[] = { 0x43, 0x15 }; // get serial number (UA) uchar providers[] = { 0x49, 0x15 }; // get providers int32_t i; char *card; char tmp[9]; if ((atr[0] != 0x3b) || (atr[1] != 0x15) || (atr[2] != 0x11) || (atr[3] != 0x12) || ( ((atr[4] != 0xca) || (atr[5] != 0x07)) && ((atr[4] != 0x01) || (atr[5] != 0x01)) )) return ERROR; reader->provider = atr[6]; uchar checksum = xor (atr + 1, 6); if (checksum != atr[7]) rdr_log(reader, "warning: expected ATR checksum %02x, smartcard reports %02x", checksum, atr[7]); switch (atr[6]) { case 0x11: card = "Tricolor Centr"; reader->caid = 0x4ae1; break; //59 type card = MSP (74 type = ATMEL) case 0x12: card = "Cable TV"; reader->caid = 0x4ae1; //TODO not sure about this one break; case 0x14: card = "Tricolor Syberia / Platforma HD new"; reader->caid = 0x4ae1; break; //59 type card case 0x15: card = "Platforma HD / DW old"; reader->caid = 0x4ae1; break; //59 type card default: card = "Unknown"; reader->caid = 0x4ae1; break; } memset (reader->prid, 0x00, 8); static const uchar cmd30[] = { 0x30, 0x81, 0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x06, 0x87, 0x08, 0x09, 0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x00 }; dre_cmd (cmd30); //unknown command, generates error on card 0x11 and 0x14 /* response: 59 03 E2 E3 FE 48 */ uchar cmd54[] = { 0x54, 0x14 }; // geocode cmd54[1] = reader->provider; uchar geocode = 0; if ((dre_cmd (cmd54))) //error would not be fatal, like on 0x11 cards geocode = cta_res[3]; providers[1] = reader->provider; if (!(dre_cmd (providers))) return ERROR; //fatal error if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; uchar provname[128]; for (i = 0; ((i < cta_res[2] - 6) && (i < 128)); i++) { provname[i] = cta_res[6 + i]; if (provname[i] == 0x00) break; } int32_t major_version = cta_res[3]; int32_t minor_version = cta_res[4]; ua[1] = reader->provider; dre_cmd (ua); //error would not be fatal int32_t hexlength = cta_res[1] - 2; //discard first and last byte, last byte is always checksum, first is answer code reader->hexserial[0] = 0; reader->hexserial[1] = 0; memcpy (reader->hexserial + 2, cta_res + 3, hexlength); int32_t low_dre_id = ((cta_res[4] << 16) | (cta_res[5] << 8) | cta_res[6]) - 48608; int32_t dre_chksum = 0; uchar buf[32]; snprintf ((char *)buf, sizeof(buf), "%i%i%08i", reader->provider - 16, major_version + 1, low_dre_id); for (i = 0; i < 32; i++) { if (buf[i] == 0x00) break; dre_chksum += buf[i] - 48; } rdr_log (reader, "type: DRE Crypt, caid: %04X, serial: {%s}, dre id: %i%i%i%08i, geocode %i, card: %s v%i.%i", reader->caid, cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)), dre_chksum, reader->provider - 16, major_version + 1, low_dre_id, geocode, card, major_version, minor_version); rdr_log (reader, "Provider name:%s.", provname); memset (reader->sa, 0, sizeof (reader->sa)); memcpy (reader->sa[0], reader->hexserial + 2, 1); //copy first byte of unique address also in shared address, because we dont know what it is... rdr_log_sensitive(reader, "SA = %02X%02X%02X%02X, UA = {%s}", reader->sa[0][0], reader->sa[0][1], reader->sa[0][2], reader->sa[0][3], cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp))); reader->nprov = 1; if (!dre_set_provider_info (reader)) return ERROR; //fatal error rdr_log(reader, "ready for requests"); return OK; }