1832 lines
49 KiB
C
1832 lines
49 KiB
C
#include "globals.h"
|
|
#ifdef READER_NAGRA_MERLIN
|
|
#include "cscrypt/bn.h"
|
|
#include "cscrypt/idea.h"
|
|
#include "csctapi/icc_async.h"
|
|
#include "oscam-time.h"
|
|
#include "reader-common.h"
|
|
#include "reader-nagra-common.h"
|
|
#include "oscam-work.h"
|
|
#include "cscrypt/des.h"
|
|
#include "cscrypt/mdc2.h"
|
|
|
|
static uint8_t public_exponent[] = { 0x01, 0x00, 0x01 };
|
|
static const uint8_t d00ff[] = { 0x00, 0xFF, 0xFF, 0xFF };
|
|
|
|
// Datatypes
|
|
#define SYSID_CAID 0x02
|
|
#define IRDINFO 0x03
|
|
#define DT05 0x05
|
|
#define TIERS 0x0C
|
|
|
|
static time_t tier_date(uint64_t date, char *buf, int32_t l)
|
|
{
|
|
time_t ut = +694224000L + (date >> 1);
|
|
if(buf)
|
|
{
|
|
struct tm t;
|
|
cs_gmtime_r(&ut, &t);
|
|
l = 27;
|
|
snprintf(buf, l, "%04d/%02d/%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
|
|
}
|
|
return ut;
|
|
}
|
|
|
|
static void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keylen, uint8_t *expo, uint8_t expolen)
|
|
{
|
|
BN_CTX *ctx0 = BN_CTX_new();
|
|
#ifdef WITH_LIBCRYPTO
|
|
BN_CTX_start(ctx0);
|
|
#endif
|
|
BIGNUM *bnN0 = BN_CTX_get(ctx0);
|
|
BIGNUM *bnE0 = BN_CTX_get(ctx0);
|
|
BIGNUM *bnCT0 = BN_CTX_get(ctx0);
|
|
BIGNUM *bnPT0 = BN_CTX_get(ctx0);
|
|
BN_bin2bn(&key[0], keylen, bnN0);
|
|
BN_bin2bn(&expo[0], expolen, bnE0);
|
|
BN_bin2bn(&edata50[0], len, bnCT0);
|
|
BN_mod_exp(bnPT0, bnCT0, bnE0, bnN0, ctx0);
|
|
memset(out, 0x00, len);
|
|
BN_bn2bin(bnPT0, out + (len - BN_num_bytes(bnPT0)));
|
|
BN_CTX_end(ctx0);
|
|
BN_CTX_free(ctx0);
|
|
}
|
|
|
|
static void addProvider(struct s_reader *reader, uint8_t *cta_res)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
for(i = 0; i < reader->nprov; i++)
|
|
{
|
|
if((cta_res[0] == reader->prid[i][2]) && (cta_res[1] == reader->prid[i][3]))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd)
|
|
{
|
|
reader->prid[reader->nprov][0] = 0;
|
|
reader->prid[reader->nprov][1] = 0;
|
|
reader->prid[reader->nprov][2] = cta_res[0];
|
|
reader->prid[reader->nprov][3] = cta_res[1];
|
|
reader->nprov += 1;
|
|
}
|
|
}
|
|
|
|
static int32_t get_prov_index(struct s_reader *reader, const uint8_t *provid)
|
|
{
|
|
int prov;
|
|
for(prov = 0; prov < reader->nprov; prov++)
|
|
{
|
|
if(!memcmp(provid, &reader->prid[prov][2], 2))
|
|
{
|
|
return (prov);
|
|
}
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
static void addSA(struct s_reader *reader, uint8_t *cta_res)
|
|
{
|
|
if((cta_res[0] == 0x83 && cta_res[5] == 0x10) || cta_res[0] == 0x87)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
if(reader->evensa)
|
|
{
|
|
if(cta_res[0] == 0x87)
|
|
{
|
|
cta_res[4] = 0x00;
|
|
}
|
|
unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
|
|
if(sax % 2 != 0)
|
|
{
|
|
sax--;
|
|
cta_res[3] = (sax >> 16) & 0xFF;
|
|
cta_res[2] = (sax >> 8) & 0xFF;
|
|
cta_res[1] = (sax ) & 0xFF;
|
|
}
|
|
}
|
|
for(i = 0; i < reader->nsa; i++)
|
|
{
|
|
if((cta_res[1] == reader->sa[i][2]) && (cta_res[2] == reader->sa[i][1]) && (cta_res[3] == reader->sa[i][0]) && (cta_res[4] == reader->sa[i][3]))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
|
|
{
|
|
reader->sa[reader->nsa][0] = cta_res[3];
|
|
reader->sa[reader->nsa][1] = cta_res[2];
|
|
reader->sa[reader->nsa][2] = cta_res[1];
|
|
reader->sa[reader->nsa][3] = cta_res[4];
|
|
reader->nsa += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void addSAseca(struct s_reader *reader, uint8_t *cta_res)
|
|
{
|
|
if(cta_res[0] == 0x84)
|
|
{
|
|
addProvider(reader, cta_res + 1);
|
|
if(reader->evensa)
|
|
{
|
|
unsigned long sax = (cta_res[3] << 16) + (cta_res[4] << 8) + (cta_res[5]);
|
|
if(sax % 2 != 0)
|
|
{
|
|
sax--;
|
|
cta_res[3] = (sax >> 16) & 0xFF;
|
|
cta_res[4] = (sax >> 8) & 0xFF;
|
|
cta_res[5] = (sax ) & 0xFF;
|
|
}
|
|
}
|
|
if(memcmp(cta_res + 3, "\x00\x00\x00", 3))
|
|
{
|
|
int i;
|
|
i = get_prov_index(reader, cta_res + 1);
|
|
memcpy(reader->sa[i], cta_res + 3, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void addemmfilter(struct s_reader *reader, uint8_t *cta_res)
|
|
{
|
|
if(cta_res[0] == 0x82)
|
|
{
|
|
reader->emm82 = 1;
|
|
}
|
|
else if(cta_res[0] == 0x84)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
for(i = 0; i < reader->nemm84; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm84[i], 3))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 1, "\x00\x00", 2)))
|
|
{
|
|
reader->emm84[reader->nemm84][0] = cta_res[0];
|
|
reader->emm84[reader->nemm84][1] = cta_res[1];
|
|
reader->emm84[reader->nemm84][2] = cta_res[2];
|
|
reader->nemm84 += 1;
|
|
}
|
|
}
|
|
else if(cta_res[0] == 0x83 && cta_res[5] == 0x00)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
for(i = 0; i < reader->nemm83u; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm83u[i], 6))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00\x00", 4)))
|
|
{
|
|
memcpy(reader->emm83u[reader->nemm83u], cta_res, 6);
|
|
reader->nemm83u += 1;
|
|
}
|
|
}
|
|
else if(cta_res[0] == 0x83 && cta_res[5] == 0x10)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
if(reader->evensa)
|
|
{
|
|
unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
|
|
if(sax % 2 != 0)
|
|
{
|
|
sax--;
|
|
cta_res[3] = (sax >> 16) & 0xFF;
|
|
cta_res[2] = (sax >> 8) & 0xFF;
|
|
cta_res[1] = (sax ) & 0xFF;
|
|
}
|
|
}
|
|
for(i = 0; i < reader->nemm83s; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm83s[i], 6))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
|
|
{
|
|
memcpy(reader->emm83s[reader->nemm83s], cta_res, 6);
|
|
reader->nemm83s += 1;
|
|
}
|
|
}
|
|
else if(cta_res[0] == 0x87)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
if(reader->evensa)
|
|
{
|
|
cta_res[4] = 0x00;
|
|
unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
|
|
if(sax % 2 != 0)
|
|
{
|
|
sax--;
|
|
cta_res[3] = (sax >> 16) & 0xFF;
|
|
cta_res[2] = (sax >> 8) & 0xFF;
|
|
cta_res[1] = (sax ) & 0xFF;
|
|
}
|
|
}
|
|
for(i = 0; i < reader->nemm87; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm87[i], 6))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
|
|
{
|
|
memcpy(reader->emm87[reader->nemm87], cta_res, 6);
|
|
reader->nemm87 += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void addemmfilterseca(struct s_reader *reader, uint8_t *cta_res)
|
|
{
|
|
if(cta_res[0] == 0x83)
|
|
{
|
|
reader->emm83 = 1;
|
|
}
|
|
else if(cta_res[0] == 0x82 && cta_res[1] == 0x00 && cta_res[2] == 0x00)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
for(i = 0; i < reader->nemm82u; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm82u[i], 7))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 3, "\x00\x00\x00\x00", 4)))
|
|
{
|
|
memcpy(reader->emm82u[reader->nemm82u], cta_res, 7);
|
|
reader->nemm82u += 1;
|
|
}
|
|
}
|
|
else if(cta_res[0] == 0x84)
|
|
{
|
|
int i;
|
|
bool toadd = true;
|
|
if(reader->evensa)
|
|
{
|
|
unsigned long sax = (cta_res[3] << 16) + (cta_res[4] << 8) + (cta_res[5]);
|
|
if(sax % 2 != 0)
|
|
{
|
|
sax--;
|
|
cta_res[3] = (sax >> 16) & 0xFF;
|
|
cta_res[4] = (sax >> 8) & 0xFF;
|
|
cta_res[5] = (sax ) & 0xFF;
|
|
}
|
|
}
|
|
for(i = 0; i < reader->nemm84s; i++)
|
|
{
|
|
if(!memcmp(cta_res, reader->emm84s[i], 6))
|
|
{
|
|
toadd = false;
|
|
}
|
|
}
|
|
if(toadd && (memcmp(cta_res + 3, "\x00\x00\x00", 3)))
|
|
{
|
|
memcpy(reader->emm84s[reader->nemm84s], cta_res, 6);
|
|
reader->nemm84s += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_res, uint16_t cta_lr)
|
|
{
|
|
char ds[27], de[27];
|
|
|
|
switch(dt)
|
|
{
|
|
case SYSID_CAID:
|
|
{
|
|
reader->prid[0][0] = 0x00;
|
|
reader->prid[0][1] = 0x00;
|
|
reader->prid[0][2] = cta_res[19];
|
|
reader->prid[0][3] = cta_res[20];
|
|
reader->prid[1][0] = 0x00;
|
|
reader->prid[1][1] = 0x00;
|
|
reader->prid[1][2] = 0x00;
|
|
reader->prid[1][3] = 0x00;
|
|
reader->nprov += 1;
|
|
reader->caid = (SYSTEM_NAGRA | cta_res[25]);
|
|
reader->cak7_emm_caid = (SYSTEM_NAGRA | cta_res[25]);
|
|
rdr_log_dbg(reader, D_READER, "EMM CAID : %04X", reader->cak7_emm_caid);
|
|
return OK;
|
|
}
|
|
|
|
case IRDINFO: // case 0x03
|
|
{
|
|
uint16_t chid = 0;
|
|
uint32_t id = b2i(0x02, cta_res + 19);
|
|
uint32_t start_date = 1;
|
|
uint32_t expire_date = 0;
|
|
|
|
if(cta_res[21] == 0x9C)
|
|
{
|
|
if((reader->caid == 0x186D) || (reader->caid == 0x187D))
|
|
{
|
|
const uint8_t timestamp2038[4] = {0xAD, 0x0E, 0x26, 0x01};
|
|
expire_date = b2i(0x04, timestamp2038);
|
|
}
|
|
else
|
|
{
|
|
expire_date = b2i(0x04, cta_res + 22);
|
|
}
|
|
}
|
|
|
|
if((cta_res[21] == 0x01) && (reader->protocol_type == ATR_PROTOCOL_TYPE_T0 ||
|
|
((reader->caid == 0x1856 || reader->caid == 0x187D) && cta_res[8] != 0x18)))
|
|
{
|
|
expire_date = b2i(0x04, cta_res + 22);
|
|
}
|
|
|
|
if (expire_date)
|
|
{
|
|
reader->card_valid_to = tier_date(expire_date, de, 11);
|
|
cs_add_entitlement(reader, reader->caid, id, chid, 0, tier_date(start_date, ds, 11), tier_date(expire_date, de, 11), 4, 1);
|
|
rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
|
|
addProvider(reader, cta_res + 19);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
case 0x04:
|
|
{
|
|
if(cta_res[18] != 0x80)
|
|
{
|
|
addProvider(reader, cta_res + 19);
|
|
uint8_t check[] = {0x00, 0x01};
|
|
uint8_t checkecmcaid[] = {0xFF, 0x07};
|
|
uint8_t emm84g_provid[2];
|
|
check[0] = reader->cak7_emm_caid & 0xFF;
|
|
|
|
int p;
|
|
for(p = 23; p < (cta_lr - 6); p++)
|
|
{
|
|
if(!memcmp(cta_res + p, check, 2))
|
|
{
|
|
addProvider(reader, cta_res + p + 2);
|
|
if(reader->cak7type == 3)
|
|
{
|
|
addSAseca(reader, cta_res + p + 5);
|
|
addemmfilterseca(reader, cta_res + p + 5);
|
|
}
|
|
else
|
|
{
|
|
if ((reader->cak7_emm_caid == 0x186A) && ((cta_res + p + 5)[0] == 0x84) && ((cta_res + p + 5)[1] == 0x00))
|
|
{
|
|
(cta_res + p + 5)[2] = 0xAC;
|
|
}
|
|
if ((cta_res + p + 5)[0] == 0x84)
|
|
{
|
|
emm84g_provid[0] = (cta_res + p + 5)[1] & (cta_res + p + 5)[4];
|
|
emm84g_provid[1] = (cta_res + p + 5)[2] & (cta_res + p + 5)[5];
|
|
addProvider(reader, emm84g_provid);
|
|
}
|
|
addSA(reader, cta_res + p + 5);
|
|
addemmfilter(reader, cta_res + p + 5);
|
|
}
|
|
}
|
|
if((!memcmp(cta_res + p, checkecmcaid, 2)) && ((cta_res + p + 2)[1] == 0x02))
|
|
{
|
|
reader->caid = (SYSTEM_NAGRA | (cta_res + p + 2)[0]);
|
|
rdr_log_dbg(reader, D_READER, "ECM CAID : %04X", reader->caid);
|
|
}
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
case 0x09:
|
|
{
|
|
if((cta_res[19] == cta_res[23]) && (cta_res[20] == cta_res[24]))
|
|
{
|
|
addProvider(reader, cta_res + 19);
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
case DT05: // case 0x05
|
|
{
|
|
memcpy(reader->edata,cta_res + 26, 0x70);
|
|
reader->dt5num = cta_res[20];
|
|
char tmp[8];
|
|
rdr_log(reader, "Card has DT05_%s", cs_hexdump(1, &reader->dt5num, 1, tmp, sizeof(tmp)));
|
|
IDEA_KEY_SCHEDULE ks;
|
|
if(reader->dt5num == 0x00)
|
|
{
|
|
rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod1, reader->mod1_length, public_exponent, 3);
|
|
memcpy(reader->kdt05_00, &reader->out[18], 0x5C + 2);
|
|
memcpy(&reader->kdt05_00[0x5C + 2], cta_res + 26 + 0x70, 6);
|
|
memcpy(reader->ideakey1, reader->out, 16);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->ideakey1, 16, "IDEAKEY1: ");
|
|
memcpy(reader->block3, cta_res + 26 + 0x70 + 6, 8);
|
|
idea_set_encrypt_key(reader->ideakey1, &ks);
|
|
memset(reader->v, 0, sizeof(reader->v));
|
|
idea_cbc_encrypt(reader->block3, reader->iout, 8, &ks, reader->v, IDEA_DECRYPT);
|
|
memcpy(&reader->kdt05_00[0x5C + 2 + 6], reader->iout, 8);
|
|
|
|
uint8_t mdc_hash1[MDC2_DIGEST_LENGTH];
|
|
uint8_t check1[0x7E];
|
|
memset(check1, 0x00, 0x7E);
|
|
memcpy(check1 + 18, reader->kdt05_00, 0x6C);
|
|
MDC2_CTX c1;
|
|
MDC2_Init(&c1);
|
|
MDC2_Update(&c1, check1, 0x7E);
|
|
MDC2_Final(&(mdc_hash1[0]), &c1);
|
|
rdr_log_dump_dbg(reader, D_READER, mdc_hash1, 16, "MDC_HASH: ");
|
|
|
|
if(memcmp(mdc_hash1 + 1, reader->ideakey1 + 1, 14) == 0)
|
|
{
|
|
rdr_log(reader, "DT05_00 is correct");
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "DT05_00 error - check MOD1");
|
|
}
|
|
|
|
rdr_log_dump_dbg(reader, D_READER, reader->kdt05_00, sizeof(reader->kdt05_00), "DT05_00: ");
|
|
}
|
|
|
|
if(reader->dt5num == 0x10)
|
|
{
|
|
rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod1, reader->mod1_length, public_exponent, 3);
|
|
memcpy(reader->kdt05_10, &reader->out[16], 6 * 16);
|
|
memcpy(reader->ideakey1, reader->out, 16);
|
|
memcpy(reader->block3, cta_res + 26 + 0x70, 8);
|
|
idea_set_encrypt_key(reader->ideakey1, &ks);
|
|
memset(reader->v, 0, sizeof(reader->v));
|
|
idea_cbc_encrypt(reader->block3, reader->iout, 8, &ks, reader->v, IDEA_DECRYPT);
|
|
memcpy(&reader->kdt05_10[6 * 16], reader->iout, 8);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->kdt05_10, sizeof(reader->kdt05_10), "DT05_10: ");
|
|
}
|
|
|
|
if(reader->dt5num == 0x20)
|
|
{
|
|
rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod2, reader->mod2_length, public_exponent, 3);
|
|
memcpy(reader->tmprsa, reader->out, 0x70);
|
|
reader->hasunique = 1;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
case TIERS: // case 0x0C
|
|
{
|
|
if(cta_lr >= 0x30)
|
|
{
|
|
uint16_t chid = b2i(0x02, cta_res + 23);
|
|
uint32_t id = b2i(0x02, cta_res + 19);
|
|
uint32_t start_date = 0;
|
|
uint32_t expire_date1;
|
|
uint32_t expire_date2;
|
|
uint32_t expire_date = 0;
|
|
|
|
switch(reader->caid)
|
|
{
|
|
case 0x1830: // Max TV
|
|
case 0x1843: // HD02
|
|
case 0x1860: // HD03
|
|
start_date = b2i(0x04, cta_res + 42);
|
|
expire_date1 = b2i(0x04, cta_res + 28);
|
|
expire_date2 = b2i(0x04, cta_res + 46);
|
|
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
|
|
break;
|
|
|
|
case 0x1861: // Polsat, Vodafone D08, Movistar Latin America
|
|
{
|
|
if(!memcmp(reader->rom, "\x44\x4E\x41\x53\x50\x34\x35\x30\x20\x52\x65\x76\x57\x36\x30", 15))
|
|
{
|
|
start_date = b2i(0x04, cta_res + 53);
|
|
expire_date1 = b2i(0x04, cta_res + 39);
|
|
expire_date2 = b2i(0x04, cta_res + 57);
|
|
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
|
|
}
|
|
else if(!memcmp(reader->rom, "\x44\x4E\x41\x53\x50\x34\x31\x30\x20\x52\x65\x76\x51\x32\x31", 15))
|
|
{
|
|
start_date = b2i(0x04, cta_res + 42);
|
|
expire_date = b2i(0x04, cta_res + 28);
|
|
}
|
|
else if(!memcmp(reader->rom, "\x44\x4E\x41\x53\x50\x34\x31\x30\x20\x52\x65\x76\x51\x32\x53", 15))
|
|
{
|
|
start_date = 1;
|
|
expire_date = b2i(0x04, cta_res + 28);
|
|
}
|
|
else
|
|
{
|
|
start_date = b2i(0x04, cta_res + 42);
|
|
expire_date1 = b2i(0x04, cta_res + 28);
|
|
expire_date2 = b2i(0x04, cta_res + 46);
|
|
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x186A: // HD04, HD05
|
|
start_date = b2i(0x04, cta_res + 53);
|
|
expire_date1 = b2i(0x04, cta_res + 39);
|
|
expire_date2 = b2i(0x04, cta_res + 57);
|
|
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
|
|
break;
|
|
|
|
case 0x186D: // HD04H
|
|
case 0x187D: // Canal+ reunion
|
|
case 0x1884: // nc+
|
|
{
|
|
if(cta_res[8] == 0x45)
|
|
{
|
|
start_date = b2i(0x04, cta_res + 47);
|
|
expire_date1 = b2i(0x04, cta_res + 39);
|
|
expire_date2 = b2i(0x04, cta_res + 51);
|
|
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x1812:
|
|
case 0x1814: // MEO
|
|
case 0x1817: // Canal Digitaal
|
|
case 0x1818: // TV Vlaanderen
|
|
case 0x1819: // Telesat
|
|
{
|
|
if(cta_res[8] > 0x28)
|
|
{
|
|
start_date = b2i(0x04, cta_res + 32);
|
|
expire_date = b2i(0x04, cta_res + 36);
|
|
}
|
|
if(cta_res[8] == 0x20)
|
|
{
|
|
start_date = b2i(0x04, cta_res + 28);
|
|
expire_date = b2i(0x04, cta_res + 32);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x1824:
|
|
start_date = 1;
|
|
expire_date = b2i(0x04, cta_res + 28);
|
|
break;
|
|
|
|
default: // unknown card
|
|
start_date = 1;
|
|
expire_date = 0xAD0E2601;
|
|
}
|
|
|
|
cs_add_entitlement(reader, reader->caid, id, chid, 0, tier_date(start_date, ds, 11), tier_date(expire_date, de, 11), 4, 1);
|
|
rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
|
|
addProvider(reader, cta_res + 19);
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
default:
|
|
return OK;
|
|
}
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
static int32_t CAK7do_cmd(struct s_reader *reader, uint8_t dt, uint8_t *res, uint16_t *rlen, int32_t sub, uint8_t retlen)
|
|
{
|
|
uint8_t dtdata[0x10];
|
|
memset(dtdata, 0xCC, 0x10);
|
|
dtdata[ 7] = 0x04;
|
|
dtdata[ 8] = 0x04;
|
|
dtdata[ 9] = (sub >> 16) & 0xFF;
|
|
dtdata[10] = (sub >> 8) & 0xFF;
|
|
dtdata[11] = (sub ) & 0xFF;
|
|
dtdata[12] = dt;
|
|
|
|
do_cak7_cmd(reader, res, rlen, dtdata, sizeof(dtdata), retlen);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t CAK7GetDataType(struct s_reader *reader, uint8_t dt)
|
|
{
|
|
def_resp;
|
|
int32_t sub = 0x00;
|
|
uint8_t retlen = 0x10;
|
|
|
|
while(1)
|
|
{
|
|
CAK7do_cmd(reader, dt, cta_res, &cta_lr, sub, retlen);
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, cta_lr, "Decrypted Answer:");
|
|
|
|
// hier eigentlich check auf 90 am ende usw... obs halt klarging ...
|
|
if(cta_lr == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(cta_res[cta_lr - 2] == 0x6F && cta_res[cta_lr - 1] == 0x01)
|
|
{
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
break;
|
|
}
|
|
|
|
uint32_t newsub = (cta_res[9] << 16) + (cta_res[10] << 8) + (cta_res[11]);
|
|
if(newsub == 0xFFFFFF)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(cta_res[12] == dt)
|
|
{
|
|
uint8_t oretlen = retlen;
|
|
retlen = cta_res[13] + 0x10 + 0x2;
|
|
|
|
while(retlen % 0x10 != 0x00)
|
|
{
|
|
retlen++;
|
|
}
|
|
|
|
if(retlen == oretlen)
|
|
{
|
|
sub = newsub + 1;
|
|
retlen = 0x10;
|
|
ParseDataType(reader, dt, cta_res, cta_lr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void sub_6AD78(uint32_t *dinit) // gbox function
|
|
{
|
|
double res = *dinit * 16807.0;
|
|
*dinit = (uint32_t)(res - (uint32_t)(res / 2147483647.0) * 2147483647.0);
|
|
}
|
|
|
|
static void calc_cak7_exponent(uint32_t *dinit, uint8_t *out, uint8_t len)
|
|
{
|
|
memset(out, 0x00, len);
|
|
sub_6AD78(dinit);
|
|
int nR4 = 0;
|
|
int nR5 = 0;
|
|
|
|
while(true)
|
|
{
|
|
uint32_t nR0 = (uint32_t)* dinit;
|
|
int nR3 = nR4 + 3;
|
|
nR5 += 4;
|
|
|
|
if(nR3 > len)
|
|
{
|
|
break;
|
|
}
|
|
|
|
out[nR5 - 1] = ((nR0 ) & 0xFF);
|
|
out[nR5 - 2] = ((nR0 >> 8) & 0xFF);
|
|
out[nR5 - 3] = ((nR0 >> 16) & 0xFF);
|
|
out[nR5 - 4] = ((nR0 >> 24) & 0xFF);
|
|
nR4 += 4;
|
|
sub_6AD78(dinit);
|
|
}
|
|
|
|
uint32_t nR0 = (uint32_t)* dinit;
|
|
|
|
while(nR4 < len)
|
|
{
|
|
out[nR4] = nR0 & 0xFF;
|
|
nR4++;
|
|
nR0 >>= 8;
|
|
}
|
|
|
|
out[ 0] &= 0x03;
|
|
out[0x10] |= 0x01;
|
|
}
|
|
|
|
static void IdeaDecrypt(unsigned char *data, int len, const unsigned char *key, unsigned char *iv)
|
|
{
|
|
unsigned char v[8];
|
|
|
|
if(!iv)
|
|
{
|
|
memset(v, 0, sizeof(v));
|
|
iv = v;
|
|
}
|
|
|
|
IDEA_KEY_SCHEDULE ks;
|
|
idea_set_encrypt_key(key, &ks);
|
|
idea_cbc_encrypt(data, data, len&~7, &ks, iv, IDEA_DECRYPT);
|
|
}
|
|
|
|
static inline void xor8(uint8_t *data, const uint8_t *v1, const uint8_t *v2)
|
|
{
|
|
int i;
|
|
for(i = 0; i < 8; ++i)
|
|
{
|
|
data[i] = v1[i] ^ v2[i];
|
|
}
|
|
}
|
|
|
|
static void CreateRSAPair60(struct s_reader *reader, const unsigned char *key)
|
|
{
|
|
unsigned char idata[96];
|
|
|
|
int i;
|
|
for(i = 11; i >= 0; i--)
|
|
{
|
|
unsigned char *d = &idata[i * 8];
|
|
memcpy(d, &key[13], 8);
|
|
*d ^= i;
|
|
IdeaDecrypt(d, 8, key, 0);
|
|
xor8(d, d, &key[13]);
|
|
*d ^= i;
|
|
}
|
|
|
|
BN_CTX *ctx5 = BN_CTX_new();
|
|
#ifdef WITH_LIBCRYPTO
|
|
BN_CTX_start(ctx5);
|
|
#endif
|
|
BIGNUM *p = BN_CTX_get(ctx5);
|
|
BIGNUM *q = BN_CTX_get(ctx5);
|
|
BIGNUM *m = BN_CTX_get(ctx5);
|
|
BIGNUM *e = BN_CTX_get(ctx5);
|
|
BIGNUM *a = BN_CTX_get(ctx5);
|
|
BIGNUM *r = BN_CTX_get(ctx5);
|
|
|
|
// Calculate P
|
|
idata[ 0] |= 0x80;
|
|
idata[47] |= 1;
|
|
BN_bin2bn(idata, 48, p);
|
|
BN_add_word(p, (key[21] << 5) | ((key[22] & 0xF0) >> 3));
|
|
|
|
// Calculate Q
|
|
idata[48] |= 0x80;
|
|
idata[95] |= 1;
|
|
BN_bin2bn(idata + 48, 48, q);
|
|
BN_add_word(q, ((key[22] & 0xF) << 9) | (key[23] << 1));
|
|
|
|
// Calculate M = P * Q
|
|
BN_mul(m, p, q, ctx5);
|
|
memset(reader->key60, 0x00, 0x60);
|
|
BN_bn2bin(m, reader->key60 + (0x60 - BN_num_bytes(m)));
|
|
rdr_log_dump_dbg(reader, D_READER, reader->key60, sizeof(reader->key60), "key60: ");
|
|
|
|
// Calculate D
|
|
BN_sub_word(p, 1);
|
|
BN_sub_word(q, 1);
|
|
BN_mul(e, p, q, ctx5);
|
|
BN_bin2bn(public_exponent, 3, a);
|
|
BN_mod_inverse(r, a, e, ctx5);
|
|
memset(reader->exp60, 0x00, 0x60);
|
|
BN_bn2bin(r, reader->exp60 + (0x60 - BN_num_bytes(r)));
|
|
rdr_log_dump_dbg(reader, D_READER, reader->exp60, sizeof(reader->exp60), "exp60: ");
|
|
BN_CTX_end(ctx5);
|
|
BN_CTX_free(ctx5);
|
|
}
|
|
|
|
static void CreateRSAPair68(struct s_reader *reader, const unsigned char *key)
|
|
{
|
|
unsigned char idata[104];
|
|
|
|
int i;
|
|
for(i = 12; i >= 0; i--)
|
|
{
|
|
unsigned char *d = &idata[i * 8];
|
|
memcpy(d, &key[13], 8);
|
|
*d ^= i;
|
|
IdeaDecrypt(d, 8, key, 0);
|
|
xor8(d, d, &key[13]);
|
|
*d ^= i;
|
|
}
|
|
|
|
BN_CTX *ctx6 = BN_CTX_new();
|
|
#ifdef WITH_LIBCRYPTO
|
|
BN_CTX_start(ctx6);
|
|
#endif
|
|
BIGNUM *p = BN_CTX_get(ctx6);
|
|
BIGNUM *q = BN_CTX_get(ctx6);
|
|
BIGNUM *m = BN_CTX_get(ctx6);
|
|
BIGNUM *e = BN_CTX_get(ctx6);
|
|
BIGNUM *a = BN_CTX_get(ctx6);
|
|
BIGNUM *r = BN_CTX_get(ctx6);
|
|
|
|
// Calculate P
|
|
idata[ 0] |= 0x80;
|
|
idata[51] |= 1;
|
|
BN_bin2bn(idata, 52, p);
|
|
BN_add_word(p, (key[21] << 5) | ((key[22] & 0xF0) >> 3));
|
|
|
|
// Calculate Q
|
|
idata[ 52] |= 0x80;
|
|
idata[103] |= 1;
|
|
BN_bin2bn(idata + 52, 52, q);
|
|
BN_add_word(q, ((key[22] & 0xF) << 9) | (key[23] << 1));
|
|
|
|
// Calculate M = P * Q
|
|
BN_mul(m, p, q, ctx6);
|
|
memset(reader->key68, 0x00, 0x68);
|
|
BN_bn2bin(m, reader->key68 + (0x68 - BN_num_bytes(m)));
|
|
rdr_log_dump_dbg(reader, D_READER, reader->key68, sizeof(reader->key68), "key68: ");
|
|
|
|
// Calculate D
|
|
BN_sub_word(p, 1);
|
|
BN_sub_word(q, 1);
|
|
BN_mul(e, p, q, ctx6);
|
|
BN_bin2bn(public_exponent, 3, a);
|
|
BN_mod_inverse(r, a, e, ctx6);
|
|
memset(reader->exp68, 0x00, 0x68);
|
|
BN_bn2bin(r, reader->exp68 + (0x68 - BN_num_bytes(r)));
|
|
rdr_log_dump_dbg(reader, D_READER, reader->exp68, sizeof(reader->exp68), "exp68: ");
|
|
BN_CTX_end(ctx6);
|
|
BN_CTX_free(ctx6);
|
|
}
|
|
|
|
static void dt05_20(struct s_reader *reader)
|
|
{
|
|
uint8_t data_20_00[72];
|
|
uint8_t sig_20_00[16];
|
|
uint8_t data_20_id[72];
|
|
uint8_t data_20_x[64];
|
|
uint8_t data_20_fin[72];
|
|
uint8_t data_20_flag58[16];
|
|
|
|
rdr_log_dump_dbg(reader, D_READER, reader->tmprsa, sizeof(reader->tmprsa), "DT05_20 after RSA: ");
|
|
|
|
// copy signature
|
|
memcpy(sig_20_00, reader->tmprsa + 24, 16);
|
|
|
|
// copy data
|
|
memcpy(data_20_00, reader->tmprsa + 40, 72);
|
|
|
|
// IDEA encrypt 0x48 data
|
|
int i;
|
|
int offs = 0;
|
|
for(i = 0; i < 9; i++)
|
|
{
|
|
IDEA_KEY_SCHEDULE ks;
|
|
idea_set_encrypt_key(reader->key3310, &ks);
|
|
idea_ecb_encrypt(data_20_00 + offs, data_20_id + offs, &ks);
|
|
offs += 8;
|
|
}
|
|
|
|
// xor
|
|
for(i = 0; i < 64; i++)
|
|
{
|
|
data_20_x[i] = data_20_00[i] ^ data_20_id[i + 8];
|
|
}
|
|
rdr_log_dump_dbg(reader, D_READER, data_20_x, sizeof(data_20_x), "data_20_x: ");
|
|
|
|
// create final data block
|
|
memcpy(data_20_fin, data_20_id, 8);
|
|
memcpy(data_20_fin + 8, data_20_x, 64);
|
|
rdr_log_dump_dbg(reader, D_READER, data_20_fin, sizeof(data_20_fin), "data_20_fin: ");
|
|
uint8_t mdc_hash4[MDC2_DIGEST_LENGTH];
|
|
uint8_t check4[112];
|
|
memset(check4, 0x00, 112);
|
|
memcpy(check4, reader->cardid, 4);
|
|
memcpy(check4 + 4, reader->idird, 4);
|
|
memcpy(check4 + 23, reader->tmprsa + 23, 1);
|
|
memcpy(check4 + 40, data_20_fin, 72);
|
|
MDC2_CTX c4;
|
|
MDC2_Init(&c4);
|
|
MDC2_Update(&c4, check4, 112);
|
|
MDC2_Final(&(mdc_hash4[0]), &c4);
|
|
if(memcmp(mdc_hash4, sig_20_00, 16) == 0)
|
|
{
|
|
rdr_log(reader, "DT05_20 is correct");
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "DT05_20 error - check MOD2");
|
|
}
|
|
|
|
// Store 3des software key Flag58 CW overencrypt
|
|
memcpy(data_20_flag58, data_20_x + 16, 16);
|
|
memcpy(reader->key3des, data_20_flag58, 16);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->key3des, sizeof(reader->key3des), "Flag58 3DES Key: ");
|
|
|
|
// create rsa pair from final data
|
|
memcpy(reader->klucz68, data_20_fin, 0x18);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->klucz68, sizeof(reader->klucz68), "klucz68: ");
|
|
}
|
|
|
|
static int32_t CAK7_cmd03_global(struct s_reader *reader)
|
|
{
|
|
def_resp;
|
|
|
|
if(reader->cak7_seq <= 15)
|
|
{
|
|
unsigned char klucz[24];
|
|
memset(klucz, 0x00, 24);
|
|
memcpy(klucz, reader->key3588, 24);
|
|
CreateRSAPair60(reader, klucz);
|
|
}
|
|
|
|
rsa_decrypt(reader->step1, 0x60, reader->data, reader->key60, 0x60, reader->exp60, 0x60);
|
|
|
|
memcpy(&reader->step2[0], d00ff, 4);
|
|
memcpy(&reader->step2[4], reader->cardid, 4);
|
|
memcpy(&reader->step2[8], reader->data, 0x60);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->step2, sizeof(reader->step2), "STEP 2:");
|
|
rsa_decrypt(reader->step2, 0x68, reader->data, reader->kdt05_10, 0x68, public_exponent, 3);
|
|
|
|
memcpy(&reader->step3[0], d00ff, 4);
|
|
memcpy(&reader->step3[4], reader->data, 0x68);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->step3, sizeof(reader->step3), "STEP 3:");
|
|
rsa_decrypt(reader->step3, 0x6C, reader->data, reader->kdt05_00, 0x6C, public_exponent, 3);
|
|
|
|
uint8_t cmd03[] = {0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x0A, 0x03, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
|
|
memcpy(&cmd03[9], reader->data, 0x6C);
|
|
do_cak7_cmd(reader, cta_res, &cta_lr, cmd03, sizeof(cmd03), 0x90);
|
|
if(cta_lr == 0)
|
|
{
|
|
rdr_log(reader, "card is not responding to CMD03 - check your data");
|
|
return ERROR;
|
|
}
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, 0x90, "CMD03 ANSWER:");
|
|
memcpy(reader->encrypted, &cta_res[10], 0x68);
|
|
rsa_decrypt(reader->encrypted, 0x68, reader->result, reader->kdt05_10, 0x68, public_exponent, 3);
|
|
//uint8_t stillencrypted[0x50];
|
|
memcpy(reader->stillencrypted, &reader->result[12], 0x50);
|
|
//uint8_t resultrsa[0x50];
|
|
rsa_decrypt(reader->stillencrypted, 0x50, reader->resultrsa, reader->mod50, reader->mod50_length, reader->cak7expo, 0x11);
|
|
|
|
uint8_t mdc_hash3[MDC2_DIGEST_LENGTH];
|
|
MDC2_CTX c3;
|
|
MDC2_Init(&c3);
|
|
MDC2_Update(&c3, reader->resultrsa, sizeof(reader->resultrsa));
|
|
MDC2_Final(&(mdc_hash3[0]), &c3);
|
|
memcpy(&reader->cak7_aes_key[16], mdc_hash3, 16);
|
|
memcpy(reader->cak7_aes_key, mdc_hash3, 16);
|
|
char tmp7[128];
|
|
rdr_log(reader, "New AES: %s", cs_hexdump(1, reader->cak7_aes_key, 16, tmp7, sizeof(tmp7)));
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t CAK7_cmd03_unique(struct s_reader *reader)
|
|
{
|
|
def_resp;
|
|
|
|
rsa_decrypt(reader->step1, 0x60, reader->data, reader->key3460, reader->key3460_length, public_exponent, 3);
|
|
|
|
memcpy(&reader->step2[0], d00ff, 4);
|
|
memcpy(&reader->step2[4], reader->cardid, 4);
|
|
memcpy(&reader->step2[8], reader->data, 0x60);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->step2, sizeof(reader->step2), "STEP 2:");
|
|
|
|
if(reader->cak7_seq <= 15)
|
|
{
|
|
dt05_20(reader);
|
|
CreateRSAPair68(reader, reader->klucz68);
|
|
}
|
|
|
|
rsa_decrypt(reader->step2, 0x68, reader->data, reader->key68, 0x68, reader->exp68, 0x68);
|
|
|
|
memcpy(&reader->step3[0], d00ff, 4);
|
|
memcpy(&reader->step3[4], reader->data, 0x68);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->step3, sizeof(reader->step3), "STEP 3:");
|
|
rsa_decrypt(reader->step3, 0x6C, reader->data, reader->kdt05_00, 0x6C, public_exponent, 3);
|
|
|
|
uint8_t cmd03[] = {0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x0A, 0x03, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
|
|
memcpy(&cmd03[9], reader->data, 0x6C);
|
|
|
|
do_cak7_cmd(reader, cta_res, &cta_lr, cmd03, sizeof(cmd03), 0x90);
|
|
if(cta_lr == 0)
|
|
{
|
|
rdr_log(reader, "card is not responding to CMD03 - check your data");
|
|
return ERROR;
|
|
}
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, 0x90, "CMD03 ANSWER:");
|
|
memcpy(reader->encrypted, &cta_res[18], 0x60);
|
|
rsa_decrypt(reader->encrypted, 0x60, reader->result, reader->key3460, reader->key3460_length, public_exponent, 3);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->result, 0x60, "after RSA_3460: ");
|
|
//uint8_t stillencrypted[0x50];
|
|
memcpy(reader->stillencrypted, &reader->result[4], 0x50);
|
|
//uint8_t resultrsa[0x50];
|
|
rsa_decrypt(reader->stillencrypted, 0x50, reader->resultrsa, reader->mod50, reader->mod50_length, reader->cak7expo, 0x11);
|
|
|
|
uint8_t mdc_hash5[MDC2_DIGEST_LENGTH];
|
|
MDC2_CTX c5;
|
|
MDC2_Init(&c5);
|
|
MDC2_Update(&c5, reader->resultrsa, sizeof(reader->resultrsa));
|
|
MDC2_Final(&(mdc_hash5[0]), &c5);
|
|
memcpy(&reader->cak7_aes_key[16], mdc_hash5, 16);
|
|
memcpy(reader->cak7_aes_key, mdc_hash5, 16);
|
|
char tmp7[128];
|
|
rdr_log(reader, "New AES: %s", cs_hexdump(1, reader->cak7_aes_key, 16, tmp7, sizeof(tmp7)));
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t CAK7_GetCamKey(struct s_reader *reader)
|
|
{
|
|
def_resp;
|
|
uint8_t cmd0e[] = {0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x0E, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
|
|
|
|
if(!reader->nuid_length)
|
|
{
|
|
uint8_t cmd02[] = {0x02, 0x7B};
|
|
memcpy(cmd0e + 7, cmd02, 2);
|
|
rdr_log(reader, "using CMD02");
|
|
}
|
|
else
|
|
{
|
|
int cwekeycount = 0, i;
|
|
memcpy(cmd0e + 132, reader->nuid, reader->nuid_length); // inject NUID
|
|
|
|
for (i = 0; i < 17; i++)
|
|
{
|
|
cwekeycount = reader->cwekey_length[i] ? i + 1 : cwekeycount;
|
|
}
|
|
|
|
if(cwekeycount == 0)
|
|
{
|
|
if(reader->otpcsc_length)
|
|
{
|
|
memcpy(cmd0e + 136, reader->otpcsc, reader->otpcsc_length);
|
|
}
|
|
else
|
|
{
|
|
cmd0e[136] = 0x00;
|
|
cmd0e[137] = !reader->cwpkota ? 0xFF : 0x00;
|
|
}
|
|
if(reader->otacsc_length)
|
|
{
|
|
memcpy(cmd0e + 138, reader->otacsc, reader->otacsc_length);
|
|
}
|
|
else
|
|
{
|
|
cmd0e[138] = 0x00;
|
|
cmd0e[139] = reader->cwpkota ? 0xFF : 0x00;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(reader->otpcsc_length)
|
|
{
|
|
memcpy(cmd0e + 136, reader->otpcsc, reader->otpcsc_length);
|
|
}
|
|
else
|
|
{
|
|
cmd0e[136] = 0x00;
|
|
cmd0e[137] = !reader->cwpkota ? cwekeycount : 0x00;
|
|
}
|
|
if(reader->otacsc_length)
|
|
{
|
|
memcpy(cmd0e + 138, reader->otacsc, reader->otacsc_length);
|
|
}
|
|
else
|
|
{
|
|
cmd0e[138] = 0x00;
|
|
cmd0e[139] = reader->cwpkota ? cwekeycount : 0x00;
|
|
}
|
|
}
|
|
char tmp[16];
|
|
rdr_log(reader, "OTP CSC No. of keys: %s", cs_hexdump(1, cmd0e + 136, 2, tmp, sizeof(tmp)));
|
|
rdr_log(reader, "OTA CSC No. of keys: %s", cs_hexdump(1, cmd0e + 138, 2, tmp, sizeof(tmp)));
|
|
}
|
|
|
|
if(reader->forcepair_length)
|
|
{
|
|
rdr_log(reader, "Forcing Pairing Type");
|
|
memcpy(cmd0e + 13, reader->forcepair, 1);
|
|
}
|
|
else
|
|
{
|
|
if(reader->hasunique == 1)
|
|
{
|
|
cmd0e[13] = 0x40;
|
|
}
|
|
}
|
|
|
|
memcpy(cmd0e + 14, reader->idird, 4);
|
|
memcpy(reader->irdId, reader->idird, 4);
|
|
|
|
if(reader->cmd0eprov_length)
|
|
{
|
|
memcpy(cmd0e + 18, reader->cmd0eprov, 2);
|
|
}
|
|
else
|
|
{
|
|
memcpy(cmd0e + 18, reader->prid[0] + 2, 2);
|
|
}
|
|
|
|
memcpy(cmd0e + 20, reader->key3588 + 24, 0x70);
|
|
|
|
if(reader->cak7_seq <= 15)
|
|
{
|
|
srand(time(NULL));
|
|
}
|
|
|
|
uint32_t data1r = rand() % 4294967294u;
|
|
reader->timestmp1[0] = (data1r >> 24) & 0xFF;
|
|
reader->timestmp1[1] = (data1r >> 16) & 0xFF;
|
|
reader->timestmp1[2] = (data1r >> 8) & 0xFF;
|
|
reader->timestmp1[3] = (data1r ) & 0xFF;
|
|
memcpy(cmd0e + 9, reader->timestmp1, 0x04);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->timestmp1, 4, "DATA1 CMD0E:");
|
|
rdr_log_dump_dbg(reader, D_READER, reader->prid[0], 4, "SysID:");
|
|
|
|
do_cak7_cmd(reader,cta_res, &cta_lr, cmd0e, sizeof(cmd0e), 0x20);
|
|
if(cta_lr == 0)
|
|
{
|
|
rdr_log(reader, "card is not responding to CMD02/E - check your data");
|
|
return ERROR;
|
|
}
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, 0x20, "Decrypted answer to CMD02/0E:");
|
|
|
|
reader->needrestart = (cta_res[22] << 16);
|
|
reader->needrestart += (cta_res[23] << 8);
|
|
reader->needrestart += (cta_res[24] );
|
|
reader->needrestart--;
|
|
if(reader->cak7_seq <= 15)
|
|
{
|
|
rdr_log(reader, "card needs FASTreinit after %d CMDs", reader->needrestart);
|
|
}
|
|
else
|
|
{
|
|
uint32_t cmdleft = reader->needrestart - reader->cak7_seq;
|
|
rdr_log(reader, "%d CMDs left to FASTreinit", cmdleft);
|
|
}
|
|
|
|
reader->dword_83DBC = (cta_res[18] << 24);
|
|
reader->dword_83DBC += (cta_res[19] << 16);
|
|
reader->dword_83DBC += (cta_res[20] << 8);
|
|
reader->dword_83DBC += (cta_res[21] );
|
|
calc_cak7_exponent(&reader->dword_83DBC, reader->cak7expo, 0x11);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->cak7expo, 0x11, "CAK7 Exponent:");
|
|
memcpy(reader->cardid, cta_res + 14, 4);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->cardid, 0x04, "CardSerial: ");
|
|
memcpy(reader->hexserial + 2, reader->cardid, 4);
|
|
|
|
unsigned long datal = (cta_res[9] << 24) + (cta_res[10] << 16) + (cta_res[11] << 8) + (cta_res[12]);
|
|
|
|
datal++;
|
|
reader->data2[0] = (datal >> 24) & 0xFF;
|
|
reader->data2[1] = (datal >> 16) & 0xFF;
|
|
reader->data2[2] = (datal >> 8) & 0xFF;
|
|
reader->data2[3] = (datal ) & 0xFF;
|
|
|
|
data1r++;
|
|
reader->timestmp2[0] = (data1r >> 24) & 0xFF;
|
|
reader->timestmp2[1] = (data1r >> 16) & 0xFF;
|
|
reader->timestmp2[2] = (data1r >> 8) & 0xFF;
|
|
reader->timestmp2[3] = (data1r ) & 0xFF;
|
|
|
|
memcpy(reader->ecmheader, cta_res + 18, 4);
|
|
|
|
if(reader->cak7_seq <= 15)
|
|
{
|
|
uint8_t mdc_hash2[MDC2_DIGEST_LENGTH];
|
|
uint8_t check2[0x78];
|
|
memset(check2, 0x00, 0x78);
|
|
memcpy(check2, reader->cardid, 4);
|
|
memcpy(check2 + 16, reader->kdt05_10, 0x68);
|
|
|
|
MDC2_CTX c2;
|
|
MDC2_Init(&c2);
|
|
MDC2_Update(&c2, check2, 0x78);
|
|
MDC2_Final(&(mdc_hash2[0]), &c2);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->ideakey1, 16, "IDEAKEY1: ");
|
|
rdr_log_dump_dbg(reader, D_READER, mdc_hash2, 16, "MDC_HASH: ");
|
|
|
|
if(memcmp(mdc_hash2 + 1, reader->ideakey1 + 1, 14) == 0)
|
|
{
|
|
rdr_log(reader, "DT05_10 is correct");
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "DT05_10 error - check MOD1");
|
|
}
|
|
}
|
|
|
|
rsa_decrypt(reader->data50, reader->data50_length, reader->data, reader->mod50, reader->mod50_length, reader->cak7expo, 0x11);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->timestmp2, 4, "DATA1 CMD03:");
|
|
memcpy(&reader->step1[0], d00ff, 4);
|
|
memcpy(&reader->step1[4], reader->data, 0x50);
|
|
memcpy(&reader->step1[4 + 0x50], reader->idird, 0x04);
|
|
memcpy(&reader->step1[4 + 4 + 0x50], reader->timestmp2, 0x04);
|
|
memcpy(&reader->step1[4 + 4 + 4 + 0x50], reader->data2, 0x04);
|
|
rdr_log_dump_dbg(reader, D_READER, reader->step1, sizeof(reader->step1), "STEP 1:");
|
|
|
|
reader->pairtype = cta_res[13];
|
|
if((reader->pairtype > 0x00) && (reader->pairtype < 0xC0))
|
|
{
|
|
rdr_log(reader,"Card is starting in GLOBAL mode");
|
|
if(!CAK7_cmd03_global(reader))
|
|
{
|
|
return ERROR;
|
|
}
|
|
}
|
|
else if(reader->pairtype == 0xC0)
|
|
{
|
|
rdr_log(reader,"Card is starting in UNIQUE mode");
|
|
if(!reader->mod2_length)
|
|
{
|
|
rdr_log(reader, "no mod2 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->key3460_length)
|
|
{
|
|
rdr_log(reader, "no key3460 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->key3310_length)
|
|
{
|
|
rdr_log(reader, "no key3310 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!CAK7_cmd03_unique(reader))
|
|
{
|
|
return ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "Unknown Pairing Type");
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t nagra3_card_init(struct s_reader *reader, ATR *newatr)
|
|
{
|
|
get_atr;
|
|
memset(reader->hexserial, 0, 8);
|
|
reader->cak7_seq = 0;
|
|
reader->hasunique = 0;
|
|
memset(reader->ecmheader, 0, 4);
|
|
cs_clear_entitlement(reader);
|
|
|
|
if(memcmp(atr + 8, "DNASP4", 6) == 0)
|
|
{
|
|
if((memcmp(atr + 8, "DNASP400", 8) == 0) && !reader->cak7_mode)
|
|
{
|
|
return ERROR;
|
|
}
|
|
else
|
|
{
|
|
memcpy(reader->rom, atr + 8, 15);
|
|
rdr_log(reader, "Rom revision: %.15s", reader->rom);
|
|
}
|
|
}
|
|
else if(memcmp(atr + 11, "DNASP4", 6) == 0)
|
|
{
|
|
memcpy(reader->rom, atr + 11, 15);
|
|
rdr_log(reader, "Rom revision: %.15s", reader->rom);
|
|
}
|
|
else
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
reader->nprov = 1;
|
|
/*reader->nsa = 0;
|
|
reader->nemm82u = 0;
|
|
reader->nemm84 = 0;
|
|
reader->nemm84s = 0;
|
|
reader->nemm83u = 0;
|
|
reader->nemm83s = 0;
|
|
reader->nemm87 = 0;*/
|
|
|
|
if(!reader->mod1_length)
|
|
{
|
|
rdr_log(reader, "no MOD1 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->key3588_length)
|
|
{
|
|
rdr_log(reader, "no key3588 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->data50_length)
|
|
{
|
|
rdr_log(reader, "no data50 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->mod50_length)
|
|
{
|
|
rdr_log(reader, "no mod50 defined");
|
|
return ERROR;
|
|
}
|
|
|
|
if(!reader->idird_length)
|
|
{
|
|
rdr_log(reader, "no idird defined");
|
|
return ERROR;
|
|
}
|
|
|
|
CAK7GetDataType(reader, SYSID_CAID);
|
|
CAK7GetDataType(reader, DT05);
|
|
if(!CAK7_GetCamKey(reader))
|
|
{
|
|
return ERROR;
|
|
}
|
|
CAK7GetDataType(reader, 0x09);
|
|
|
|
char tmp[4 * 3 + 1];
|
|
reader->nsa = 0;
|
|
reader->nemm82u = 0;
|
|
reader->nemm84 = 0;
|
|
reader->nemm84s = 0;
|
|
reader->nemm83u = 0;
|
|
reader->nemm83s = 0;
|
|
reader->nemm87 = 0;
|
|
CAK7GetDataType(reader, 0x04);
|
|
|
|
if(reader->forceemmg)
|
|
{
|
|
reader->emm82 = 1;
|
|
}
|
|
|
|
int i;
|
|
for(i = 1; i < reader->nprov; i++)
|
|
{
|
|
rdr_log(reader, "Prv.ID: %s", cs_hexdump(1, reader->prid[i], 4, tmp, sizeof(tmp)));
|
|
}
|
|
|
|
if(reader->cak7type != 3)
|
|
{
|
|
rdr_log(reader, "-----------------------------------------");
|
|
rdr_log(reader, "| EMM Filters (PRIVATE!!) |");
|
|
rdr_log(reader, "+---------------------------------------+");
|
|
if(reader->emm82 == 1)
|
|
{
|
|
rdr_log(reader, "|emm82 |");
|
|
}
|
|
char tmp7[48];
|
|
for(i = 0; i < reader->nemm84; i++)
|
|
{
|
|
rdr_log(reader, "|emm84 : %s |", cs_hexdump(1, reader->emm84[i], 3, tmp7, sizeof(tmp7)));
|
|
}
|
|
for(i = 0; i < reader->nemm83u; i++)
|
|
{
|
|
rdr_log(reader, "|emm83U: %s |", cs_hexdump(1, reader->emm83u[i], 6, tmp7, sizeof(tmp7)));
|
|
}
|
|
for(i = 0; i < reader->nemm83s; i++)
|
|
{
|
|
rdr_log(reader, "|emm83S: %s |", cs_hexdump(1, reader->emm83s[i], 6, tmp7, sizeof(tmp7)));
|
|
}
|
|
for(i = 0; i < reader->nemm87; i++)
|
|
{
|
|
rdr_log(reader, "|emm87 : %s |", cs_hexdump(1, reader->emm87[i], 6, tmp7, sizeof(tmp7)));
|
|
}
|
|
rdr_log(reader, "-----------------------------------------");
|
|
}
|
|
|
|
if(reader->cak7type != 1)
|
|
{
|
|
rdr_log(reader, "-----------------------------------------");
|
|
rdr_log(reader, "| EMM Filters (PRIVATE!!) |");
|
|
rdr_log(reader, "+---------------------------------------+");
|
|
if(reader->emm83 == 1)
|
|
{
|
|
rdr_log(reader, "|emm83 |");
|
|
}
|
|
char tmp7[48];
|
|
for(i = 0; i < reader->nemm82u; i++)
|
|
{
|
|
rdr_log(reader, "|emm82U: %s |", cs_hexdump(1, reader->emm82u[i], 7, tmp7, sizeof(tmp7)));
|
|
}
|
|
for(i = 0; i < reader->nemm84s; i++)
|
|
{
|
|
rdr_log(reader, "|emm84S: %s |", cs_hexdump(1, reader->emm84s[i], 6, tmp7, sizeof(tmp7)));
|
|
}
|
|
rdr_log(reader, "-----------------------------------------");
|
|
}
|
|
|
|
rdr_log(reader, "ready for requests");
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t nagra3_card_info(struct s_reader *reader)
|
|
{
|
|
char tmp[4 * 3 + 1];
|
|
|
|
rdr_log(reader, "ROM: %c %c %c %c %c %c %c %c", reader->rom[0], reader->rom[1], reader->rom[2], reader->rom[3], reader->rom[4], reader->rom[5], reader->rom[6], reader->rom[7]);
|
|
rdr_log(reader, "REV: %c %c %c %c %c %c", reader->rom[9], reader->rom[10], reader->rom[11], reader->rom[12], reader->rom[13], reader->rom[14]);
|
|
rdr_log_sensitive(reader, "SER: {%s}", cs_hexdump(1, reader->hexserial + 2, 4, tmp, sizeof(tmp)));
|
|
rdr_log(reader, "ECM CAID: %04X", reader->caid);
|
|
rdr_log(reader, "EMM CAID: %04X", reader->cak7_emm_caid);
|
|
rdr_log(reader, "Prv.ID: %s(sysid)", cs_hexdump(1, reader->prid[0], 4, tmp, sizeof(tmp)));
|
|
cs_clear_entitlement(reader); // reset the entitlements
|
|
rdr_log(reader, "-----------------------------------------");
|
|
rdr_log(reader, "|id |tier |valid from |valid to |");
|
|
rdr_log(reader, "+----+--------+------------+------------+");
|
|
CAK7GetDataType(reader, IRDINFO);
|
|
CAK7GetDataType(reader, TIERS);
|
|
rdr_log(reader, "-----------------------------------------");
|
|
struct timeb now;
|
|
cs_ftime(&now);
|
|
reader->last_refresh = now;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int32_t fastreinit(struct s_reader *reader)
|
|
{
|
|
ATR newatr[ATR_MAX_SIZE];
|
|
memset(newatr, 0, 1);
|
|
|
|
if(ICC_Async_Activate(reader, newatr, 0))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
reader->cak7_seq = 0;
|
|
|
|
if(!CAK7_GetCamKey(reader))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void nagra3_post_process(struct s_reader *reader)
|
|
{
|
|
if(reader->cak7_seq >= reader->needrestart)
|
|
{
|
|
rdr_log(reader, "card needs FASTreinit to prevent crash");
|
|
if(!fastreinit(reader))
|
|
{
|
|
rdr_log(reader, "FASTreinit failed - need to restart reader");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
}
|
|
else if((reader->cak7_camstate & 64) == 64)
|
|
{
|
|
rdr_log(reader, "negotiating new Session Key");
|
|
if(!CAK7_GetCamKey(reader))
|
|
{
|
|
rdr_log(reader, "negotiations failed - trying FASTreinit");
|
|
if(!fastreinit(reader))
|
|
{
|
|
rdr_log(reader, "FASTreinit failed - need to restart reader");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32_t nagra3_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
|
|
{
|
|
def_resp;
|
|
|
|
if(reader->cak7type == 3)
|
|
{
|
|
if(er->ecm[2] > 0x61 && er->ecm[7] == 0x5C && er->ecm[100] == 0x0B)
|
|
{
|
|
if(er->ecm[101] == 0x03 || er->ecm[101] == 0x04)
|
|
{
|
|
if(er->ecm[104] > reader->pairtype)
|
|
{
|
|
rdr_log(reader, "reinit card in Unique Pairing Mode");
|
|
return ERROR;
|
|
}
|
|
if(er->ecm[104] == 0x80 && reader->pairtype == 0x80)
|
|
{
|
|
rdr_log(reader, "reinit card in Unique Pairing Mode");
|
|
return ERROR;
|
|
}
|
|
}
|
|
if(er->ecm[101] == 0x04 && !reader->nuid_length)
|
|
{
|
|
rdr_log(reader, "reinit card with NUID");
|
|
return ERROR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(er->ecm[2] > 0x86 && er->ecm[4] == 0x84 && er->ecm[137] == 0x0B)
|
|
{
|
|
if(er->ecm[138] == 0x03 || er->ecm[138] == 0x04)
|
|
{
|
|
if(er->ecm[141] > reader->pairtype)
|
|
{
|
|
rdr_log(reader, "reinit card in Unique Pairing Mode");
|
|
return ERROR;
|
|
}
|
|
if(er->ecm[141] == 0x80 && reader->pairtype == 0x80)
|
|
{
|
|
rdr_log(reader, "reinit card in Unique Pairing Mode");
|
|
return ERROR;
|
|
}
|
|
}
|
|
if(er->ecm[138] == 0x04 && !reader->nuid_length)
|
|
{
|
|
rdr_log(reader, "reinit card with NUID");
|
|
return ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t ecmreq[0xC0];
|
|
memset(ecmreq, 0xCC, 0xC0);
|
|
ecmreq[7] = 0x05;
|
|
if(reader->headermode == 0)
|
|
{
|
|
ecmreq[ 9] = 0x00;
|
|
ecmreq[10] = 0x00;
|
|
ecmreq[11] = 0x00;
|
|
ecmreq[12] = 0x00;
|
|
ecmreq[13] = 0x00;
|
|
}
|
|
else if(reader->headermode == 1)
|
|
{
|
|
ecmreq[ 9] = 0x04;
|
|
ecmreq[10] = reader->ecmheader[0];
|
|
ecmreq[11] = reader->ecmheader[1];
|
|
ecmreq[12] = reader->ecmheader[2];
|
|
ecmreq[13] = reader->ecmheader[3];
|
|
}
|
|
|
|
if(reader->cak7type == 3)
|
|
{
|
|
ecmreq[8] = er->ecm[7] + 6;
|
|
memcpy(&ecmreq[14], er->ecm + 7, er->ecm[7] + 1);
|
|
}
|
|
else
|
|
{
|
|
ecmreq[8] = er->ecm[4] + 6;
|
|
memcpy(&ecmreq[14], er->ecm + 4, er->ecm[4] + 1);
|
|
}
|
|
|
|
if((er->ecm[2] == 0xAC) && (er->ecm[3] == 0x05))
|
|
{
|
|
ecmreq[15] = 0x0A;
|
|
}
|
|
|
|
do_cak7_cmd(reader, cta_res, &cta_lr, ecmreq, sizeof(ecmreq), 0xB0);
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, 0xB0, "Decrypted ECM Answer:");
|
|
|
|
if((cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 1] != 0x00) || cta_lr == 0)
|
|
{
|
|
rdr_log(reader, "(ECM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
else if(cta_res[27] != 0x00 && cta_res[27] != 0xCC)
|
|
{
|
|
memcpy(reader->ecmheader, cta_res + 9, 4);
|
|
reader->cak7_camstate = cta_res[4];
|
|
uint8_t _cwe0[8];
|
|
uint8_t _cwe1[8];
|
|
|
|
if(cta_res[78] == 0x01 || reader->forcecwswap)
|
|
{
|
|
memcpy(_cwe0, &cta_res[52], 0x08);
|
|
memcpy(_cwe1, &cta_res[28], 0x08);
|
|
}
|
|
else
|
|
{
|
|
memcpy(_cwe0, &cta_res[28], 0x08);
|
|
memcpy(_cwe1, &cta_res[52], 0x08);
|
|
}
|
|
|
|
if(cta_res[27] == 0x5C)
|
|
{
|
|
uint8_t cta_res144 = cta_res[144];
|
|
if(cta_res144 < 0x11)
|
|
{
|
|
if(!reader->cwekey_length[cta_res144])
|
|
{
|
|
rdr_log(reader, "ERROR: CWPK%d is not set, can not decrypt CW", cta_res[144]);
|
|
return ERROR;
|
|
}
|
|
des_ecb3_decrypt(_cwe0, reader->cwekey[cta_res144]);
|
|
des_ecb3_decrypt(_cwe1, reader->cwekey[cta_res144]);
|
|
rdr_log_dbg(reader, D_READER, "CW Decrypt ok");
|
|
}
|
|
}
|
|
else if(cta_res[27] == 0x58)
|
|
{
|
|
des_ecb3_decrypt(_cwe0, reader->key3des);
|
|
des_ecb3_decrypt(_cwe1, reader->key3des);
|
|
rdr_log_dbg(reader, D_READER, "CW Decrypt ok");
|
|
}
|
|
|
|
memcpy(ea->cw, _cwe0, 0x08);
|
|
memcpy(ea->cw + 8, _cwe1, 0x08);
|
|
return OK;
|
|
}
|
|
else if(cta_res[23] == 0x00)
|
|
{
|
|
memcpy(reader->ecmheader, cta_res + 9, 4);
|
|
reader->cak7_camstate = cta_res[4];
|
|
if(reader->hasunique && reader->pairtype < 0xC0)
|
|
{
|
|
rdr_log(reader, "reinit card in Unique Pairing Mode");
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "card has no right to decode this channel");
|
|
}
|
|
}
|
|
else if(cta_res[23] == 0x04)
|
|
{
|
|
if(!reader->nuid_length)
|
|
{
|
|
rdr_log(reader, "reinit card with NUID");
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "wrong OTP/OTA CSC values");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rdr_log(reader, "card got wrong ECM");
|
|
}
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
static int32_t nagra3_do_emm(struct s_reader *reader, EMM_PACKET *ep)
|
|
{
|
|
def_resp;
|
|
|
|
if(ep->emm[0] == 0x90)
|
|
{
|
|
rdr_log(reader, "OSCam got your BoxEMM");
|
|
char tmp[128];
|
|
rdr_log(reader, "NUID: %s", cs_hexdump(1, reader->nuid, 4, tmp, sizeof(tmp)));
|
|
rdr_log(reader, "Index: %s", cs_hexdump(1, ep->emm + 10, 1, tmp, sizeof(tmp)));
|
|
rdr_log(reader, "eCWPK: %s", cs_hexdump(1, ep->emm + 11, 16, tmp, sizeof(tmp)));
|
|
}
|
|
else
|
|
{
|
|
uint8_t emmreq[0xC0];
|
|
memset(emmreq, 0xCC, 0xC0);
|
|
emmreq[7] = 0x05;
|
|
if(reader->headermode == 0)
|
|
{
|
|
emmreq[ 9] = 0x00;
|
|
emmreq[10] = 0x00;
|
|
emmreq[11] = 0x00;
|
|
emmreq[12] = 0x00;
|
|
emmreq[13] = 0x00;
|
|
}
|
|
else if(reader->headermode == 1)
|
|
{
|
|
emmreq[ 9] = 0x04;
|
|
emmreq[10] = reader->ecmheader[0];
|
|
emmreq[11] = reader->ecmheader[1];
|
|
emmreq[12] = reader->ecmheader[2];
|
|
emmreq[13] = reader->ecmheader[3];
|
|
}
|
|
|
|
if(reader->cak7type == 3)
|
|
{
|
|
int32_t i;
|
|
uint8_t *prov_id_ptr;
|
|
|
|
switch(ep->type)
|
|
{
|
|
case SHARED:
|
|
emmreq[8] = ep->emm[9] + 6;
|
|
prov_id_ptr = ep->emm + 3;
|
|
memcpy(&emmreq[14], ep->emm + 9, ep->emm[9] + 1);
|
|
break;
|
|
|
|
case UNIQUE:
|
|
emmreq[8] = ep->emm[12] + 6;
|
|
prov_id_ptr = ep->emm + 9;
|
|
memcpy(&emmreq[14], ep->emm + 12, ep->emm[12] + 1);
|
|
break;
|
|
|
|
case GLOBAL:
|
|
emmreq[8] = ep->emm[6] + 6;
|
|
prov_id_ptr = ep->emm + 3;
|
|
memcpy(&emmreq[14], ep->emm + 6, ep->emm[6] + 1);
|
|
break;
|
|
|
|
default:
|
|
rdr_log(reader, "EMM: Congratulations, you have discovered a new EMM on Merlin.");
|
|
rdr_log(reader, "This has not been decoded yet.");
|
|
return ERROR;
|
|
}
|
|
|
|
i = get_prov_index(reader, prov_id_ptr);
|
|
if(i == -1)
|
|
{
|
|
rdr_log(reader, "EMM: skipped since provider id doesnt match");
|
|
return SKIPPED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
emmreq[8] = ep->emm[9] + 6;
|
|
memcpy(&emmreq[14], ep->emm + 9, ep->emm[9] + 1);
|
|
}
|
|
|
|
do_cak7_cmd(reader, cta_res, &cta_lr, emmreq, sizeof(emmreq), 0xB0);
|
|
rdr_log_dump_dbg(reader, D_READER, cta_res, 0xB0, "Decrypted EMM Answer:");
|
|
|
|
if((cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 1] != 0x00) || cta_lr == 0)
|
|
{
|
|
rdr_log(reader, "(EMM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
memcpy(reader->ecmheader, cta_res + 9, 4);
|
|
if(reader->cak7_seq >= reader->needrestart)
|
|
{
|
|
rdr_log(reader, "card needs FASTreinit to prevent crash");
|
|
if(!fastreinit(reader))
|
|
{
|
|
rdr_log(reader, "FASTreinit failed - need to restart reader");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
}
|
|
else if(cta_res[4] == 0x80)
|
|
{
|
|
rdr_log_dbg(reader, D_READER, "EMM forced card to reinit");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
else if(cta_res[13] == 0x02)
|
|
{
|
|
rdr_log_dbg(reader, D_READER, "Revision update - card reinit necessary");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
else if((cta_res[4] & 64) == 64)
|
|
{
|
|
rdr_log(reader, "negotiating new Session Key");
|
|
if(!CAK7_GetCamKey(reader))
|
|
{
|
|
rdr_log(reader, "negotiations failed - trying FASTreinit");
|
|
if(!fastreinit(reader))
|
|
{
|
|
rdr_log(reader, "FASTreinit failed - need to restart reader");
|
|
reader->card_status = CARD_NEED_INIT;
|
|
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
else if(cta_res[8] == 0x0E)
|
|
{
|
|
rdr_log_dbg(reader, D_READER, "card got wrong EMM");
|
|
return OK;
|
|
}
|
|
|
|
struct timeb now;
|
|
cs_ftime(&now);
|
|
int64_t gone_now = comp_timeb(&now, &reader->emm_last);
|
|
int64_t gone_refresh = comp_timeb(&reader->emm_last, &reader->last_refresh);
|
|
if(((gone_now > (int64_t)3600*1000) && (gone_now < (int64_t)365*24*3600*1000)) || ((gone_refresh > (int64_t)12*3600*1000) && (gone_refresh < (int64_t)365*24*3600*1000)))
|
|
{
|
|
reader->last_refresh = now;
|
|
add_job(reader->client, ACTION_READER_CARDINFO, NULL, 0); // refresh entitlement since it might have been changed!
|
|
}
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
const struct s_cardsystem reader_nagracak7 =
|
|
{
|
|
.desc = "nagra merlin",
|
|
.caids = (uint16_t[]){ 0x18, 0 },
|
|
.do_emm = nagra3_do_emm,
|
|
.do_ecm = nagra3_do_ecm,
|
|
.post_process = nagra3_post_process,
|
|
.card_info = nagra3_card_info,
|
|
.card_init = nagra3_card_init,
|
|
.get_emm_type = nagra_get_emm_type,
|
|
.get_emm_filter = nagra_get_emm_filter,
|
|
};
|
|
|
|
#endif
|