oscam-2.26.01-11942-802-wit.../reader-viaccess.c
2026-02-24 21:37:51 +00:00

2555 lines
85 KiB
C
Executable File

#include "globals.h"
#ifdef READER_VIACCESS
#include "oscam-aes.h"
#include "oscam-time.h"
#include "oscam-emm.h"
#include "reader-common.h"
#include "cscrypt/des.h"
#include "oscam-work.h"
typedef unsigned int uint;
typedef unsigned char byte;
struct geo_cache
{
uint32_t provid;
uint8_t geo[256];
uint8_t geo_len;
int32_t number_ecm;
};
struct viaccess_data
{
struct geo_cache last_geo;
uint8_t availkeys[CS_MAXPROV][16];
};
struct via_date
{
uint16_t day_s : 5;
uint16_t month_s : 4;
uint16_t year_s : 7;
uint16_t day_e : 5;
uint16_t month_e : 4;
uint16_t year_e : 7;
};
uint8_t N98Init = 0;
uint KeyS[132];
char SBoxInverse[] =
{
13, 3, 11, 0, 10, 6, 5, 12, 1, 14, 4, 7, 15, 9, 8, 2,
5, 8, 2, 14, 15, 6, 12, 3, 11, 4, 7, 9, 1, 13, 10, 0,
12, 9, 15, 4, 11, 14, 1, 2, 0, 3, 6, 13, 5, 8, 10, 7,
0, 9, 10, 7, 11, 14, 6, 13, 3, 5, 12, 2, 4, 8, 15, 1,
5, 0, 8, 3, 10, 9, 7, 14, 2, 12, 11, 6, 4, 15, 13, 1,
8, 15, 2, 9, 4, 1, 13, 14, 11, 6, 5, 3, 7, 12, 10, 0,
15, 10, 1, 13, 5, 3, 6, 0, 4, 9, 14, 7, 2, 12, 8, 11,
3, 0, 6, 13, 9, 14, 15, 8, 5, 12, 11, 7, 10, 1, 4, 2
};
static void parse_via_date(const uint8_t *buf, struct via_date *vd, int32_t fend)
{
uint16_t date;
date = (buf[0] << 8) | buf[1];
vd->day_s = date & 0x1f;
vd->month_s = (date >> 5) & 0x0f;
vd->year_s = (date >> 9) & 0x7f;
if(fend)
{
date = (buf[2] << 8) | buf[3];
vd->day_e = date & 0x1f;
vd->month_e = (date >> 5) & 0x0f;
vd->year_e = (date >> 9) & 0x7f;
}
}
struct emm_rass *find_rabuf(struct s_client *client, int32_t provid, uint8_t nano, int8_t add)
{
struct emm_rass *e;
LL_ITER it;
if(!client->ra_buf)
{
client->ra_buf = ll_create("client->ra_buf");
}
it = ll_iter_create(client->ra_buf);
while((e = ll_iter_next(&it)) != NULL)
{
if(!add && e->provid == provid && e->emmlen != 0)
{
return e;
}
if(add && e->provid == provid && e->emm[0] == nano)
{
return e;
}
}
if(!add)
{
return NULL;
}
if(!cs_malloc(&e, sizeof(struct emm_rass)))
{
return NULL;
}
e->provid = provid;
ll_append(client->ra_buf, e);
return e;
}
static void show_class(struct s_reader *reader, const char *p, uint32_t provid, const uint8_t *b, int32_t l)
{
int32_t i, j;
// b -> via date (4 uint8_ts)
b += 4;
l -= 4;
j = l - 1;
for(; j >= 0; j--)
{
for(i = 0; i < 8; i++)
{
if(b[j] & (1 << (i & 7)))
{
uint8_t cls;
struct via_date vd;
parse_via_date(b - 4, &vd, 1);
cls = (l - (j + 1)) * 8 + i;
if(p) // just show class info, dont add entitlement!
{
rdr_log(reader, "%sclass: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", p, cls,
vd.year_s + 1980, vd.month_s, vd.day_s,
vd.year_e + 1980, vd.month_e, vd.day_e);
}
else
{
rdr_log(reader, "class: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", cls,
vd.year_s + 1980, vd.month_s, vd.day_s,
vd.year_e + 1980, vd.month_e, vd.day_e);
//convert time:
time_t start_t, end_t;
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_year = vd.year_s + 80; //via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_s - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_s;
start_t = cs_timegm(&tm);
tm.tm_year = vd.year_e + 80; //via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_e - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_e;
end_t = cs_timegm(&tm);
cs_add_entitlement(reader, reader->caid, provid, cls, cls, start_t, end_t, 5, 1);
}
}
}
}
}
static int8_t add_find_class(struct s_reader *reader, uint32_t provid, const uint8_t *b, int32_t l, int8_t add)
{
int32_t i, j, freshdate = 0;
// b -> via date (4 uint8_ts)
b += 4;
l -= 4;
j = l - 1;
for(; j >= 0; j--)
{
for(i = 0; i < 8; i++)
{
if(b[j] & (1 << (i & 7)))
{
uint8_t cls;
cls = (l - (j + 1)) * 8 + i;
if(cs_add_entitlement(reader, reader->caid, provid, cls, cls, 0, 0, 5, 0) == NULL && !add)
{
rdr_log(reader, "provid %06X class %02X not found", provid, cls);
freshdate = 1;
}
else
{
if(!add)
{
rdr_log(reader, "provid %06X has matching class %02X", provid, cls);
}
struct via_date vd;
parse_via_date(b - 4, &vd, 1);
time_t start_t, end_t;
struct tm tm;
//convert time:
memset(&tm, 0, sizeof(tm));
tm.tm_year = vd.year_s + 80; // via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_s - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_s;
start_t = cs_timegm(&tm);
tm.tm_year = vd.year_e + 80; //via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_e - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_e;
end_t = cs_timegm(&tm);
if(cs_add_entitlement(reader, reader->caid, provid, cls, cls, start_t, end_t, 5, add) != NULL)
{
if(!add)
{
rdr_log(reader, "class %02X provid %06X has already this daterange or newer entitled", cls, provid);
}
}
else
{
freshdate = 1;
}
}
}
}
}
if(freshdate == 0)
{
return -2;
}
return 1; // emmdate is fresh!
}
static void show_subs(struct s_reader *reader, const uint8_t *emm)
{
switch(emm[0])
{
case 0xA9:
{
show_class(reader, "nano A9: ", 1, emm + 2, emm[1]);
break;
}
case 0xA6:
{
char szGeo[256];
memset(szGeo, 0, 256);
cs_strncpy(szGeo, (char *)emm + 2, emm[1]);
rdr_log(reader, "nano A6: geo %s", szGeo);
break;
}
case 0xB6:
{
uint8_t m; // modexp
struct via_date vd;
m = emm[emm[1] + 1];
parse_via_date(emm + 2, &vd, 0);
rdr_log(reader, "nano B6: modexp %d%d%d%d%d%d: %02d/%02d/%04d",
(m & 0x20) ? 1 : 0,
(m & 0x10) ? 1 : 0,
(m & 0x08) ? 1 : 0,
(m & 0x04) ? 1 : 0,
(m & 0x02) ? 1 : 0,
(m & 0x01) ? 1 : 0,
vd.day_s, vd.month_s, vd.year_s + 1980);
break;
}
}
}
static int32_t chk_prov(struct s_reader *reader, uint8_t *id, uint8_t keynr)
{
struct viaccess_data *csystem_data = reader->csystem_data;
int32_t i, j, rc;
for(rc = i = 0; (!rc) && (i < reader->nprov); i++)
{
if(!memcmp(&reader->prid[i][1], id, 3))
{
for(j = 0; (!rc) && (j < 16); j++)
{
if(csystem_data->availkeys[i][j] == keynr)
{
rc = 1;
}
}
}
}
return (rc);
}
static int32_t get_maturity(struct s_reader *reader)
{
/* retrieve maturity rating on the card */
def_resp;
uint8_t insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
uint8_t insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
insac[2] = 0x06;
write_cmd(insac, NULL); // request maturity rating
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read maturity rating nano + len
insb8[4] = cta_res[1];
write_cmd(insb8, NULL); // read maturity rating
reader->maturity = cta_res[cta_lr - 3] & 0x0F;
if (reader->maturity < 0xF)
{
rdr_log(reader, "Maturity level [%X]= older than %i years", reader->maturity, reader->maturity);
}
else
{
rdr_log(reader, "Maturity level [%X]=no age limit", reader->maturity);
}
return 0;
}
static int32_t unlock_parental(struct s_reader *reader)
{
/* disabling parental lock. assuming pin "0000" if no pin code is provided in the config */
static const uint8_t inDPL[] = { 0xca, 0x24, 0x02, 0x00, 0x09 };
uint8_t cmDPL[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F };
def_resp;
if(strcmp(reader->pincode, "none"))
{
rdr_log(reader, "Using PIN %s", reader->pincode);
// the pin need to be coded in bcd, so we need to convert from ascii to bcd, so '1234' -> 0x12 0x34
cmDPL[6] = ((reader->pincode[0] - 0x30) << 4) | ((reader->pincode[1] - 0x30) & 0x0f);
cmDPL[7] = ((reader->pincode[2] - 0x30) << 4) | ((reader->pincode[3] - 0x30) & 0x0f);
}
else
{
rdr_log(reader, "Using PIN 0000!");
}
write_cmd(inDPL, cmDPL);
if(!(cta_res[cta_lr - 2] == 0x90 && cta_res[cta_lr - 1] == 0))
{
if(strcmp(reader->pincode, "none"))
{
rdr_log(reader, "Can't disable parental lock. Wrong PIN? OSCam used %s!", reader->pincode);
}
else
{
rdr_log(reader, "Can't disable parental lock. Wrong PIN? OSCam used 0000!");
}
}
else
{
rdr_log(reader, "Parental lock disabled");
get_maturity(reader);
}
return 0;
}
int32_t hdSurEncBasicCrypt_D2_0F_11(int32_t Value, int32_t XorVal)
{
int32_t i = (Value << 13) - Value + 0x1B59;
i = (i * Value) + 0x07CF;
return (i ^ XorVal);
}
int32_t hdSurEncCryptLookup_D2_0F_11(uint8_t Value, uint8_t AddrInd)
{
static const uint8_t lookup[] =
{
0x94, 0xB2, 0xA9, 0x79, 0xC4, 0xC7, 0x0D, 0x36, 0x6F, 0x24, 0x11, 0xD1, 0xDB, 0x59, 0xD2, 0xA5,
0xE1, 0x00, 0xD4, 0x97, 0xA3, 0x2B, 0x11, 0xFA, 0x5F, 0xF1, 0xC1, 0x44, 0xBF, 0x9B, 0x5A, 0xC8,
0xF1, 0xE1, 0x99, 0x82, 0x0E, 0xB2, 0x01, 0x09, 0x0C, 0xC8, 0xB3, 0x3B, 0xD1, 0x80, 0x50, 0xE8,
0xF5, 0x52, 0x4C, 0xE6, 0x82, 0xAC, 0x58, 0x40, 0xD4, 0x71, 0x87, 0x52, 0x06, 0xEA, 0xA6, 0x27,
0xB7, 0xFE, 0x6C, 0x49, 0x47, 0x3B, 0x70, 0x6C, 0xEB, 0xCD, 0xC5, 0x0B, 0x8C, 0x31, 0x29, 0x42,
0x4E, 0x10, 0x2B, 0x2D, 0x46, 0xEC, 0x39, 0xA3, 0x90, 0x4B, 0x25, 0x60, 0x9C, 0x62, 0xD4, 0x20,
0xF6, 0x16, 0xA8, 0x9C, 0xE4, 0x20, 0xED, 0xC7, 0xBA, 0x5E, 0xB6, 0x4E, 0x03, 0x15, 0xA6, 0xF6,
0x23, 0x98, 0x32, 0xC0, 0xAE, 0xA3, 0xFD, 0xD3, 0x7F, 0xF8, 0xED, 0xF0, 0x29, 0x29, 0x12, 0xB3,
0xB7, 0x58, 0xAD, 0xA2, 0x58, 0x2C, 0x70, 0x1B, 0xA4, 0x25, 0xE8, 0xA5, 0x43, 0xF1, 0xB9, 0x8F,
0x1E, 0x3B, 0x10, 0xDF, 0x52, 0xFE, 0x58, 0x29, 0xAD, 0x3F, 0x99, 0x4D, 0xDF, 0xD2, 0x08, 0x06,
0xA1, 0x1C, 0x66, 0x29, 0x26, 0x80, 0x52, 0x8A, 0x5A, 0x73, 0xE7, 0xDF, 0xC1, 0xC4, 0x47, 0x82,
0xAB, 0x5C, 0x32, 0xAE, 0x96, 0x04, 0x2B, 0xC3, 0x2D, 0x5A, 0xD2, 0xB0, 0x64, 0x88, 0x97, 0xBF,
0x7E, 0x99, 0x60, 0xCC, 0x63, 0x76, 0x66, 0xE9, 0x9A, 0x3D, 0xBB, 0xF7, 0x7F, 0xE4, 0x7C, 0x3F,
0xB8, 0x4D, 0x10, 0x8D, 0x2A, 0xEA, 0x3C, 0xD3, 0x03, 0x74, 0xE6, 0x46, 0xC0, 0x29, 0xAE, 0xB0,
0x79, 0xBE, 0xCB, 0x18, 0x34, 0xBE, 0x5A, 0xE9, 0x19, 0x8F, 0xA3, 0x8F, 0xD6, 0x6A, 0x6C, 0x88,
0x1E, 0x21, 0x08, 0x15, 0xC4, 0xE7, 0xE6, 0xBA, 0x97, 0x9C, 0x4F, 0x89, 0x9F, 0x1A, 0x67, 0x4F,
0xC0, 0xD5, 0x72, 0x51, 0x16, 0xB4, 0xD3, 0x8A, 0x1F, 0xE3, 0x92, 0x02, 0x7F, 0x59, 0x56, 0x8F,
0x07, 0x8D, 0xC1, 0xC2, 0x42, 0x69, 0x3C, 0xA6, 0xBF, 0x3D, 0xDF, 0x0D, 0xAA, 0x4F, 0x7E, 0x80,
0x07, 0x11, 0xE2, 0x94, 0x19, 0x9B, 0x16, 0x26, 0x1A, 0x46, 0x09, 0x0D, 0xB5, 0xB8, 0x8E, 0x01,
0x9C, 0xFE, 0x09, 0xB3, 0x60, 0xC2, 0xAE, 0x50, 0x3C, 0x68, 0x75, 0x4A, 0x57, 0xD8, 0x4F, 0xD7,
0xA2, 0x76, 0x2C, 0xC1, 0xA2, 0x23, 0xBC, 0x54, 0x2A, 0xDD, 0xF3, 0xDD, 0xA7, 0x34, 0xF7, 0x5C,
0xF4, 0x86, 0x23, 0x48, 0x7C, 0x3F, 0x05, 0x40, 0x0E, 0xB0, 0xE5, 0xEB, 0x3E, 0xDF, 0x6A, 0x83,
0x65, 0xA0, 0xB2, 0x06, 0xD1, 0x40, 0x79, 0x0D, 0xDE, 0x95, 0x84, 0x96, 0x87, 0x6F, 0xCE, 0x48,
0x24, 0x13, 0x0B, 0xF5, 0xC7, 0xF5, 0xA8, 0x7F, 0x2E, 0xC7, 0xE1, 0xBA, 0xAE, 0x2B, 0xF7, 0xF0,
0x8E, 0xF7, 0x54, 0x0B, 0xF0, 0xD2, 0x41, 0x81, 0x68, 0x3B, 0x1E, 0x35, 0xAB, 0xD9, 0x2B, 0x46,
0x57, 0xE8, 0x53, 0xDF, 0xDE, 0x10, 0xEF, 0xCB, 0x4C, 0xE0, 0x52, 0x18, 0x2C, 0x4E, 0xB9, 0x20,
0xE9, 0x7E, 0x85, 0xDF, 0x75, 0x32, 0xE6, 0x10, 0xE9, 0x9C, 0x7B, 0x2E, 0x4C, 0xDA, 0x46, 0xE6,
0xCC, 0x77, 0x36, 0x1D, 0x4A, 0x15, 0xF5, 0x32, 0x18, 0x6B, 0x7E, 0xAA, 0xCC, 0x97, 0xCC, 0xD1,
0x2F, 0xE5, 0x58, 0x03, 0x35, 0x35, 0x3D, 0xA0, 0x2B, 0x13, 0x3A, 0x65, 0xFF, 0x24, 0x72, 0xCF,
0xA7, 0x6D, 0x52, 0x55, 0xF6, 0xC2, 0x30, 0x23, 0x7D, 0x9B, 0x9E, 0xB0, 0x94, 0x02, 0xAD, 0x60,
0x8A, 0x9F, 0xBC, 0xC8, 0xE4, 0x2B, 0x92, 0x96, 0xF5, 0xAE, 0x04, 0xA4, 0x33, 0x0C, 0x90, 0x67,
0xF0, 0xB9, 0x1E, 0x7E, 0xBE, 0x02, 0x18, 0xB2, 0x03, 0xB6, 0x40, 0xBF, 0x05, 0xE3, 0x76, 0x98,
0x21, 0x38, 0xC9, 0x5F, 0xD3, 0x51, 0x8B, 0x43, 0x0B, 0x1A, 0x0B, 0xF9, 0x3C, 0x21, 0x6C, 0x3D,
0xB8, 0xA0, 0x57, 0xCA, 0x68, 0xCD, 0x1E, 0xD2, 0x2C, 0x50, 0xEE, 0xC0, 0xDF, 0x25, 0x88, 0x52,
0x37, 0xE1, 0x44, 0xC6, 0x76, 0x3B, 0x91, 0x95, 0x86, 0x76, 0x87, 0x49, 0x21, 0x93, 0x44, 0x0A,
0x52, 0xB9, 0x2D, 0x2B, 0xE3, 0x1D, 0xB0, 0xE4, 0x98, 0xC6, 0xEE, 0x3D, 0x96, 0x53, 0x4B, 0xFF,
0x39, 0x00, 0xD5, 0x42, 0x7E, 0xE1, 0x4C, 0x6F, 0xD5, 0xB7, 0xE6, 0x99, 0x2A, 0x5B, 0x67, 0xEE,
0x3E, 0xBA, 0xF7, 0xEC, 0x43, 0x2A, 0x1C, 0xB6, 0xB5, 0x04, 0x26, 0x59, 0xB1, 0x4C, 0x17, 0xCC,
0x83, 0xB9, 0x00, 0x3E, 0x36, 0x91, 0x90, 0xF7, 0x5E, 0x38, 0xDC, 0xE4, 0x15, 0xC7, 0x67, 0xF0,
0xCA, 0xC8, 0xD2, 0x91, 0x5D, 0x74, 0xAC, 0x97, 0x56, 0x36, 0x1A, 0x82, 0x0A, 0xAA, 0xB4, 0x4E,
0xBF, 0x29, 0x5C, 0xBF, 0x58, 0xB3, 0x97, 0xF9, 0xEB, 0x7C, 0x85, 0xB4, 0xA5, 0x13, 0x2F, 0xD1,
0xDE, 0x1C, 0xEC, 0x97, 0xDD, 0xE2, 0x39, 0xE4, 0xFB, 0x0A, 0x02, 0xE0, 0xC3, 0xBA, 0x39, 0x79,
0xAA, 0x1C, 0x37, 0x75, 0x25, 0x54, 0xBE, 0x85, 0x74, 0x2C, 0xFA, 0x0C, 0xFA, 0x50, 0xF6, 0xBE,
0x9F, 0x2A, 0x53, 0x7C, 0x27, 0x46, 0x68, 0x2D, 0x74, 0x2B, 0x46, 0xDA, 0xF5, 0x07, 0x95, 0x09,
0x6A, 0x91, 0xB7, 0xB1, 0x34, 0x07, 0x5F, 0xEA, 0xBE, 0x0F, 0x87, 0x28, 0x68, 0x97, 0x43, 0x77,
0xD5, 0x38, 0x2B, 0x11, 0x11, 0x4F, 0xD9, 0x75, 0x5E, 0xE1, 0x06, 0xA0, 0x3B, 0xAC, 0x32, 0xFE,
0xBF, 0x73, 0x59, 0x5B, 0xA2, 0xA8, 0x7E, 0x10, 0x4C, 0x6E, 0x78, 0xF0, 0x4A, 0x4E, 0x95, 0xD6,
0xDD, 0x05, 0x7A, 0xBB, 0xF1, 0xEB, 0xA8, 0xA4, 0x5D, 0x91, 0xF0, 0xED, 0xDB, 0xB8, 0x01, 0x41,
0xF8, 0x97, 0x7F, 0xC3, 0x91, 0x53, 0xBF, 0xE9, 0xEA, 0x33, 0x1F, 0xDC, 0xA6, 0xE6, 0x8D, 0xCB,
0x75, 0xD0, 0x69, 0xD0, 0xA4, 0x59, 0xA5, 0x02, 0xFC, 0x60, 0x0D, 0x6A, 0xA0, 0x05, 0x1A, 0x54,
0x8A, 0xA7, 0x57, 0xA3, 0xF0, 0x90, 0x8A, 0xD5, 0x6F, 0x1E, 0x2E, 0x10, 0x9A, 0x93, 0x2B, 0x51,
0x2C, 0xFD, 0x99, 0xE5, 0x9B, 0x5D, 0xB2, 0xA7, 0x37, 0x99, 0x26, 0x35, 0xCA, 0xDD, 0x22, 0x19,
0x59, 0x2A, 0xB0, 0x99, 0x23, 0xDF, 0xA7, 0xA9, 0x85, 0x12, 0xCF, 0xBF, 0xFC, 0x74, 0x80, 0x87,
0xE1, 0x97, 0xD0, 0xF9, 0xEF, 0x5F, 0x1B, 0x45, 0xF7, 0x76, 0xDB, 0x66, 0x39, 0x05, 0x43, 0x06,
0xA9, 0x9F, 0x2E, 0x14, 0x9F, 0x1C, 0x0C, 0x1F, 0xD5, 0xD9, 0xA4, 0x8D, 0x18, 0x6F, 0x08, 0x53,
0x0B, 0x92, 0x9A, 0x0C, 0xEA, 0x4C, 0xE4, 0x1D, 0x9E, 0x9A, 0x51, 0xB8, 0x7E, 0x2D, 0xE7, 0x3C,
0xFF, 0x84, 0x5C, 0xBF, 0x8F, 0x8C, 0x89, 0x09, 0x1B, 0x7E, 0x4B, 0xE7, 0x85, 0xEC, 0x04, 0xB5,
0x20, 0x18, 0x1E, 0x55, 0xD5, 0x5B, 0xAC, 0xC6, 0x25, 0x5A, 0xA1, 0x81, 0xC1, 0x31, 0x9C, 0xF5,
0xB5, 0x54, 0x07, 0x65, 0x0A, 0x5B, 0x90, 0x06, 0x4F, 0x84, 0xB2, 0x7F, 0xD1, 0xAD, 0x16, 0x81,
0x25, 0xAF, 0xAF, 0xE2, 0x03, 0xA9, 0x1F, 0x13, 0x02, 0x5D, 0x54, 0x89, 0xCD, 0x44, 0x51, 0xEB,
0xA4, 0x2B, 0xBD, 0x47, 0xB0, 0xB6, 0x27, 0x1D, 0x9B, 0x14, 0x6F, 0xBF, 0xCD, 0x59, 0xBC, 0x0A,
0x37, 0xA8, 0x74, 0x7D, 0x16, 0x90, 0x28, 0xD5, 0x94, 0xC3, 0xE4, 0x23, 0xC4, 0x98, 0x91, 0xCE,
0x55, 0xBD, 0x21, 0x3B, 0x84, 0xBD, 0x44, 0x3C, 0xF9, 0xCD, 0x37, 0x43, 0x4A, 0xC6, 0x8C, 0x23,
0x04, 0x28, 0x63, 0x7A, 0x03, 0x85, 0xD2, 0x46, 0x93, 0xCA, 0xFE, 0xC3, 0x83, 0x0B, 0x13, 0xCC,
0x5D, 0xCB, 0xBA, 0xCA, 0x68, 0xAB, 0x05, 0xF7, 0xEC, 0x4A, 0x9C, 0x0F, 0xD5, 0xC4, 0x5A, 0xA5,
0xA0, 0x04, 0x41, 0x6A, 0xF6, 0xEF, 0x16, 0x9B, 0x69, 0x38, 0xF6, 0x2D, 0xAA, 0xEB, 0x2D, 0xE2,
0x82, 0xA2, 0x9F, 0x6F, 0xBD, 0x2A, 0xE3, 0x66, 0x6B, 0x21, 0xDA, 0x56, 0xAD, 0x82, 0x2B, 0x93,
0xF3, 0x25, 0xEA, 0xFC, 0xFD, 0xFD, 0x1B, 0xA9, 0xFC, 0xB8, 0xC6, 0x98, 0x45, 0xF2, 0x70, 0x03,
0x4A, 0x9C, 0x60, 0x82, 0x65, 0xB6, 0x68, 0x4C, 0xE7, 0x41, 0x10, 0x9D, 0x59, 0x40, 0x03, 0x02,
0x07, 0x12, 0x33, 0xAF, 0x79, 0xE1, 0xC4, 0xEB, 0xB8, 0xCE, 0x6A, 0x90, 0x72, 0x61, 0x5D, 0x56,
0xC7, 0x59, 0x31, 0xCB, 0x45, 0x2D, 0x42, 0x9F, 0x10, 0x1D, 0x09, 0x63, 0x59, 0x8C, 0x6C, 0xDB,
0x11, 0xCF, 0xA1, 0xDF, 0x5F, 0x4D, 0xDF, 0xB4, 0xC3, 0x82, 0xEE, 0x58, 0x16, 0xB4, 0x74, 0xFA,
0xBE, 0x11, 0x9C, 0x1E, 0x98, 0x29, 0xDE, 0xE3, 0xE5, 0x9E, 0xCF, 0xD7, 0x91, 0x0A, 0xA3, 0xA4,
0x42, 0xA1, 0x95, 0x09, 0x9E, 0x16, 0xD5, 0xA8, 0x24, 0x56, 0x5B, 0x23, 0xC8, 0x56, 0x4C, 0xCB,
0x89, 0x18, 0x69, 0xEB, 0x0C, 0x1F, 0xC0, 0x41, 0x5C, 0x63, 0x04, 0x68, 0xB2, 0x0F, 0x3F, 0x88,
0x36, 0xDD, 0x23, 0x4D, 0x4C, 0xC0, 0x81, 0xE3, 0xE9, 0xAD, 0xE0, 0x27, 0xD5, 0xE5, 0x46, 0xEB,
0xFF, 0x32, 0xA2, 0xB7, 0x14, 0x64, 0x0B, 0x6D, 0x1B, 0xE5, 0xD8, 0xAE, 0x9D, 0xE8, 0x55, 0xB9,
0x52, 0x70, 0x59, 0xB8, 0x72, 0x92, 0x69, 0x37, 0x95, 0x61, 0x0A, 0xE5, 0xF6, 0x55, 0x97, 0x1D,
0xBF, 0xF7, 0x29, 0x77, 0x0F, 0x72, 0x80, 0xB2, 0x7E, 0x56, 0xBF, 0xFD, 0xE9, 0xF5, 0x9B, 0x62,
0xE9, 0xBD, 0x0B, 0xC2, 0x07, 0x55, 0x31, 0x4C, 0x57, 0x3A, 0x05, 0xB9, 0x27, 0x41, 0x4A, 0xC3,
0xEC, 0x72, 0x20, 0xB3, 0x0C, 0xF9, 0xD9, 0x3A, 0x14, 0x6A, 0x03, 0x44, 0x6A, 0xF1, 0x41, 0x55,
0x7F, 0x81, 0xC2, 0x04, 0xA8, 0x05, 0xB9, 0x49, 0x2E, 0x43, 0xC4, 0x00, 0x87, 0x86, 0x04, 0xAC,
0xAF, 0x73, 0x78, 0x0E, 0xA4, 0x43, 0x5B, 0x36, 0xA2, 0x8F, 0x9C, 0xF7, 0x66, 0x4A, 0x5A, 0x09,
0x6B, 0xAA, 0x69, 0x6F, 0xB1, 0x20, 0x0D, 0x56, 0x85, 0x0A, 0x5E, 0x06, 0xBF, 0xE2, 0x32, 0xB4,
0x5C, 0x46, 0x33, 0x0D, 0x27, 0xA3, 0x6B, 0xE1, 0xB2, 0x6A, 0x7D, 0x4A, 0xA7, 0x81, 0x0F, 0x2B,
0x16, 0x7C, 0x51, 0xD6, 0xC0, 0x3D, 0xB9, 0xFE, 0xB4, 0x66, 0xC4, 0xB6, 0x54, 0x53, 0x67, 0xDA,
0x70, 0x96, 0x9A, 0x0A, 0x07, 0x1A, 0x26, 0xBA, 0x85, 0x50, 0xF5, 0x27, 0x53, 0x9C, 0x3A, 0x94,
0x0A, 0x7D, 0xDB, 0xE1, 0xC3, 0xE3, 0x6A, 0x3E, 0x9E, 0xD5, 0x13, 0x0A, 0xA3, 0xD2, 0x21, 0x75,
0x79, 0x17, 0x26, 0xAC, 0x48, 0x5F, 0x3D, 0xE1, 0x7D, 0xA4, 0xB1, 0x56, 0x0F, 0x92, 0x2C, 0x60,
0xE6, 0xCB, 0x87, 0x35, 0xB8, 0x75, 0xC3, 0xA2, 0x03, 0x50, 0x4B, 0xA2, 0x6E, 0x01, 0xE1, 0xDD,
0x87, 0xA5, 0x33, 0xC6, 0x2F, 0xA2, 0x41, 0xFC, 0x72, 0x98, 0xA2, 0x69, 0x4C, 0x3F, 0xF0, 0x53,
0xF5, 0x41, 0x2B, 0x23, 0x24, 0x3B, 0xCE, 0x9D, 0x39, 0x31, 0x17, 0x08, 0xE1, 0x3F, 0x5F, 0xFB,
0x00, 0xFA, 0xF1, 0xE3, 0xE1, 0x7B, 0x0C, 0xDF, 0x8D, 0xA2, 0xC4, 0xCD, 0x62, 0x3D, 0xAE, 0xC7,
0x48, 0x09, 0x1C, 0x66, 0xCB, 0x0E, 0x23, 0xE8, 0x1B, 0x9F, 0x1B, 0xCB, 0xF8, 0x14, 0xC3, 0x34,
0x91, 0x32, 0x2B, 0x39, 0x1C, 0xBA, 0x1C, 0xA0, 0x19, 0xF2, 0x57, 0x9D, 0x78, 0x00, 0x55, 0x1F,
0x15, 0x12, 0x9A, 0xA2, 0xF2, 0xC2, 0xB7, 0x4E, 0xEA, 0x46, 0x01, 0xC2, 0xE9, 0x76, 0xBF, 0xDE,
0xCF, 0x8B, 0xC7, 0x50, 0x80, 0xEE, 0x46, 0x91, 0x93, 0x1E, 0x5C, 0x48, 0x5D, 0xC8, 0xC8, 0x63,
0xD1, 0x89, 0x02, 0x29, 0xE9, 0x90, 0x9F, 0x0B, 0x0A, 0x1A, 0x44, 0x17, 0xE7, 0x4E, 0xAD, 0x58,
0x55, 0xF8, 0x38, 0xF6, 0x4F, 0xD8, 0x1C, 0x7E, 0x25, 0x9B, 0x59, 0x16, 0xBC, 0x65, 0x24, 0xC5,
0xA7, 0x56, 0xE5, 0x20, 0x3F, 0xD9, 0x27, 0xE0, 0x32, 0x24, 0xE1, 0x7B, 0xE1, 0x32, 0xEA, 0xF4,
0xFE, 0xD9, 0xA5, 0xFF, 0x35, 0xAE, 0xA9, 0x1B, 0x38, 0x28, 0x6A, 0xC0, 0x1A, 0x42, 0xD9, 0x5E,
0x14, 0x2C, 0xC2, 0x2D, 0x9B, 0x94, 0x5B, 0xCF, 0x83, 0x30, 0xB9, 0x06, 0xAF, 0x4B, 0xD7, 0xF6,
0x38, 0x7C, 0xFF, 0xB4, 0xA5, 0x1A, 0xA0, 0xE9, 0xF3, 0x01, 0xE3, 0x97, 0xC4, 0xA9, 0x57, 0xF5,
0xB9, 0x96, 0xA7, 0xA3, 0xB8, 0x10, 0x0E, 0xFB, 0x1D, 0x39, 0x44, 0x16, 0x97, 0x94, 0x3E, 0x5F,
0xAF, 0x0F, 0xE3, 0x99, 0xDC, 0xA0, 0xE9, 0x8D, 0x26, 0x2B, 0xD9, 0xAE, 0xEC, 0x4C, 0x4F, 0x09,
0x86, 0x7E, 0x7B, 0xC3, 0xE3, 0xC6, 0x17, 0xAE, 0x30, 0x9C, 0x31, 0xD1, 0x84, 0x47, 0xAF, 0xCB,
0xEA, 0x69, 0x2A, 0x08, 0x3E, 0x13, 0x00, 0xDE, 0xF6, 0x4A, 0x42, 0xD3, 0xBE, 0x33, 0xD9, 0x50,
0x6B, 0x8D, 0x59, 0x12, 0x1A, 0xD3, 0xA7, 0x7C, 0x0A, 0xE7, 0x87, 0x47, 0xCA, 0xAA, 0x33, 0xFD,
0xC1, 0xF6, 0x28, 0xC1, 0x62, 0xA2, 0x4C, 0x79, 0x83, 0x48, 0x86, 0x0E, 0xA4, 0x67, 0x34, 0x95,
0xAE, 0x7D, 0xD6, 0xEE, 0x91, 0x05, 0x35, 0x91, 0xE8, 0x34, 0x39, 0xA3, 0xE5, 0xE6, 0x80, 0x53,
0x76, 0x1F, 0x94, 0xA0, 0xF6, 0xA5, 0x41, 0x79, 0x82, 0xD3, 0xB0, 0x1F, 0xCE, 0xE1, 0x86, 0x64,
0x65, 0x0C, 0x8D, 0xD6, 0xFA, 0xC1, 0x10, 0x6C, 0x07, 0xD5, 0xF0, 0x77, 0x65, 0xB9, 0x0C, 0xBD,
0xAE, 0x2D, 0x62, 0x6C, 0x42, 0x7E, 0x2A, 0xBE, 0x5F, 0xC1, 0x17, 0x3B, 0x07, 0xFF, 0x5E, 0xD7,
0x31, 0x52, 0x26, 0x2F, 0x9F, 0x12, 0xD8, 0x2E, 0xA3, 0xF5, 0xB5, 0xD2, 0xFC, 0x6E, 0x08, 0x1F,
0xC8, 0x93, 0xA1, 0xEB, 0xF9, 0x13, 0x1D, 0x1F, 0x98, 0x5E, 0xB0, 0x0C, 0x65, 0x6C, 0xAE, 0x07,
0x78, 0xF8, 0x12, 0xD2, 0xD1, 0x1E, 0x77, 0x5C, 0x24, 0x62, 0xE5, 0x94, 0xD6, 0x6A, 0x8E, 0xD0,
0x72, 0x59, 0xDA, 0x48, 0x38, 0x2F, 0x31, 0x75, 0x0C, 0x52, 0xF0, 0x0C, 0x8F, 0x5C, 0xE9, 0x5E,
0x5A, 0x94, 0xE8, 0xD2, 0x80, 0xF8, 0x4F, 0xE7, 0xAA, 0x6C, 0xBE, 0x47, 0xFB, 0xDD, 0x57, 0x0A,
0xD8, 0x5E, 0xCC, 0x0D, 0x8F, 0x42, 0x5E, 0xDC, 0x5D, 0x95, 0x95, 0x60, 0x9B, 0x6F, 0x05, 0x5E,
0x08, 0x45, 0x91, 0xE4, 0xB8, 0x06, 0xB1, 0xF2, 0xC0, 0xD7, 0xE3, 0x47, 0xB7, 0x38, 0x08, 0xA8,
0x58, 0xE4, 0x55, 0xFC, 0xE2, 0x37, 0x1F, 0x38, 0xA2, 0x18, 0x9E, 0xC2, 0x0F, 0x90, 0x14, 0x20,
0x50, 0xD1, 0xD0, 0xAB, 0x36, 0x7F, 0xAA, 0x03, 0x1C, 0xE6, 0x0A, 0xF9, 0x8E, 0x41, 0xDB, 0x32,
0x1C, 0x68, 0xA0, 0xA0, 0xED, 0x4A, 0xF4, 0x4B, 0x09, 0xD0, 0xF0, 0x01, 0x8B, 0x17, 0x44, 0xE1,
0xEA, 0xC5, 0x9D, 0x3B, 0x37, 0x7A, 0x68, 0xF1, 0x78, 0x46, 0xCF, 0xB6, 0x57, 0xDB, 0x4B, 0x5C,
0x03, 0xE1, 0x9D, 0xC0, 0x37, 0x55, 0x8D, 0x03, 0xFB, 0x6A, 0x00, 0x82, 0x19, 0xD1, 0xC0, 0x76,
0x97, 0xEE, 0xC9, 0xAD, 0x0D, 0x72, 0x0B, 0xE9, 0xA8, 0x09, 0x92, 0x03, 0xA4, 0xAA, 0x2C, 0xCF,
0xFD, 0xDE, 0x86, 0xD0, 0x06, 0x4A, 0xAE, 0x7E, 0xC1, 0xB8, 0x2A, 0x4E, 0x9F, 0xA3, 0x5E, 0x8C,
0x12, 0x40, 0x74, 0x38, 0xE7, 0xEA, 0xB0, 0x51, 0xC2, 0xB9, 0x6D, 0x4A, 0x50, 0xBF, 0x59, 0x9C,
0x05, 0xB2, 0x42, 0xE2, 0x0F, 0x71, 0x44, 0xDB, 0x97, 0x0B, 0xD0, 0xDB, 0x44, 0x1F, 0x9A, 0x3B,
0x18, 0x2A, 0x7B, 0xD9, 0x03, 0x83, 0x0B, 0xCF, 0x27, 0x20, 0x43, 0xA6, 0x42, 0xED, 0x89, 0x63,
0xDB, 0x2D, 0x27, 0xC2, 0x3B, 0xE6, 0x0D, 0x3E, 0xB6, 0x96, 0x33, 0x70, 0xA6, 0xF3, 0xF5, 0x56,
0xEA, 0xEB, 0xF1, 0xE7, 0xD8, 0xCB, 0x04, 0x48, 0x99, 0x4C, 0x00, 0xA4, 0x2A, 0xA5, 0x8A, 0xF1,
0x58, 0xD5, 0x17, 0x4C, 0xC5, 0x88, 0x06, 0x8F, 0xA6, 0x67, 0xA6, 0x14, 0xC7, 0xB9, 0xE0, 0x86,
0xAC, 0x67, 0xFD, 0xB3, 0x5B, 0x3E, 0xDF, 0x03, 0xFD, 0xC8, 0xC4, 0x4A, 0x32, 0x78, 0x6B, 0xD1,
0xC1, 0xE2, 0x36, 0x9D, 0x0B, 0xF2, 0x54, 0x25, 0xB8, 0xB7, 0xB2, 0x10, 0x7A, 0xA6, 0x79, 0x52,
0xC2, 0xEE, 0x98, 0xA5, 0x3D, 0xF0, 0x07, 0x8D, 0x25, 0xC3, 0xAC, 0xFD, 0xCF, 0x83, 0x98, 0x80,
0x56, 0x95, 0xC4, 0x14, 0xA2, 0xA5, 0x93, 0xFE, 0x24, 0x59, 0x44, 0x73, 0xDF, 0xD6, 0x47, 0xDA,
0x22, 0x3A, 0x82, 0xC5, 0xD1, 0x59, 0x40, 0x9D, 0x0C, 0x1A, 0xB7, 0x79, 0x45, 0x9A, 0xF8, 0x6D,
0x5A, 0x5C, 0xC2, 0x80, 0xFC, 0xAA, 0x8A, 0xA4, 0xFE, 0x68, 0x61, 0x7D, 0xFE, 0x2C, 0x36, 0xE3,
0xE0, 0x59, 0x28, 0x40, 0x79, 0xAD, 0x2D, 0x28, 0x12, 0x30, 0xFC, 0x56, 0x2E, 0x1D, 0xEC, 0x48,
0x3A, 0xF0, 0xC5, 0x6C, 0x31, 0xE0, 0x2E, 0xB3, 0x91, 0x70, 0xB9, 0x9E, 0xBD, 0xE7, 0x96, 0x58,
0xCB, 0xBC, 0x1C, 0xE4, 0xC7, 0x78, 0xC7, 0x1E, 0x39, 0xDB, 0xB8, 0x77, 0x50, 0xB7, 0x65, 0x20,
0x04, 0x16, 0x8B, 0xFC, 0x66, 0xC4, 0x6D, 0x05, 0x8C, 0x3C, 0xB6, 0x32, 0x2F, 0xDE, 0xC3, 0x6F,
0xFC, 0x82, 0x06, 0x02, 0x87, 0x47, 0xFD, 0xD8, 0xDA, 0x75, 0xE0, 0x4E, 0x8C, 0x40, 0x00, 0xB2,
0x9B, 0x35, 0x78, 0xA4, 0x61, 0x64, 0x96, 0x62, 0x37, 0xF6, 0x3E, 0x39, 0xFA, 0x14, 0x5B, 0xC4,
0x70, 0x17, 0xDC, 0x0C, 0x9E, 0x31, 0x82, 0x2C, 0x63, 0xCC, 0x8A, 0x43, 0x7C, 0x69, 0x12, 0x05,
0x18, 0xA3, 0x62, 0xCC, 0xA2, 0x13, 0x96, 0x25, 0xA6, 0x1B, 0xF2, 0x10, 0xC8, 0x73, 0x4F, 0xCB,
0x80, 0xCA, 0xAF, 0x73, 0xC9, 0x78, 0xB1, 0xAE, 0x87, 0xB8, 0xDF, 0x50, 0xD3, 0x55, 0x1E, 0x3A,
0x81, 0xF6, 0x84, 0xD6, 0x57, 0x36, 0xCF, 0x38, 0xB7, 0xBC, 0xBC, 0x1E, 0x48, 0x62, 0x9F, 0x0F,
0x0C, 0xE5, 0xF0, 0x63, 0x33, 0xE6, 0x59, 0x6B, 0x1E, 0xE6, 0x1C, 0x8A, 0xF9, 0xDD, 0x6B, 0xA3,
0xDC, 0x02, 0x4A, 0x2F, 0x8C, 0x6A, 0x8D, 0x16, 0x7E, 0x2F, 0xF1, 0x75, 0xD5, 0x15, 0x93, 0x07,
0x27, 0xD9, 0x6F, 0x1A, 0x5D, 0x43, 0xF3, 0x47, 0xC4, 0xED, 0xAD, 0x05, 0x9F, 0xEC, 0x8F, 0xD0,
0xBE, 0xB5, 0x58, 0xF4, 0xF6, 0xBE, 0x08, 0x73, 0x96, 0x19, 0x05, 0x25, 0xEC, 0x3D, 0x26, 0xF4,
0x93, 0xDB, 0x9F, 0x56, 0x48, 0x4C, 0xBC, 0xD0, 0x02, 0x59, 0xD1, 0x40, 0x4C, 0xA6, 0x06, 0x41,
0xE8, 0x7D, 0x47, 0xAE, 0x3A, 0x9E, 0x1A, 0x71, 0x52, 0xD4, 0x67, 0xC1, 0x14, 0x7E, 0x40, 0x6F,
0x1C, 0x75, 0x30, 0x7B, 0x70, 0x3A, 0xE0, 0x37, 0xB7, 0x41, 0x7F, 0xCB, 0x4A, 0xBA, 0xA7, 0xCE,
0x56, 0x54, 0xC5, 0x46, 0x65, 0x6F, 0xB4, 0xB6, 0xF0, 0x57, 0xCE, 0x2E, 0x4F, 0xA9, 0xF0, 0x14,
0x50, 0xC3, 0x30, 0xC5, 0xBA, 0xE1, 0x5E, 0xD6, 0xDC, 0xC5, 0x78, 0x55, 0x32, 0xAA, 0xCB, 0x29,
0x35, 0x81, 0x46, 0x5E, 0x92, 0xE7, 0xDE, 0xCC, 0x92, 0x29, 0x86, 0xE0, 0x8F, 0x91, 0x3C, 0x74,
0x97, 0x79, 0x63, 0x97, 0x4A, 0xCC, 0x88, 0xB5, 0xA3, 0x7A, 0xF0, 0xF0, 0x33, 0x87, 0xCD, 0xBD
};
uint8_t b = Value ^ hdSurEncBasicCrypt_D2_0F_11(Value, lookup[(((AddrInd * 2) + 0) * 256) + Value]);
return (Value ^ hdSurEncBasicCrypt_D2_0F_11(b, lookup[(((AddrInd * 2) + 1) * 256) + b]));
}
void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
{
static const uint8_t lookup1[] =
{
0x16, 0x71, 0xCA, 0x14, 0xC4, 0xF4, 0xA3, 0x5A, 0x9D, 0x5F, 0x85, 0x8B, 0xA6, 0x77, 0xFD, 0x3C,
0x5F, 0x13, 0x2A, 0x5F, 0x61, 0x36, 0xE4, 0xDC, 0x0D, 0x82, 0x92, 0xC5, 0x25, 0xE1, 0x7A, 0x1C,
0x29, 0x19, 0x94, 0x2F, 0xC5, 0xD2, 0xDC, 0xBA, 0x86, 0x60, 0x64, 0x60, 0x86, 0x92, 0xA3, 0x4E,
0x3D, 0x9B, 0xCC, 0x16, 0xBB, 0xBA, 0xD2, 0xF0, 0x6A, 0xD3, 0x2F, 0x07, 0x75, 0xBD, 0x28, 0xDB
};
static const int8_t lookup2[] = { 1, -1, -1, 1, -1, 2, 1, -2, -1, 1, 2, -2, 1, -2, -2, 4 };
static const int8_t CAddrIndex[] = { 0, 1, 3, 4 };
int32_t i, j, i1, i2, i3;
for(i = 3; i >= 0; --i)
{
for(j = 0; j <= 15; ++j)
{
CWs[j] = CWs[j] ^ hdSurEncBasicCrypt_D2_0F_11(j , lookup1 [(16 * i) + j]);
}
uint8_t Buffer[16];
uint32_t k;
for(i1 = 0; i1 <= 3; ++i1)
{
for(i2 = 0; i2 <= 3; ++i2)
{
k = 0;
for(i3 = 0; i3 <= 3; ++i3)
{
k = k + (CWs[(i2 * 4) + i3] * lookup2[(i3 * 4) + i1]);
Buffer[(i2 * 4) + i1] = (uint8_t)k;
}
}
}
memcpy(CWs, Buffer, 16);
// CW positions are mixed around here
uint8_t a4[4];
for(i1 = 1; i1 <= 3; ++i1)
{
for(i2 = 0; i2 <= 3; ++i2)
{
a4[i2] = i1 + (i2 * 4);
}
for(i2 = 0; i2 <= i1 - 1; ++i2) // the given code in Func1_3 seems to be wrong here(3 instead of i1-1)!
{
uint8_t tmp = CWs[a4[0]];
for(i3 = 1; i3 <= 3; ++i3)
{
CWs[a4[i3 - 1]] = CWs[a4[i3]];
}
CWs[a4[3]] = tmp;
}
}
for(i1 = 0; i1 <= 15; ++i1)
{
CWs[i1] = hdSurEncCryptLookup_D2_0F_11(CWs[i1], CAddrIndex[i1 & 3]);
}
}
}
void hdSurEncPhase2_D2_0F_11_sub(uint8_t *CWa, uint8_t *CWb, uint8_t AddrInd)
{
uint8_t Buffer[8];
uint8_t tmp, i;
for(i = 0; i <= 7; ++i)
{
Buffer[i] = hdSurEncCryptLookup_D2_0F_11(CWb[i], AddrInd);
}
// some bitshifting
tmp = Buffer[7];
for(i = 7; i >= 1; --i)
{
Buffer[i] = ((Buffer[1] >> 4) & 0xFF) | ((Buffer[i - 1] << 4) & 0xFF);
}
Buffer[0] = ((Buffer[0] >> 4) & 0xFF) | ((tmp << 4) & 0xFF);
// saving the result
for(i = 0; i <= 7; ++i)
{
CWa[i] = CWa[i] ^ Buffer[i];
}
}
void hdSurEncPhase2_D2_0F_11(uint8_t *CWs)
{
hdSurEncPhase2_D2_0F_11_sub(CWs, CWs + 8, 0);
hdSurEncPhase2_D2_0F_11_sub(CWs + 8, CWs, 1);
hdSurEncPhase2_D2_0F_11_sub(CWs, CWs + 8, 2);
hdSurEncPhase2_D2_0F_11_sub(CWs + 8, CWs, 3);
hdSurEncPhase2_D2_0F_11_sub(CWs, CWs + 8, 4);
}
void CommonMain_1_D2_13_15(const uint8_t *datain, uint8_t *dataout)
{
const uint8_t Tab3[88] =
{
0x1B, 0x12, 0x12, 0x0C, 0x12, 0x0C, 0x0C, 0x08, 0x09, 0x09, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04,
0x08, 0x04, 0x04, 0x02, 0x04, 0x02, 0x02, 0x01, 0x09, 0x06, 0x09, 0x06, 0x06, 0x04, 0x06, 0x04,
0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
0x09, 0x06, 0x06, 0x04, 0x09, 0x06, 0x06, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x02, 0x02,
0x04, 0x02, 0x04, 0x02, 0x02, 0x01, 0x02, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};
int i1,i2;
unsigned long bb;
for (i1 = 0; i1 < 11; i1++)
{
bb = 0;
for (i2 = 0; i2 < 8; i2++)
{
bb += (Tab3[(i1 * 8) + i2] * datain[i2]);
}
dataout[i1] = (bb & 0xFF);
}
}
unsigned short CommonMain_2_D2_13_15(const uint8_t *data, const unsigned long num)
{
unsigned long bb1, bb2;
bb1 = num >> 3;
bb2 = (data[bb1] << 24) + (data[bb1 + 1] << 16) + (data[bb1 + 2] << 8);
return ((bb2 >> (21 - (num & 7))) & 0x7FF);
}
void CommonMain_3_D2_13_15(uint8_t *data0, uint8_t *data1, int nbrloop)
{
int i;
unsigned long bb1, bb2;
bb1 = 0;
bb2 = 0;
for (i = nbrloop - 1; i >= 0; i--)
{
bb1 += (data0[i] * 2) + data1[i];
bb2 += data0[i] + data1[i];
data0[i] = (bb1 & 0xFF);
data1[i] = (bb2 & 0xFF);
bb1 >>= 8;
bb2 >>= 8;
}
}
void CommonMain_D2_13_15(const uint8_t *datain, uint8_t *dataout, int loopval)
{
const uint8_t Tab0_Comp[0x800] =
{
0x54, 0x75, 0x01, 0x0C, 0x7C, 0xE2, 0xC3, 0xC2, 0x5E, 0x13, 0x26, 0xCA, 0xB2, 0xCD, 0xB8, 0x3D,
0x02, 0x2C, 0xE4, 0x19, 0x41, 0x3D, 0xE4, 0x0F, 0xEC, 0xF1, 0x45, 0x83, 0xE2, 0xE2, 0x72, 0xF9,
0xCD, 0x75, 0x1E, 0x41, 0xCC, 0x0C, 0x1F, 0x39, 0x87, 0x9B, 0x46, 0xFF, 0x68, 0x1F, 0x00, 0xD8,
0x41, 0x82, 0xCA, 0xC6, 0xEF, 0x87, 0x90, 0xA2, 0x7E, 0xD9, 0xDE, 0xC8, 0x25, 0xEA, 0xC9, 0x75,
0x6E, 0x18, 0x81, 0xD8, 0x5A, 0xA6, 0x74, 0x05, 0xAF, 0xAE, 0xE0, 0x4F, 0x85, 0xAD, 0x94, 0xF6,
0x45, 0xF4, 0xF5, 0x55, 0xA8, 0xEB, 0xEC, 0xDB, 0x6C, 0xFF, 0x2F, 0xC2, 0xC3, 0x7D, 0x93, 0xE6,
0xF5, 0x31, 0x96, 0xB7, 0x9A, 0xDB, 0xE5, 0x76, 0x66, 0xFB, 0xDD, 0xBC, 0x19, 0x18, 0x42, 0xC6,
0x36, 0xCD, 0x46, 0x33, 0xEA, 0xF1, 0x4C, 0xC0, 0x72, 0x07, 0xCD, 0x61, 0xCE, 0x0E, 0x08, 0x01,
0xA3, 0xFA, 0x84, 0x21, 0xF2, 0x43, 0x37, 0x1C, 0xDE, 0x25, 0x8A, 0x1A, 0xF4, 0xBB, 0x40, 0xF3,
0x53, 0xFE, 0x17, 0x60, 0x91, 0x6D, 0x7B, 0x6D, 0x5F, 0x1C, 0x15, 0x73, 0xCC, 0x6E, 0x73, 0x46,
0x27, 0x73, 0xA3, 0x10, 0x16, 0x32, 0xB3, 0x39, 0x45, 0xA6, 0x55, 0xE7, 0x91, 0x32, 0x24, 0xC8,
0xAE, 0xAF, 0x1B, 0x28, 0x69, 0x22, 0x2F, 0xE9, 0x77, 0x72, 0xBF, 0x4B, 0x8B, 0x07, 0x82, 0x31,
0xB0, 0x95, 0x10, 0x78, 0x9F, 0xC5, 0xF3, 0x73, 0xE1, 0xF8, 0x36, 0x84, 0xFE, 0x1B, 0x92, 0xB2,
0xE6, 0xA5, 0xCE, 0xDA, 0x56, 0x48, 0x52, 0x77, 0x9D, 0x9D, 0x8E, 0x37, 0x4B, 0xC8, 0x35, 0x7E,
0xB9, 0x5D, 0xA4, 0xAE, 0x3F, 0xD0, 0xAA, 0x60, 0xA8, 0x4C, 0x85, 0x49, 0xF6, 0x0C, 0x27, 0xE8,
0x94, 0x84, 0xA0, 0xAA, 0x06, 0x4D, 0xAC, 0x58, 0x8B, 0x61, 0x29, 0x3D, 0x68, 0x25, 0xD3, 0xD3,
0x8E, 0xA1, 0xE0, 0x71, 0xBF, 0x21, 0x0C, 0xC7, 0x18, 0x19, 0xF1, 0x25, 0x98, 0x5F, 0x79, 0x5E,
0x51, 0xBA, 0x8C, 0x2F, 0x52, 0x43, 0xF3, 0x5A, 0xE3, 0x58, 0x97, 0x64, 0x23, 0xE0, 0x44, 0x4F,
0x30, 0x2A, 0xE0, 0x16, 0x8D, 0x4D, 0xD1, 0x1F, 0x7B, 0xC9, 0xC5, 0x74, 0x11, 0x23, 0x5D, 0x95,
0xAC, 0x7F, 0x2E, 0x30, 0xBE, 0x2D, 0xE3, 0xB5, 0xC6, 0xA7, 0x69, 0x99, 0x1F, 0x18, 0x3C, 0x96,
0x30, 0x45, 0x99, 0x71, 0x28, 0x08, 0x3C, 0xF7, 0x37, 0x4F, 0x6A, 0xD6, 0xAE, 0x9B, 0x57, 0xC1,
0xCC, 0x2C, 0xE2, 0x0F, 0x7D, 0x66, 0xF4, 0x36, 0x0C, 0x3B, 0x35, 0xF6, 0x28, 0x03, 0xA3, 0x7A,
0x83, 0x15, 0xF5, 0x61, 0x5E, 0xE8, 0xB7, 0xD8, 0x54, 0x33, 0x93, 0x63, 0x80, 0x40, 0x43, 0xD0,
0x9C, 0xAA, 0x3A, 0x98, 0x50, 0xD2, 0xB8, 0x80, 0x5D, 0x16, 0xDF, 0x1C, 0x03, 0xAA, 0x87, 0xC7,
0x63, 0xA5, 0x8D, 0xA9, 0x2E, 0xFB, 0x4F, 0x7C, 0x2B, 0xF5, 0xF9, 0x57, 0xB5, 0x90, 0xD8, 0x75,
0xAB, 0x81, 0x4C, 0x1B, 0xAF, 0x6C, 0x0E, 0xCB, 0xB1, 0x4F, 0xD3, 0xE3, 0x69, 0x18, 0x8C, 0x7A,
0x3C, 0xE1, 0x11, 0x86, 0x47, 0x78, 0x11, 0xA0, 0xD4, 0x28, 0xC3, 0x0D, 0xAC, 0xC6, 0x17, 0xA1,
0x32, 0x9F, 0x8F, 0x42, 0xD9, 0x3F, 0x66, 0xD7, 0x2D, 0x87, 0x7B, 0x65, 0xD3, 0xD6, 0x90, 0x83,
0xA2, 0x75, 0xE8, 0x98, 0x90, 0x9D, 0xDE, 0x81, 0x9E, 0x3D, 0xE4, 0xA9, 0xE4, 0x0B, 0xBC, 0xBA,
0x96, 0xDD, 0x05, 0xCA, 0xAE, 0x78, 0x69, 0x24, 0xDB, 0xA7, 0x3E, 0x7A, 0x3B, 0xB4, 0xC4, 0x59,
0x61, 0xD2, 0xF2, 0xE3, 0x99, 0x8F, 0x8F, 0x8A, 0x82, 0x33, 0xB8, 0x17, 0x5E, 0x7A, 0x32, 0x41,
0x10, 0x8D, 0xC2, 0xEF, 0xAA, 0xF8, 0x5A, 0xF7, 0xD2, 0x1D, 0xC0, 0xCB, 0x5E, 0xB7, 0x8A, 0x78,
0x49, 0x42, 0xEB, 0x19, 0x1B, 0x61, 0xA0, 0x77, 0x5A, 0xF4, 0x6D, 0x55, 0xDA, 0xEB, 0xCE, 0x4E,
0xB8, 0xE6, 0x32, 0xD7, 0x51, 0x3F, 0x73, 0x14, 0x34, 0x6E, 0x38, 0xD6, 0xA7, 0x28, 0x87, 0x4A,
0x59, 0xCA, 0x1C, 0x80, 0xB5, 0x8C, 0x9D, 0x94, 0xCB, 0xFE, 0x29, 0x41, 0xE5, 0x69, 0xCF, 0xFD,
0x0B, 0xE1, 0x7C, 0xA1, 0x70, 0x12, 0x76, 0x43, 0xDA, 0xB9, 0xD4, 0xC3, 0x31, 0xBC, 0x94, 0x77,
0x04, 0xB4, 0x1C, 0xAA, 0xEC, 0x6F, 0xA5, 0x12, 0x9D, 0x6F, 0x34, 0x65, 0x77, 0xA0, 0xD2, 0x6F,
0x60, 0xC6, 0x47, 0xC2, 0xDF, 0x6A, 0x10, 0x53, 0xD4, 0xBA, 0xF3, 0xB7, 0x38, 0x79, 0x63, 0xC9,
0xD4, 0x77, 0xBC, 0x54, 0xE9, 0x79, 0x42, 0xD5, 0xE0, 0x71, 0xE7, 0x9E, 0x5A, 0x62, 0x0C, 0xAD,
0x01, 0x09, 0xA8, 0x9F, 0x8E, 0x67, 0x4A, 0x30, 0xA4, 0xB1, 0x08, 0xFC, 0x0A, 0xEA, 0x7A, 0x1D,
0x4C, 0x4A, 0x21, 0xDE, 0x00, 0xD7, 0x41, 0x98, 0x6B, 0x38, 0x50, 0x3E, 0x1F, 0x25, 0x06, 0xE3,
0x6C, 0xA3, 0x84, 0x5B, 0xC1, 0xED, 0x47, 0xDD, 0xB3, 0x83, 0x46, 0x72, 0x69, 0xCE, 0x72, 0x04,
0x43, 0x67, 0x3A, 0x19, 0xD9, 0x0A, 0xF7, 0x43, 0x88, 0xCA, 0xC7, 0x31, 0x34, 0x21, 0x4E, 0x4C,
0xE8, 0xD1, 0x70, 0x00, 0xBD, 0xB1, 0xB6, 0x76, 0x6F, 0x5B, 0xF9, 0xF5, 0xF4, 0x19, 0x20, 0x21,
0xC1, 0xF0, 0x11, 0x36, 0x66, 0xAB, 0x15, 0xBD, 0x69, 0x92, 0xC6, 0x46, 0xDE, 0xDC, 0xE9, 0x9A,
0xF8, 0x6C, 0x15, 0x29, 0x15, 0xA6, 0x35, 0x3E, 0x08, 0xE5, 0x90, 0x62, 0x9F, 0x86, 0x56, 0x83,
0x5D, 0x60, 0x0D, 0x22, 0x77, 0xA7, 0x60, 0x9B, 0x26, 0x80, 0x16, 0x67, 0xB4, 0x46, 0xBF, 0x74,
0x55, 0x92, 0x5B, 0x34, 0xFF, 0xC8, 0x28, 0x37, 0xFF, 0x14, 0x62, 0xFA, 0xBD, 0x03, 0x78, 0x04,
0x1B, 0x65, 0x7F, 0x99, 0x05, 0x27, 0x14, 0xC0, 0x06, 0x4D, 0x4B, 0x0E, 0x98, 0x34, 0x6A, 0xB3,
0xA1, 0xFE, 0xBC, 0x45, 0x7D, 0x52, 0x50, 0x0E, 0x2C, 0xFB, 0x91, 0xF5, 0xFB, 0x2A, 0xB7, 0xD9,
0xB8, 0xB8, 0x54, 0x31, 0x81, 0x03, 0x93, 0x2C, 0xE1, 0x5C, 0xB9, 0x2C, 0xE8, 0x38, 0xC0, 0xA7,
0x58, 0x18, 0x92, 0xC5, 0x8B, 0xEF, 0x1E, 0x33, 0xA4, 0xBA, 0x86, 0x2B, 0xE9, 0xEE, 0xB1, 0xDF,
0xAB, 0xB8, 0x48, 0xDA, 0x84, 0xF1, 0x68, 0x05, 0x4E, 0xDE, 0xB5, 0x9E, 0x88, 0x12, 0xC9, 0x60,
0x50, 0x58, 0x56, 0x9D, 0x26, 0x84, 0xB6, 0x1A, 0xE6, 0x4B, 0x40, 0x94, 0x6D, 0xE9, 0x1D, 0x0D,
0x8A, 0xF9, 0x2A, 0xB5, 0xBC, 0xDB, 0x06, 0x8F, 0x13, 0x7E, 0x1D, 0x1C, 0xC7, 0xFD, 0x8F, 0x78,
0x55, 0x3F, 0x16, 0x84, 0x48, 0xDA, 0x1A, 0xD1, 0x93, 0x95, 0x20, 0x58, 0x92, 0x39, 0xF6, 0x73,
0x4E, 0x9E, 0x7B, 0x70, 0xFC, 0x1E, 0x5B, 0x20, 0x48, 0x96, 0xB3, 0x7C, 0x50, 0x09, 0x5B, 0x61,
0x57, 0x97, 0x36, 0x04, 0x29, 0x2C, 0x32, 0x8E, 0x93, 0x4A, 0x45, 0xFA, 0xD5, 0x24, 0x14, 0x1A,
0x28, 0x9C, 0x1A, 0x71, 0xAE, 0x85, 0x4B, 0x26, 0x79, 0x99, 0x65, 0xD0, 0x07, 0x98, 0xED, 0xC9,
0x1B, 0x39, 0x57, 0x5B, 0xDB, 0x3D, 0x87, 0x69, 0x66, 0x9B, 0x03, 0x23, 0x54, 0x6B, 0x4B, 0xAC,
0x6E, 0x7A, 0x25, 0x1E, 0xB6, 0x97, 0xCF, 0x1D, 0x07, 0xCB, 0x2A, 0x3E, 0x85, 0x02, 0x93, 0x31,
0x12, 0x27, 0xF0, 0xA6, 0x6D, 0x0F, 0x9A, 0xB6, 0xFC, 0x22, 0x79, 0x6C, 0x77, 0xFD, 0x3F, 0xDC,
0x19, 0xD0, 0xDF, 0xBD, 0x9E, 0xE0, 0xBE, 0x20, 0x13, 0xA3, 0x0A, 0x0B, 0x22, 0xF2, 0xC8, 0x6B,
0xA1, 0xDD, 0x6C, 0x67, 0xB3, 0xFD, 0x71, 0xC2, 0x7B, 0x08, 0x3B, 0xF1, 0x37, 0xB5, 0x0F, 0x86,
0xFA, 0xA9, 0xE9, 0x42, 0xD1, 0xE8, 0xCD, 0x05, 0xEF, 0xD3, 0xCC, 0x0B, 0x70, 0x51, 0x5B, 0x97,
0x06, 0xC4, 0x9D, 0x88, 0x11, 0x3E, 0x99, 0x9F, 0xBE, 0x76, 0x8C, 0x8D, 0xE6, 0xBA, 0xDA, 0x48,
0xD0, 0x04, 0x86, 0x4F, 0xA9, 0xC6, 0xB0, 0xED, 0xA4, 0x94, 0x46, 0x96, 0x27, 0xEE, 0x9F, 0xBD,
0xDA, 0x9B, 0x3D, 0x11, 0x80, 0xD3, 0x7B, 0x5A, 0x48, 0x94, 0xE5, 0xCC, 0x48, 0xEA, 0xE4, 0x18,
0xDF, 0x51, 0xB3, 0x02, 0x57, 0x20, 0x4B, 0x0F, 0x07, 0xFF, 0x41, 0x33, 0x0F, 0x6B, 0x2E, 0xAA,
0xDE, 0xB2, 0x56, 0xF7, 0xFB, 0xA2, 0x48, 0x3C, 0x97, 0x1A, 0x64, 0x2C, 0xD1, 0x74, 0x40, 0xCF,
0x65, 0x7F, 0x14, 0x08, 0x59, 0xC4, 0x35, 0xD3, 0x8A, 0x0F, 0xFD, 0x71, 0x7A, 0x71, 0xAC, 0x2D,
0xF3, 0xFD, 0x7B, 0x12, 0x5F, 0xC0, 0xBC, 0x4E, 0x96, 0x12, 0xF2, 0x8E, 0x41, 0x84, 0x01, 0x0F,
0xED, 0x7B, 0xC1, 0xB9, 0x39, 0x03, 0x35, 0x40, 0x49, 0x53, 0xB8, 0xB4, 0x6B, 0xA6, 0xE7, 0x0A,
0x14, 0xBB, 0x29, 0x16, 0xEC, 0x2A, 0x3A, 0xD6, 0x09, 0xBB, 0x5C, 0x20, 0xF8, 0x09, 0xFD, 0x86,
0xC4, 0x25, 0x09, 0x85, 0x0B, 0xD5, 0xD8, 0x51, 0xB1, 0xA2, 0xCB, 0xDC, 0xC4, 0xDD, 0x34, 0xDF,
0xE2, 0x85, 0xA9, 0xCC, 0x4E, 0x66, 0x51, 0xFA, 0x9C, 0x4D, 0xB7, 0x1E, 0x3E, 0x49, 0x34, 0x9C,
0x21, 0x66, 0x07, 0x44, 0xB2, 0xEC, 0x73, 0xC5, 0xBB, 0x27, 0x9A, 0xA5, 0x91, 0x5A, 0xB9, 0x9F,
0xBE, 0xC8, 0xA2, 0x27, 0x89, 0x21, 0xA7, 0xEE, 0x50, 0x4D, 0x43, 0x50, 0x67, 0xC2, 0x3B, 0x7C,
0x20, 0x0B, 0x95, 0x40, 0xBE, 0xEA, 0xB5, 0xD9, 0x82, 0xD7, 0x9C, 0xB5, 0x21, 0xAD, 0xA6, 0xF9,
0x70, 0xEA, 0xCD, 0x04, 0xDD, 0x58, 0x91, 0x89, 0xB2, 0xA9, 0xF9, 0xB4, 0x12, 0xA2, 0x63, 0x89,
0x40, 0x8E, 0xEA, 0x62, 0xEE, 0x0B, 0x01, 0x82, 0x6F, 0xB3, 0x5E, 0x5C, 0x36, 0xBE, 0xF4, 0x97,
0x2C, 0xCF, 0x96, 0x7C, 0x0D, 0xAD, 0x62, 0xCE, 0xD4, 0x38, 0xC5, 0x32, 0x02, 0x24, 0x57, 0x27,
0xE0, 0xCF, 0x56, 0xA5, 0x72, 0x6D, 0x90, 0x89, 0x2D, 0x4C, 0x34, 0xF6, 0x1D, 0xDD, 0x88, 0x5E,
0x7A, 0x23, 0xE3, 0x6F, 0x42, 0xA3, 0xD9, 0x58, 0x7E, 0xE3, 0x52, 0x74, 0x57, 0x63, 0xB7, 0xB2,
0xC1, 0xA3, 0x30, 0x92, 0x2E, 0xB0, 0x91, 0x01, 0x13, 0x36, 0x9A, 0x6A, 0xA7, 0x5B, 0x3C, 0x07,
0xFB, 0xD8, 0x1E, 0x7E, 0xCF, 0x49, 0xAB, 0x3F, 0xCA, 0xCE, 0x74, 0x40, 0x54, 0x8D, 0x83, 0x61,
0xCA, 0xC3, 0x76, 0x59, 0x5C, 0x9F, 0x49, 0x8A, 0x7D, 0xD1, 0x17, 0x9C, 0xA4, 0xDB, 0xB9, 0x16,
0x4D, 0x64, 0xF7, 0xC7, 0xF0, 0x24, 0xE7, 0x00, 0xB6, 0x98, 0xD5, 0x8B, 0x54, 0xCB, 0x1E, 0x8B,
0xA2, 0x2B, 0x7D, 0x50, 0x51, 0x8A, 0xF0, 0xEF, 0x47, 0xAE, 0xD0, 0xD6, 0xA0, 0x42, 0x8A, 0xD8,
0x22, 0xAF, 0x02, 0x99, 0x4A, 0xE0, 0x8D, 0x8D, 0xBF, 0x11, 0x05, 0xA4, 0xC4, 0x9D, 0xB3, 0x89,
0xB4, 0x4C, 0xC9, 0xF7, 0x4D, 0xC5, 0x2A, 0x35, 0x95, 0x30, 0xF3, 0x0E, 0x2F, 0xEC, 0x6E, 0x3A,
0x8B, 0x05, 0x76, 0xED, 0x1A, 0x7C, 0xC0, 0xE7, 0x22, 0xCB, 0x59, 0xFF, 0xE6, 0x37, 0x78, 0x44,
0xD4, 0xEE, 0xAD, 0xD7, 0xBD, 0x2E, 0xB7, 0x6A, 0xA4, 0x4E, 0x0E, 0xFB, 0xB0, 0xF5, 0xCB, 0x87,
0xCF, 0xC3, 0x18, 0x64, 0x6F, 0x26, 0x5C, 0xD7, 0x16, 0xC8, 0x7F, 0xAB, 0x29, 0xC4, 0xBA, 0xFF,
0xCD, 0x1C, 0xE4, 0x3A, 0xF2, 0xEB, 0x6A, 0x38, 0xE4, 0x65, 0xC2, 0x33, 0x03, 0x26, 0x7D, 0x9B,
0x7E, 0x1D, 0x83, 0x00, 0x04, 0x2D, 0x2B, 0x5F, 0xFE, 0x39, 0x7E, 0xF1, 0x3C, 0xA2, 0x8C, 0x52,
0x95, 0xBF, 0x46, 0x81, 0x24, 0x44, 0xF8, 0x10, 0xC3, 0x87, 0x8E, 0x64, 0x80, 0x17, 0x44, 0xE2,
0x8B, 0xD1, 0x3C, 0x4A, 0xE2, 0x1F, 0xA9, 0xDE, 0x75, 0x13, 0xFC, 0x2E, 0x86, 0x0A, 0x5C, 0x5F,
0x92, 0x2B, 0x92, 0x2D, 0x2A, 0xEC, 0xD2, 0x5C, 0x82, 0x6B, 0x76, 0x1E, 0xED, 0xE6, 0x56, 0xF7,
0xD2, 0xDB, 0x96, 0x68, 0x02, 0x68, 0x99, 0x49, 0xEE, 0x88, 0x66, 0xCE, 0x5D, 0x08, 0x88, 0xA8,
0xB9, 0x24, 0xB0, 0xB4, 0xDC, 0xA6, 0xC9, 0xD8, 0x68, 0x80, 0xBF, 0x6B, 0x32, 0x57, 0x7F, 0x91,
0x0E, 0x37, 0x59, 0xF6, 0x76, 0xD2, 0xC5, 0x0B, 0xF3, 0x23, 0xBF, 0x38, 0x52, 0x0D, 0x97, 0x81,
0x17, 0xBB, 0x9A, 0xC2, 0x55, 0x44, 0x72, 0xCE, 0xEE, 0xFA, 0xBB, 0xDA, 0xAB, 0xB0, 0x09, 0xEA,
0xDB, 0xBF, 0x45, 0x95, 0x07, 0x88, 0xD4, 0xD2, 0x0D, 0x2E, 0x15, 0x31, 0xBE, 0x6A, 0xF4, 0xEF,
0xA3, 0x7D, 0x22, 0x81, 0x3B, 0xA8, 0x83, 0xF9, 0x42, 0xE5, 0x9B, 0x79, 0x01, 0xF5, 0xDC, 0x19,
0x64, 0xEB, 0x47, 0x67, 0xAF, 0xA4, 0xB2, 0xAE, 0xF8, 0xF9, 0x4D, 0x63, 0xAD, 0x54, 0xE1, 0x02,
0x56, 0x89, 0x4E, 0x0A, 0xE8, 0x3E, 0x03, 0xFA, 0x33, 0x61, 0x58, 0x80, 0x64, 0x55, 0x3C, 0x8C,
0x2A, 0x3D, 0x70, 0x3E, 0xE5, 0xC1, 0xA7, 0x75, 0xFC, 0x91, 0x75, 0x05, 0x8C, 0x6E, 0x3A, 0x74,
0x10, 0xF1, 0x30, 0xE6, 0xF6, 0xF7, 0xAB, 0x6C, 0xB1, 0x2B, 0xF0, 0x2F, 0x13, 0x6E, 0xD4, 0x0A,
0x64, 0x29, 0xF8, 0xBB, 0xA1, 0xAA, 0x55, 0x09, 0x93, 0x47, 0x2F, 0x8C, 0x7D, 0xF1, 0x2D, 0x81,
0xFE, 0x78, 0xFC, 0xEE, 0x3F, 0xDD, 0x49, 0xDC, 0x0D, 0x52, 0x5C, 0x3B, 0x8F, 0x08, 0xB0, 0xDF,
0xDC, 0xFC, 0xBE, 0x5F, 0x3B, 0x53, 0x82, 0xE2, 0xBD, 0x6D, 0x5D, 0xF2, 0x8D, 0xFB, 0x5A, 0x1D,
0x15, 0x1B, 0xE4, 0xB1, 0x56, 0x06, 0x1A, 0xF8, 0x9C, 0xB9, 0x44, 0xF2, 0xD9, 0xF4, 0xB2, 0x00,
0x9A, 0x94, 0x62, 0x33, 0x7E, 0x0A, 0xB0, 0x0C, 0xD5, 0xEF, 0x8E, 0xA8, 0xEB, 0x47, 0xE9, 0x20,
0xA8, 0x68, 0xEF, 0x53, 0xA0, 0x59, 0x1B, 0xA0, 0x2B, 0xC5, 0x2B, 0x30, 0xB6, 0x5D, 0xAB, 0xB4,
0x5F, 0x86, 0x71, 0x95, 0x89, 0xFC, 0xC7, 0x9A, 0xC3, 0xED, 0x82, 0xA0, 0x3D, 0x73, 0xC1, 0x36,
0x01, 0x5F, 0x9E, 0xD7, 0xE3, 0xC0, 0x62, 0x74, 0xED, 0x13, 0xB6, 0xD6, 0xD5, 0x37, 0x17, 0xE1,
0x39, 0xC7, 0x6D, 0x31, 0xBA, 0x02, 0xAF, 0xD5, 0xCC, 0x51, 0xA8, 0x09, 0x3F, 0x00, 0x4A, 0x8F,
0xA6, 0x23, 0x13, 0x88, 0xCD, 0x1F, 0x38, 0x60, 0xE7, 0xE7, 0x53, 0xDC, 0x65, 0xE8, 0x53, 0x26,
0xBB, 0xE1, 0x1F, 0x65, 0xF0, 0xAD, 0x53, 0x3B, 0xBD, 0xAD, 0x97, 0xAC, 0xD1, 0xA5, 0xD0, 0xE9,
0xEB, 0xD6, 0x11, 0xD5, 0x00, 0xDF, 0x72, 0x9C, 0xCC, 0x7F, 0xD3, 0x67, 0xA1, 0x3A, 0x79, 0xE1,
0x85, 0x70, 0xE5, 0x43, 0xC9, 0x28, 0xA5, 0x2F, 0x9E, 0xE7, 0xFE, 0xEB, 0x14, 0x10, 0x23, 0xC7,
0xAF, 0xB1, 0x24, 0xC8, 0xE5, 0x44, 0x6F, 0x4C, 0x04, 0xEC, 0xC1, 0xF0, 0x23, 0x1C, 0xF6, 0xAC,
0xAF, 0xC4, 0x0E, 0x2D, 0x59, 0x39, 0x47, 0xA9, 0x9E, 0xD9, 0x2E, 0x79, 0xBA, 0xFE, 0x4F, 0x12,
0x7F, 0x63, 0x7F, 0x62, 0x67, 0x7C, 0x52, 0x2F, 0xCA, 0x8B, 0x6B, 0x4F, 0x10, 0x8F, 0x14, 0xC6,
0xA1, 0x9B, 0x45, 0x15, 0x90, 0x63, 0x22, 0x5D, 0x68, 0x4B, 0xCF, 0xFA, 0x6A, 0x06, 0xF0, 0x26,
0xAC, 0x6C, 0x3A, 0x89, 0x25, 0xF3, 0x5E, 0x90, 0x06, 0x93, 0xB6, 0x35, 0x0D, 0x85, 0x60, 0x98,
0xBC, 0x6E, 0xF2, 0xA5, 0x17, 0x29, 0x70, 0xD6, 0xFF, 0x0C, 0xD0, 0xC0, 0x35, 0xD7, 0x4A, 0xFD
};
const uint8_t Tab1_Comp[11 * 8] =
{
0x70, 0x49, 0xD7, 0xE3, 0xDF, 0x3C, 0x96, 0x03, 0x2A, 0x70, 0x82, 0xA6, 0x5F, 0xDE, 0xCC, 0x0C,
0x2A, 0x62, 0x2A, 0x3E, 0xA4, 0x0C, 0x0A, 0xAB, 0x4F, 0x06, 0x5D, 0xD4, 0x14, 0xAA, 0xE1, 0xC3,
0x96, 0xDA, 0x16, 0x36, 0x45, 0x3C, 0x63, 0xC2, 0x97, 0x71, 0x87, 0xAB, 0xFA, 0xB2, 0xFC, 0xD6,
0x8F, 0x85, 0xC9, 0x04, 0x56, 0xBA, 0xEB, 0x3F, 0x42, 0x9F, 0xCB, 0x66, 0x55, 0x45, 0x1C, 0x96,
0xFF, 0x4D, 0x35, 0xDF, 0x88, 0x0E, 0xDC, 0xC8, 0x4E, 0x3F, 0x81, 0x74, 0xD8, 0x77, 0x4C, 0x8E,
0x00, 0xC0, 0x64, 0x83, 0x4E, 0xBB, 0xF0, 0xB1
};
unsigned short buff8[8];
uint8_t buff11[11 + 1]; // +1 to avoid func2 bug
int i1, i2;
buff11[11] = 0;
CommonMain_1_D2_13_15(datain, buff11);
for (i1 = 0; i1 < 11; i1++)
{
buff11[i1] ^= Tab1_Comp[(loopval * 11) + i1];
}
for (i1 = 0; i1 < 8; i1++)
{
buff8[i1] = CommonMain_2_D2_13_15(buff11, i1 * 11);
}
for (i1 = 0; i1 < 8; i1++)
{
dataout[i1] = Tab0_Comp[buff8[i1]];
}
i1 = 1;
while (i1 < 8)
{
i2 = 0 ;
while (i2 < 8)
{
CommonMain_3_D2_13_15(&dataout[i2], &dataout[i1 + i2], i1);
i2 += (i1 * 2);
}
i1 *= 2;
}
}
void Common_D2_13_15(uint8_t *cw0, const uint8_t *cw1, int loopval)
{
int i;
uint8_t buff8[8];
CommonMain_D2_13_15(cw1, buff8, loopval);
for (i = 0; i < 8; i++)
{
cw0[i] ^= buff8[i];
}
}
void ExchangeCWs(uint8_t *cw0, uint8_t *cw1)
{
int i;
uint8_t b;
for (i = 0; i < 8; i++)
{
b = cw1[i];
cw1[i] = cw0[i];
cw0[i] = b;
}
}
void hdSurEncPhase1_D2_13_15(uint8_t *cws)
{
int i;
for (i = 0; i <= 7; i++)
{
// Possible code
if ((i & 1) == 0)
{
Common_D2_13_15((uint8_t *) &cws[0], (uint8_t *) &cws[8], i);
}
else
{
Common_D2_13_15((uint8_t *) &cws[8], (uint8_t *) &cws[0], i);
}
}
ExchangeCWs((uint8_t *) &cws[0], (uint8_t *) &cws[8]);
}
void hdSurEncPhase2_D2_13_15(uint8_t *cws)
{
int i;
for (i = 7; i >= 0; i--)
{
// Possible code
if ((i & 1) == 0)
{
Common_D2_13_15((uint8_t *) &cws[8], (uint8_t *) &cws[0], i);
}
else
{
Common_D2_13_15((uint8_t *) &cws[0], (uint8_t *) &cws[8], i);
}
}
ExchangeCWs((uint8_t *) &cws[8], (uint8_t *) &cws[0]);
}
uint getBit(uint number, int bt)
{
return (number >> bt ) & 1;
}
void SBitslice(uint* Iarray, int offsetin, uint* Oarray, int offsetout, int row, char* box)
{
int bi, input, l, output;
uint calcArray[4] = {0, 0, 0, 0};
for (bi = 0; bi < 32; bi++)
{
input = 0;
for (l = 0; l < 4; l++)
{
input += getBit(Iarray[l + offsetin], bi) << l;
}
output = box[input + 16 * row];
for (l = 0; l < 4; l++)
{
calcArray[l] += getBit(output, l) << bi;
}
}
for (l = 0; l < 4; l++)
{
Oarray[l + offsetout] = calcArray[l];
}
}
void xorBlock(uint* data, int offset)
{
int i;
for (i = 0; i < 4; i++)
{
data[i] ^= KeyS[i + 4*offset];
}
}
uint rotr(uint val, int nbits)
{
return ((val >> nbits) + (val << (32 - nbits)));
}
void LTBitsliceInverse(uint* data)
{
uint C0 = data[0];
uint C1 = data[1];
uint C2 = data[2];
uint C3 = data[3];
C2 = rotr(C2, 22);
C0 = rotr(C0, 5);
C2 ^= C3 ^ (C1 << 7);
C0 ^= C1 ^ C3;
C3 = rotr(C3, 7);
C3 ^= C2 ^ (C0 << 3);
C1 = rotr(C1, 1);
C1 ^= C0 ^ C2;
C2 = rotr(C2, 3);
C0 = rotr(C0, 13);
data[0] = C0;
data[1] = C1;
data[2] = C2;
data[3] = C3;
}
void N98_decrypt(byte* data)
{
int r; // round
int i, j;
uint N98[4]; // make 32 bits words
for(i = 0; i < 4; i++)
{
N98[i] = data[4 * i] + (data[4 * i + 1] << 8) + (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24);
}
for(r = 31; r >= 0; r--) // decrypt, inverse order
{
if (r == 31)
{
xorBlock(N98, 32);
}
else
{
LTBitsliceInverse(N98); // inverse Linear Transform
}
SBitslice(N98, 0, N98, 0, (r & 7), SBoxInverse); // SBox inverse, bitslice mode
xorBlock(N98, r);
}
for(i = 0; i < 4; i++) // set bytes to caller's array
{
for(j = 0; j < 4; j++)
{
data[4 * i + j] = (N98[i] >> 8 * j) & 0xFF;
}
}
}
void MakeSubKeys(uint* KeySch, char key98Idx)
{
int i, k;
char j;
uint w[140] = {0};
char Sbox[128];
// uint KeyS[132];
// calc SBox , inverse of SBoxInverse
for(i = 0; i < 8; i++) //row
{
for(j = 0; j < 16; j++) // search for column
{
k = 0;
while (SBoxInverse[k+16*i] != j)
{
k = k +1;
}
Sbox[j + 16 * i] = k;
}
}
switch (key98Idx)
{
case 0x21:
{
w[0] = 0x6341F22E;
w[1] = 0x002E2D10;
w[2] = 0x181D7704;
w[3] = 0x1D93A0F3;
w[4] = 1;
w[5] = 0;
w[6] = 0;
w[7] = 0;
break;
}
}
for(i = 0; i < 132; i++)
{
w[i + 8] = rotr((w[i + 0] ^ w[i + 3] ^ w[i + 5] ^ w[i + 7] ^ 0x9E3779B9 ^ i), 21);
}
for(i = 0; i < 33; i++)
{
SBitslice(w, (4 * i + 8), KeySch, (4 * i), ((35 - i) & 7), Sbox); // SBox , bitslice mode
}
}
static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
{
get_atr;
def_resp;
int32_t i;
uint8_t buf[256];
uint8_t insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
uint8_t insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
uint8_t insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
uint8_t insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
static const uint8_t insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC
static const uint8_t FacDat[] = { 0x00, 0x00, 0x28 };
static uint8_t ins8702_data[] = { 0x00, 0x00, 0x11};
static uint8_t ins8704[] = { 0x87, 0x04, 0x00, 0x00, 0x07 };
static uint8_t ins8706[] = { 0x87, 0x06, 0x00, 0x00, 0x04 };
if((atr[1] != 0x77) || ((atr[2] != 0x18) && (atr[2] != 0x11) && (atr[2] != 0x19)) || ((atr[9] != 0x68) && (atr[9] != 0x6C) && (atr[9] != 0x64)))
{
return ERROR;
}
write_cmd(insFAC, FacDat);
if(!(cta_res[cta_lr - 2] == 0x90 && cta_res[cta_lr - 1] == 0))
{
return ERROR;
}
if(!cs_malloc(&reader->csystem_data, sizeof(struct viaccess_data)))
{
return ERROR;
}
struct viaccess_data *csystem_data = reader->csystem_data;
write_cmd(insFAC, ins8702_data);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
write_cmd(ins8704, NULL);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
write_cmd(ins8706, NULL);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
csystem_data->last_geo.number_ecm = (cta_res[2] << 8) | (cta_res[3]);
rdr_log(reader, "using ecm #%x for long viaccess ecm", csystem_data->last_geo.number_ecm);
}
}
}
reader->caid = 0x500;
memset(reader->prid, 0xff, sizeof(reader->prid));
insac[2] = 0xa4;
write_cmd(insac, NULL); // request unique id
insb8[4] = 0x07;
write_cmd(insb8, NULL); // read unique id
memcpy(reader->hexserial, cta_res + 2, 5);
// rdr_log(reader, "[viaccess-reader] type: Viaccess, ver: %s serial: %llu", ver, b2ll(5, cta_res+2));
rdr_log_sensitive(reader, "type: Viaccess (%sstandard atr), caid: %04X, serial: {%llu}",
atr[9] == 0x68 ? "" : "non-", reader->caid, (unsigned long long) b2ll(5, cta_res + 2));
i = 0;
insa4[2] = 0x00;
write_cmd(insa4, NULL); // select issuer 0
buf[0] = 0;
while((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
insc0[4] = 0x1a;
write_cmd(insc0, NULL); // show provider properties
cta_res[2] &= 0xF0;
reader->prid[i][0] = 0;
memcpy(&reader->prid[i][1], cta_res, 3);
memcpy(&csystem_data->availkeys[i][0], cta_res + 10, 16);
snprintf((char *)buf + cs_strlen((char *)buf), sizeof(buf) - cs_strlen((char *)buf), ",%06X", b2i(3, &reader->prid[i][1]));
// rdr_log(reader, "[viaccess-reader] buf: %s", buf);
insac[2] = 0xa5;
write_cmd(insac, NULL); // request sa
insb8[4] = 0x06;
write_cmd(insb8, NULL); // read sa
memcpy(&reader->sa[i][0], cta_res + 2, 4);
insa4[2] = 0x02;
write_cmd(insa4, NULL); // select next issuer
i++;
}
reader->nprov = i;
rdr_log(reader, "providers: %d (%s)", reader->nprov, buf + 1);
get_maturity(reader);
if(cfg.ulparent)
{
unlock_parental(reader);
}
rdr_log(reader, "ready for requests");
return OK;
}
bool dcw_crc(uint8_t *dw)
{
int8_t i;
for(i = 0; i < 16; i += 4)
{
if(dw[i + 3] != ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xFF))
{
return 0;
}
}
return 1;
}
static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
{
def_resp;
static const uint8_t insa4[] = { 0xca, 0xa4, 0x04, 0x00, 0x03 }; // set provider id
uint8_t ins88[] = { 0xca, 0x88, 0x00, 0x00, 0x00 }; // set ecm
uint8_t insf8[] = { 0xca, 0xf8, 0x00, 0x00, 0x00 }; // set geographic info
static const uint8_t insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x12 }; // read dcw
struct viaccess_data *csystem_data = reader->csystem_data;
// //XXX what is the 4th uint8_t for ??
int32_t ecm88Len = MIN(MAX_ECM_SIZE - 4, SCT_LEN(er->ecm) - 4);
if(ecm88Len < 1)
{
rdr_log(reader, "ECM: Size of ECM couldn't be correctly calculated.");
return ERROR;
}
uint8_t ecmData[ecm88Len];
memset(ecmData, 0, ecm88Len);
memcpy(ecmData, er->ecm + 4, ecm88Len);
uint8_t *ecm88Data = &ecmData[0];
uint32_t provid = 0;
int32_t rc = 0;
int32_t hasD2 = 0;
uint8_t hasE0 = 0;
int32_t has98 = 0;
int32_t has9635 = 0;
int32_t has9632 = 0;
int32_t curEcm88len = 0;
int32_t nanoLen = 0;
uint8_t *nextEcm;
uint8_t DE04[MAX_ECM_SIZE];
uint8_t nano9635ecm88Data[MAX_ECM_SIZE];
uint8_t nano9632ecm88Data[MAX_ECM_SIZE];
int32_t D2KeyID = 0;
int32_t curnumber_ecm = 0;
uint8_t SubECM = 0;
char key98Idx = 0;
// nanoD2 d2 02 0d 02 -> D2 nano, len 2
// 0b, 0f, 13 -> pre AES decrypt CW
// 0d, 11, 15 -> post AES decrypt CW
int32_t nanoD2 = 0; // knowns D2 nanos: 0x0b ,0x0d ,0x0f ,0x11, 0x13, 0x15
memset(DE04, 0, sizeof(DE04)); //fix dorcel de04 bug
nextEcm = ecm88Data;
while(ecm88Len > 0 && !rc)
{
if(ecm88Data[0] == 0x00 && ecm88Data[1] == 0x00)
{
// nano 0x00 and len 0x00 aren't valid... something is obviously wrong with this ecm.
rdr_log(reader, "ECM: Invalid ECM structure. Rejecting");
return ERROR;
}
// 80 33 nano 80 (ecm) + len (33)
if(ecm88Data[0] == 0x80) // nano 80, give ecm len
{
curEcm88len = ecm88Data[1];
nextEcm = ecm88Data + curEcm88len + 2;
ecm88Data += 2;
ecm88Len -= 2;
}
if(!curEcm88len) // there was no nano 80 -> simple ecm
{
curEcm88len = ecm88Len;
}
// d2 02 0d 02 -> D2 nano, len 2, select the AES key to be used
if(ecm88Data[0] == 0xd2)
{
// test if it needs AES decrypt
if(ecm88Data[2] == 0x0b)
{
nanoD2 = 0x0b;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0b");
}
if(ecm88Data[2] == 0x0d)
{
nanoD2 = 0x0d;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0d");
}
if(ecm88Data[2] == 0x0f)
{
nanoD2 = 0x0f;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0f");
}
if(ecm88Data[2] == 0x11)
{
nanoD2 = 0x11;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x11");
}
if(ecm88Data[2] == 0x13)
{
nanoD2 = 0x13;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x13");
}
if(ecm88Data[2] == 0x15)
{
nanoD2 = 0x15;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x15");
}
// use the d2 arguments to get the key # to be used
int32_t len = ecm88Data[1] + 2;
D2KeyID = ecm88Data[3];
ecm88Data += len;
ecm88Len -= len;
curEcm88len -= len;
hasD2 = 1;
}
else
{
hasD2 = 0;
}
// 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
// 09 -> use key #9
// 05 67 00
if((ecm88Data[0] == 0x90 || ecm88Data[0] == 0x40) && (ecm88Data[1] == 0x03 || ecm88Data[1] == 0x07))
{
uint8_t ident[3], keynr;
uint8_t *ecmf8Data = 0;
int32_t ecmf8Len = 0;
nanoLen = ecm88Data[1] + 2;
keynr = ecm88Data[4] & 0x0F;
// 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
// 09 -> use key #9
if(nanoLen > 5)
{
curnumber_ecm = (ecm88Data[6] << 8) | (ecm88Data[7]);
rdr_log_dbg(reader, D_READER, "checking if the ecm number (%x) match the card one (%x)", curnumber_ecm, csystem_data->last_geo.number_ecm);
// if we have an ecm number we check it.
// we can't assume that if the nano len is 5 or more we have an ecm number
// as some card don't support this
if(csystem_data->last_geo.number_ecm > 0)
{
if(csystem_data->last_geo.number_ecm == curnumber_ecm && !(ecm88Data[nanoLen - 1] == 0x01))
{
keynr = ecm88Data[5];
rdr_log_dbg(reader, D_READER, "keyToUse = %02x, ECM ending with %02x", ecm88Data[5], ecm88Data[nanoLen - 1]);
}
else
{
if(ecm88Data[nanoLen - 1] == 0x01)
{
rdr_log_dbg(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x) for provider %02x%02x%02x", ecm88Data[nanoLen - 1], curnumber_ecm, ecm88Data[2], ecm88Data[3], ecm88Data[4]);
}
rdr_log_dbg(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x)", ecm88Data[nanoLen - 1], curnumber_ecm);
ecm88Data = nextEcm;
ecm88Len -= curEcm88len;
continue; // loop to next ecm
}
}
else // long ecm but we don't have an ecm number so we have to try them all.
{
keynr = ecm88Data[5];
rdr_log_dbg(reader, D_READER, "keyToUse = %02x", ecm88Data[5]);
}
}
memcpy(ident, &ecm88Data[2], sizeof(ident));
provid = b2i(3, ident);
ident[2] &= 0xF0;
if(hasD2 && reader->aes_list)
{
// check that we have the AES key to decode the CW
// if not there is no need to send the ecm to the card
if(!aes_present(reader->aes_list, 0x500, (uint32_t)(provid & 0xFFFFF0) , D2KeyID))
{
return ERROR;
}
}
if(!chk_prov(reader, ident, keynr))
{
rdr_log_dbg(reader, D_READER, "ECM: provider or key not found on card");
snprintf(ea->msglog, MSGLOGSIZE, "provider(%02x%02x%02x) or key(%d) not found on card", ident[0], ident[1], ident[2], keynr);
return ERROR;
}
SubECM = ecm88Data[nanoLen - 1] ; // 01 permut 4 , FF no permut
ecm88Data += nanoLen;
ecm88Len -= nanoLen;
curEcm88len -= nanoLen;
if(ecm88Data[0] == 0x96 && ecm88Data[1] == 0x35)
{
rdr_log_dbg(reader, D_READER, "[viaccess-reader] nano 96/35 ECM detected!");
ecm88Data += 55;
has9635 = 1;
}
if(ecm88Data[0] == 0x96 && ecm88Data[1] == 0x32)
{
rdr_log_dbg(reader, D_READER, "[viaccess-reader] nano 96/32 ECM detected!");
ecm88Data += 52;
has9632 = 1;
}
if(ecm88Data[0] == 0xDE && ecm88Data[1] == 0x04)
{
rdr_log_dbg(reader, D_READER, "[viaccess-reader] nano DE/04 ECM detected!");
memcpy(DE04, &ecm88Data[0], 6);
ecm88Data += 6;
}
if((ecm88Data[0] == 0xD9) && (ecm88Data[1] == 0x0A))
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano D9/0A ECM detected!");
if((ecm88Data[12] == 0xE0) && (ecm88Data[13] == 0x02) && (ecm88Data[15] == 0x02)) // accept parental data 0F for ecm88Data[2]
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano E0/02 ECM detected!");
hasE0 = 1;
}
if((ecm88Data[16] == 0x98) && (ecm88Data[17] == 0x08))
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98/08 ECM detected!");
has98 = 1;
key98Idx = ecm88Data[25];
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 Index : %02X", key98Idx);
}
if((ecm88Data[19] == 0x98) && (ecm88Data[20] == 0x08))
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98/08 ECM detected!");
has98 = 1;
key98Idx = ecm88Data[28];
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 Index : %02X", key98Idx);
}
}
if((ecm88Data[0] == 0xE0) && (ecm88Data[1] == 0x02) && (ecm88Data[3] == 0x02)) // accept parental data 0F for ecm88Data[2]
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano E0/02 ECM detected!");
hasE0 = 1;
if((ecm88Data[4] == 0x98) && (ecm88Data[5] == 0x08))
{
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98/08 ECM detected!");
has98 = 1;
key98Idx = ecm88Data[13];
rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 Index : %02X", key98Idx);
}
}
if(csystem_data->last_geo.provid != provid)
{
csystem_data->last_geo.provid = provid;
csystem_data->last_geo.geo_len = 0;
csystem_data->last_geo.geo[0] = 0;
write_cmd(insa4, ident); // set provider
}
// Nano D2 0x0b, 0x0f, 0x13 -> pre AES decrypt CW
if(hasD2 && (nanoD2 == 0x0b|| nanoD2 == 0x0f|| nanoD2 == 0x13))
{
uint8_t *ecm88DataCW = ecm88Data;
int32_t cwStart = 0;
//int32_t cwStartRes = 0;
int32_t must_exit = 0;
// find CW start
while(cwStart < curEcm88len - 1 && !must_exit)
{
if(ecm88Data[cwStart] == 0xEA && ecm88Data[cwStart + 1] == 0x10)
{
ecm88DataCW = ecm88DataCW + cwStart + 2;
must_exit = 1;
}
cwStart = cwStart + ecm88Data[cwStart + 1] + 2; // parse via nanos
//cwStart++; // error if EA 10 in nanos datas
}
if(nanoD2 == 0x0f)
{
hdSurEncPhase1_D2_0F_11(ecm88DataCW);
hdSurEncPhase2_D2_0F_11(ecm88DataCW);
}
if(nanoD2 == 0x13)
{
hdSurEncPhase1_D2_13_15(ecm88DataCW);
}
// use AES from list to decrypt CW
rdr_log_dbg(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x", D2KeyID, (provid & 0xFFFFF0));
if(aes_decrypt_from_list(reader->aes_list, 0x500, (uint32_t)(provid & 0xFFFFF0), D2KeyID, &ecm88DataCW[0], 16) == 0)
{
snprintf(ea->msglog, MSGLOGSIZE, "Missing AES key(%d)[aka E%X]",D2KeyID, D2KeyID);
}
if(nanoD2 == 0x0f)
{
hdSurEncPhase1_D2_0F_11(ecm88DataCW);
}
if(nanoD2 == 0x13)
{
hdSurEncPhase2_D2_13_15(ecm88DataCW);
}
}
while(ecm88Len > 1 && ecm88Data[0] < 0xA0)
{
nanoLen = ecm88Data[1] + 2;
if(!ecmf8Data)
{
ecmf8Data = (uint8_t *)ecm88Data;
}
ecmf8Len += nanoLen;
ecm88Len -= nanoLen;
curEcm88len -= nanoLen;
ecm88Data += nanoLen;
}
if(ecmf8Len)
{
if(csystem_data->last_geo.geo_len != ecmf8Len || memcmp(csystem_data->last_geo.geo, ecmf8Data, csystem_data->last_geo.geo_len))
{
memcpy(csystem_data->last_geo.geo, ecmf8Data, ecmf8Len);
csystem_data->last_geo.geo_len = ecmf8Len;
insf8[3] = keynr;
insf8[4] = ecmf8Len;
write_cmd(insf8, ecmf8Data);
}
}
ins88[2] = ecmf8Len ? 1 : 0;
ins88[3] = keynr;
ins88[4] = (curEcm88len > 0xFF) ? 0x00 : curEcm88len;
//
// we should check the nano to make sure the ecm is valid
// we should look for at least 1 E3 nano, 1 EA nano and the F0 signature nano
//
// DE04
if(DE04[0] == 0xDE)
{
uint32_t l = curEcm88len - 6;
if(l > MAX_ECM_SIZE || curEcm88len <= 6) //don't known if this is ok...
{
rdr_log(reader, "ecm invalid/too long! len=%d", curEcm88len);
return ERROR;
}
memcpy(DE04 + 6, (uint8_t *)ecm88Data, l);
write_cmd(ins88, DE04); // request dcw
}
else if(has9635)
{
ins88[4] -= 0x37;
memcpy(nano9635ecm88Data, (uint8_t *)ecm88Data, ins88[4]);
write_cmd(ins88, nano9635ecm88Data);
}
else if(has9632)
{
ins88[4] -= 0x34;
memcpy(nano9632ecm88Data, (uint8_t *)ecm88Data, ins88[4]);
write_cmd(ins88, nano9632ecm88Data);
}
else
{
write_cmd(ins88, (uint8_t *)ecm88Data); // request dcw
}
write_cmd(insc0, NULL); // read dcw
switch(cta_res[0])
{
case 0xe8: // even
if(cta_res[1] == 8)
{
memcpy(ea->cw, cta_res + 2, 8);
rc = 1;
} break;
case 0xe9: // odd
if(cta_res[1] == 8)
{
memcpy(ea->cw + 8, cta_res + 2, 8);
rc = 1;
} break;
case 0xea: // complete
if(cta_res[1] == 16)
{
memcpy(ea->cw, cta_res + 2, 16);
rc = 1;
} break;
default :
ecm88Data = nextEcm;
ecm88Len -= curEcm88len;
rdr_log_dbg(reader, D_READER, "Error: card respondend %02X %02X, trying next ECM", cta_res[0], cta_res[1]);
snprintf(ea->msglog, MSGLOGSIZE, "key to use is not the current one, trying next ECM");
}
}
else
{
//ecm88Data = nextEcm;
//ecm88Len -= curEcm88len;
rdr_log_dbg(reader, D_READER, "ECM: Unknown ECM type");
snprintf(ea->msglog, MSGLOGSIZE, "Unknown ECM type");
return ERROR; /*Lets interupt the loop and exit, because we don't know this ECM type.*/
}
}
// Nano D2 0d, 11, 15 -> post AES decrypt CW
if(hasD2 && !dcw_crc(ea->cw) && (nanoD2 == 0x0d || nanoD2 == 0x11 || nanoD2 == 0x15))
{
if(nanoD2 == 0x11)
{
hdSurEncPhase1_D2_0F_11(ea->cw);
hdSurEncPhase2_D2_0F_11(ea->cw);
}
if(nanoD2 == 0x15)
{
hdSurEncPhase1_D2_13_15(ea->cw);
}
rdr_log_dbg(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x", D2KeyID, (provid & 0xFFFFF0));
rc = aes_decrypt_from_list(reader->aes_list, 0x500, (uint32_t)(provid & 0xFFFFF0), D2KeyID, ea->cw, 16);
if(rc == 0)
{
snprintf(ea->msglog, MSGLOGSIZE, "Missing AES key(%d)[aka E%X]",D2KeyID, D2KeyID);
}
if(nanoD2 == 0x11)
{
hdSurEncPhase1_D2_0F_11(ea->cw);
}
if(nanoD2 == 0x15)
{
hdSurEncPhase2_D2_13_15(ea->cw);
}
}
if (has98)
{
if (N98Init == 0)
{
MakeSubKeys(KeyS, key98Idx);
N98Init = 1;
}
uint8_t inp[16];
memcpy(inp, ea->cw, 16);
N98_decrypt(inp);
memcpy(ea->cw, inp, 16);
}
if (hasE0)
{
if (reader->initCA28)
{
uint8_t returnedcw[16];
memcpy(returnedcw, ea->cw, 16);
// Processing 3DES
// Processing even cw
des(returnedcw, reader->key_schedule1, 0); // decrypt
des(returnedcw, reader->key_schedule2, 1); // crypt
des(returnedcw, reader->key_schedule1, 0); // decrypt
// Processing odd cw
des(returnedcw + 8, reader->key_schedule1, 0); // decrypt
des(returnedcw + 8, reader->key_schedule2, 1); // crypt
des(returnedcw + 8, reader->key_schedule1, 0); // decrypt
// returning value
memcpy(ea->cw, returnedcw, 16);
}
else
{
snprintf(ea->msglog, MSGLOGSIZE, "Nano E0 detected, no valid boxkey + deskey defined: no decoding");
}
}
if (SubECM == 1)
{
uint8_t rw[16];
memcpy(rw, ea->cw, 16);
memcpy(ea->cw, rw + 4, 4);
memcpy(ea->cw + 4, rw, 4);
memcpy(ea->cw + 8, rw + 12, 4);
memcpy(ea->cw + 12, rw + 8, 4);
}
return (rc ? OK : ERROR);
}
static int32_t viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
uint32_t provid = 0;
rdr_log_dbg(rdr, D_EMM, "Entered viaccess_get_emm_type ep->emm[0]=%02x", ep->emm[0]);
if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03)
{
provid = b2i(3, ep->emm + 5);
provid &= 0xFFFFF0;
i2b_buf(4, provid, ep->provid);
}
switch(ep->emm[0])
{
case 0x88:
ep->type = UNIQUE;
memset(ep->hexserial, 0, 8);
memcpy(ep->hexserial, ep->emm + 4, 4);
rdr_log_dbg(rdr, D_EMM, "UNIQUE");
if(!is_network_reader(rdr))
{
return (!memcmp(rdr->hexserial + 1, ep->hexserial, 4)); // local reader
}
else
{
return 1; // let server decide!
}
case 0x8A:
case 0x8B:
ep->type = GLOBAL;
rdr_log_dbg(rdr, D_EMM, "GLOBAL");
return 1;
case 0x8C:
case 0x8D:
ep->type = SHARED;
rdr_log_dbg(rdr, D_EMM, "SHARED (part)");
// We need those packets to pass otherwise we would never
// be able to complete EMM reassembly
return 1;
case 0x8E:
ep->type = SHARED;
rdr_log_dbg(rdr, D_EMM, "SHARED");
memset(ep->hexserial, 0, 8);
memcpy(ep->hexserial, ep->emm + 3, 3);
// local reader
int8_t i;
for(i = 0; i < rdr->nprov; i++)
{
if(!memcmp(&rdr->prid[i][2], ep->hexserial+1, 2))
{
return 1;
}
return (!memcmp(&rdr->sa[0][0], ep->hexserial, 3));
} /* fallthrough */
default:
ep->type = UNKNOWN;
rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
return 1;
}
}
static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
{
if(*emm_filters == NULL)
{
bool network = is_network_reader(rdr);
int8_t device_emm = ((rdr->deviceemm > 0) ? 1 : 0); // set to 1 if device specific emms should be catched too
const unsigned int max_filter_count = 4 + ((device_emm != 0 && rdr->nprov > 0) ? 1:0) + (3 * ((rdr->nprov > 0) ? (rdr->nprov - 1) : 0));
if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
{
return ERROR;
}
struct s_csystem_emm_filter *filters = *emm_filters;
*filter_count = 0;
int32_t idx = 0;
int32_t prov;
if(rdr->nprov > 0 && device_emm == 1)
{
filters[idx].type = EMM_GLOBAL; // 8A or 8B no reassembly needed!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8A;
filters[idx].mask[0] = 0xFE;
filters[idx].filter[3] = 0x80; // device specific emms
filters[idx].mask[3] = 0x80;
idx++;
}
// shared are most important put them on top, define first since viaccess produces a lot of filters!
for(prov = 0; (prov < rdr->nprov); prov++)
{
if((rdr->prid[prov][2] &0xF0) == 0xF0) // skip this not useful provider
{
continue;
}
filters[idx].type = EMM_SHARED; // 8C or 8D always first part of shared, second part delivered by 8E!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8C;
filters[idx].mask[0] = 0xFE;
if(rdr->nprov > 0)
{
memcpy(&filters[idx].filter[4], &rdr->prid[prov][2], 2);
filters[idx].mask[4] = 0xFF;
filters[idx].mask[5] = 0xF0; // ignore last digit since this is key on card indicator!
}
idx++;
filters[idx].type = EMM_SHARED; // 8E second part reassembly with 8c/8d needed!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8E;
filters[idx].mask[0] = 0xFF;
if(rdr->nprov > 0)
{
memcpy(&filters[idx].filter[1], &rdr->sa[prov][0], 3);
memset(&filters[idx].mask[1], 0xFF, 3);
}
idx++;
}
// globals are less important, define last since viaccess produces a lot of filters!
for(prov = 0; (prov < rdr->nprov); prov++)
{
if((rdr->prid[prov][2] &0xF0) == 0xF0) // skip this not useful provider
{
continue;
}
filters[idx].type = EMM_GLOBAL; // 8A or 8B no reassembly needed!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8A;
filters[idx].mask[0] = 0xFE;
if(rdr->nprov > 0)
{
memcpy(&filters[idx].filter[4], &rdr->prid[prov][2], 2);
filters[idx].mask[4] = 0xFF;
filters[idx].mask[5] = 0xF0; // ignore last digit since this is key on card indicator!
}
else if (device_emm == 0)
{
filters[idx].filter[3] = 0x00; // additional filter to cancel device specific emms
filters[idx].mask[3] = 0x80;
}
idx++;
}
filters[idx].type = EMM_UNIQUE;
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x88;
filters[idx].mask[0] = 0xFF;
if(!network) // network has only 3 digits out of 4
{
memcpy(&filters[idx].filter[1], rdr->hexserial + 1, 4);
memset(&filters[idx].mask[1], 0xFF, 4);
}
else
{
memcpy(&filters[idx].filter[1], rdr->hexserial + 1, 3);
memset(&filters[idx].mask[1], 0xFF, 3);
}
idx++;
*filter_count = idx;
}
return OK;
}
static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
def_resp;
static const uint8_t insa4[] = { 0xca, 0xa4, 0x04, 0x00, 0x03 }; // set provider id
uint8_t insf0[] = { 0xca, 0xf0, 0x00, 0x01, 0x22 }; // set adf
uint8_t insf4[] = { 0xca, 0xf4, 0x00, 0x01, 0x00 }; // set adf, encrypted
uint8_t ins18[] = { 0xca, 0x18, 0x01, 0x01, 0x00 }; // set subscription
uint8_t ins1c[] = { 0xca, 0x1c, 0x01, 0x01, 0x00 }; // set subscription, encrypted
struct viaccess_data *csystem_data = reader->csystem_data;
int32_t emmdatastart = 7;
if (ep->emm[1] == 0x01) // emm from cccam
{
emmdatastart = 12;
ep->emm[1] = 0x70; // (& 0x0f) of this byte is length, so 0x01 would increase the length by 256
ep->emm[2] -= 1;
if (ep->type == SHARED || ep->type == GLOBAL) // build missing 0x90 nano from provider at serial position
{
memcpy(ep->emm + 7, ep->emm + 3, 3);
ep->emm[5] = 0x90;
ep->emm[6] = 0x03;
ep->emm[9] |= 0x01;
ep->emm[10] = 0x9E;
ep->emm[11] = 0x20;
emmdatastart = 5;
}
}
if(ep->type == UNIQUE)
{
emmdatastart++;
}
if(ep->type == GLOBAL && emmdatastart == 7)
{
emmdatastart -= 4;
}
int32_t emmLen = SCT_LEN(ep->emm) - emmdatastart;
int32_t rc = 0;
rdr_log_dump(reader, ep->emm, emmLen + emmdatastart, "RECEIVED EMM VIACCESS");
int32_t emmUpToEnd;
uint8_t *emmParsed = ep->emm + emmdatastart;
int32_t provider_ok = 0;
uint32_t emm_provid = 0;
uint8_t keynr = 0;
int32_t ins18Len = 0;
uint8_t ins18Data[512];
uint8_t insData[512];
uint8_t *nano81Data = 0;
uint8_t *nano91Data = 0;
uint8_t *nano92Data = 0;
uint8_t *nano9EData = 0;
uint8_t *nanoF0Data = 0;
uint8_t *nanoA9Data = 0;
for(emmUpToEnd = emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1]))
{
rdr_log_dump(reader, emmParsed, emmParsed[1] + 2, "NANO");
if(emmParsed[0] == 0x90 && emmParsed[1] == 0x03)
{
/* identification of the service operator */
uint8_t soid[3], ident[3], i;
for(i = 0; i < 3; i++)
{
soid[i] = ident[i] = emmParsed[2 + i];
}
ident[2] &= 0xF0;
emm_provid = b2i(3, ident);
keynr = soid[2] & 0x0F;
if(chk_prov(reader, ident, keynr))
{
provider_ok = 1;
}
else
{
rdr_log(reader, "EMM: ignored since provider or key not present on card (%x, %x)", emm_provid, keynr);
return SKIPPED;
}
// check if the provider changes. If yes, set the new one. If not, don't... card will return an error if we do.
if(csystem_data->last_geo.provid != emm_provid)
{
write_cmd(insa4, ident);
if(cta_res[cta_lr - 2] != 0x90 || cta_res[cta_lr - 1] != 0x00)
{
rdr_log_dump(reader, insa4, 5, "set provider cmd:");
rdr_log_dump(reader, soid, 3, "set provider data:");
rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
return ERROR;
}
}
// as we are maybe changing the used provider, clear the cache, so the next ecm will re-select the correct one
csystem_data->last_geo.provid = 0;
csystem_data->last_geo.geo_len = 0;
csystem_data->last_geo.geo[0] = 0;
}
else if(emmParsed[0] == 0x9e && emmParsed[1] == 0x20)
{
/* adf */
if(!nano91Data)
{
/* adf is not crypted, so test it */
uint8_t custwp;
uint8_t *afd;
custwp = reader->sa[0][3];
afd = (uint8_t *)emmParsed + 2;
if(afd[31 - custwp / 8] & (1 << (custwp & 7)))
{
rdr_log_dbg(reader, D_READER, "emm for our card %08X", b2i(4, &reader->sa[0][0]));
}
else
{
rdr_log_dbg(reader, D_READER, "emm not suitable for our card %08X", b2i(4, &reader->sa[0][0]));
return SKIPPED;
}
}
// memorize
nano9EData = emmParsed;
}
else if(emmParsed[0] == 0x81)
{
nano81Data = emmParsed;
}
else if(emmParsed[0] == 0x91 && emmParsed[1] == 0x08)
{
nano91Data = emmParsed;
}
else if(emmParsed[0] == 0x92 && emmParsed[1] == 0x08)
{
nano92Data = emmParsed;
}
else if(emmParsed[0] == 0xF0 && emmParsed[1] == 0x08)
{
nanoF0Data = emmParsed;
}
else if(emmParsed[0] == 0xF0 && emmParsed[1] == 0x10 && (((emm_provid >> 8) == 0x0419) || ((emm_provid >> 8) == 0x0702)))
{
nanoF0Data = emmParsed;
}
else if(emmParsed[0] == 0xD8 && emmParsed[2] == 0x45)
{
uint8_t pos = 4 + emmParsed[3];
char *tmpbuf;
if(emmParsed[pos] == 0x46 && ((emmParsed[pos+1] - emmParsed[1]) == pos))
{
if(cs_malloc(&tmpbuf, emmParsed[pos + 1]))
{
cs_strncpy(tmpbuf, (char *)emmParsed + pos + 2, emmParsed[pos + 1]);
rdr_log(reader, "Viaccess EMM-text: %s", tmpbuf);
NULLFREE(tmpbuf);
}
}
}
else
{
/* other nanos */
show_subs(reader, emmParsed);
if(emmParsed[0] == 0xA9 && ep->type == SHARED) // check on shared (reassembled) emm if all classes are present and up to date on card: error 90 40
{
if(!emm_provid)
{
rdr_log(reader, "no provid in shared emm -> skipped!");
return SKIPPED;
}
int8_t match = add_find_class(reader, emm_provid, emmParsed + 2, emmParsed[1], 0);
if(match == -2)
{
rdr_log(reader, "shared emm provid %06X all classes have entitlementdate already same or newer -> skipped!", emm_provid);
return SKIPPED;
}
nanoA9Data = emmParsed;
}
memcpy(ins18Data + ins18Len, emmParsed, emmParsed[1] + 2);
ins18Len += emmParsed [1] + 2;
}
}
if(!provider_ok)
{
rdr_log_dbg(reader, D_READER, "provider not found in emm, continue anyway");
// force key to 1...
keynr = 1;
// return ERROR;
}
if(!nanoF0Data)
{
rdr_log_dump(reader, ep->emm, ep->emmlen, "can't find 0xf0 in emm...");
return ERROR; // error
}
if(nano9EData)
{
if(!nano91Data)
{
// set adf
insf0[3] = keynr; // key
insf0[4] = nano9EData[1] + 2;
write_cmd(insf0, nano9EData);
if(cta_res[cta_lr - 2] != 0x90 || cta_res[cta_lr - 1] != 0x00)
{
rdr_log_dump(reader, insf0, 5, "set adf cmd:");
rdr_log_dump(reader, nano9EData, insf0[4] , "set adf data:");
rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
return ERROR;
}
}
else
{
// set adf crypte
insf4[3] = keynr; // key
insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2;
memcpy(insData, nano91Data, nano91Data[1] + 2);
memcpy(insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
write_cmd(insf4, insData);
if((cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 2] != 0x91) || cta_res[cta_lr - 1] != 0x00)
{
rdr_log_dump(reader, insf4, 5, "set adf encrypted cmd:");
rdr_log_dump(reader, insData, insf4[4], "set adf encrypted data:");
rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
return ERROR;
}
}
}
if(!nano92Data)
{
// send subscription
ins18[2] = nano9EData ? 0x01 : 0x00; // found 9E nano ?
ins18[3] = keynr; // key
ins18[4] = ins18Len + nanoF0Data[1] + 2;
memcpy(insData, ins18Data, ins18Len);
memcpy(insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
write_cmd(ins18, insData);
if((cta_res[cta_lr - 2] == 0x90 || cta_res[cta_lr - 2] == 0x91) && cta_res[cta_lr - 1] == 0x00)
{
if(nanoA9Data)
{
add_find_class(reader, emm_provid, nanoA9Data + 2, nanoA9Data[1], 1);
rdr_log(reader, "Your subscription data was updated.");
}
rc = 1; // written
}
else
{
rdr_log_dump(reader, ins18, 5, "set subscription cmd:");
rdr_log_dump(reader, insData, ins18[4], "set subscription data:");
if(!(cta_res[cta_lr -2] == 0x90 && cta_res[cta_lr - 1] == 0x40)) // dont throw softerror 9040 in log!
{
rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
}
else
{
rc = 2; // skipped
}
}
}
else
{
// send subscription encrypted
if(!nano81Data)
{
rdr_log_dump(reader, ep->emm, ep->emmlen, "0x92 found, but can't find 0x81 in emm...");
return ERROR; // error
}
ins1c[2] = nano9EData ? 0x01 : 0x00; // found 9E nano ?
if(ep->type == UNIQUE)
{
ins1c[2] = 0x02;
}
ins1c[3] = keynr; // key
ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
memcpy(insData, nano92Data, nano92Data[1] + 2);
memcpy(insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
memcpy(insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
write_cmd(ins1c, insData);
if((cta_res[cta_lr - 2] == 0x90 || cta_res[cta_lr - 2] == 0x91) && (cta_res[cta_lr - 1] == 0x00 || cta_res[cta_lr - 1] == 0x08))
{
rdr_log(reader, "update successfully written");
}
if(cta_res[cta_lr - 2] == 0x98 && cta_res[cta_lr - 1] == 0x00 )
{
static const uint8_t insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC
static uint8_t ins8702_data[] = { 0x00, 0x00, 0x11};
static uint8_t ins8704[] = { 0x87, 0x04, 0x00, 0x00, 0x07 };
static uint8_t ins8706[] = { 0x87, 0x06, 0x00, 0x00, 0x04 };
write_cmd(insFAC, ins8702_data);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
write_cmd(ins8704, NULL);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
write_cmd(ins8706, NULL);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
csystem_data->last_geo.number_ecm = (cta_res[2] << 8) | (cta_res[3]);
rdr_log(reader, "using ecm #%x for long viaccess ecm", csystem_data->last_geo.number_ecm);
}
}
}
}
rc = 1;
}
return rc;
}
static int32_t viaccess_card_info(struct s_reader *reader)
{
def_resp;
int32_t i, l;
time_t now;
struct tm timeinfo;
uint16_t tmpdate;
uint8_t insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
uint8_t insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
uint8_t insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
uint8_t insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
static const uint8_t ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
uint8_t cls[] = { 0x00, 0x21, 0xff, 0x9f};
uint8_t prebook[] = {0xFC, 0x00, 0x00, 0xFE, 0xFF, 0xFF};
static const uint8_t pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
struct viaccess_data *csystem_data = reader->csystem_data;
csystem_data->last_geo.provid = 0;
csystem_data->last_geo.geo_len = 0;
csystem_data->last_geo.geo[0] = 0;
rdr_log(reader, "card detected");
cs_clear_entitlement(reader); //reset the entitlements
// set pin
write_cmd(ins24, pin);
insac[2] = 0xa4;
write_cmd(insac, NULL); // request unique id
insb8[4] = 0x07;
write_cmd(insb8, NULL); // read unique id
rdr_log_sensitive(reader, "serial: {%llu}", (unsigned long long) b2ll(5, cta_res + 2));
insa4[2] = 0x00;
write_cmd(insa4, NULL); // select issuer 0
for(i = 1; (cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0); i++)
{
bool added = false;
uint32_t l_provid, l_sa;
uint8_t l_name[64];
insc0[4] = 0x1a;
write_cmd(insc0, NULL); // show provider properties
cta_res[2] &= 0xF0;
l_provid = b2i(3, cta_res);
insac[2] = 0xa5;
write_cmd(insac, NULL); // request sa
insb8[4] = 0x06;
write_cmd(insb8, NULL); // read sa
l_sa = b2i(4, cta_res + 2);
insac[2] = 0xa7;
write_cmd(insac, NULL); // request name
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read name nano + len
l = cta_res[1];
insb8[4] = l;
write_cmd(insb8, NULL); // read name
cta_res[l] = 0;
trim((char *)cta_res);
if(cta_res[0])
{
snprintf((char *)l_name, sizeof(l_name), ", name: %.55s", cta_res);
}
else
{
l_name[0] = 0;
}
// read GEO
insac[2] = 0xa6;
write_cmd(insac, NULL); // request GEO
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read GEO nano + len
l = cta_res[1];
char tmp[l * 3 + 1];
insb8[4] = l;
write_cmd(insb8, NULL); // read geo
rdr_log_sensitive(reader, "provider: %d, id: {%06X%s}, sa: {%08X}, geo: %s", i, l_provid, l_name, l_sa, (l < 4) ? "empty" : cs_hexdump(1, cta_res, l, tmp, sizeof(tmp)));
// read classes subscription
insac[2] = 0xa9;
insac[4] = 4;
if(!reader->read_old_classes)
{
now = time(NULL) - (24 * 60 * 60);
cs_gmtime_r(&now, &timeinfo);
tmpdate = timeinfo.tm_mday | ((timeinfo.tm_mon + 1) << 5) | ((timeinfo.tm_year - 80) << 9);
cls[0] = tmpdate >> 8;
cls[1] = tmpdate & 0xff;
}
write_cmd(insac, cls); // request class subs
while((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read class subs nano + len
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
l = cta_res[1];
insb8[4] = l;
write_cmd(insb8, NULL); // read class subs
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00 || cta_res[cta_lr - 1] == 0x08))
{
show_class(reader, NULL, l_provid, cta_res, cta_lr - 2);
added = true;
}
}
}
if(!added)
{
// add entitlement info for provid without class
cs_add_entitlement(reader, reader->caid, l_provid, 0, 0, 0, 0, 5, 1);
}
// Read List of «pre-booked pay-per-view per programme» entitlements within the range [INUMB, FNUMB]
insac[2] = 0xaa;
insac[4] = 6;
write_cmd(insac, prebook); // request class subs
while((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read PPV
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
l = cta_res[1];
insb8[4] = l;
write_cmd(insb8, NULL); // read PPV
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00 || cta_res[cta_lr - 1] == 0x08))
{
time_t start_t, end_t;
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_year = (cta_res[2] >> 4) + 116;
tm.tm_mon = (cta_res[2] & 0xF) - 1;
tm.tm_mday = 1;
start_t = cs_timegm(&tm);
tm.tm_year = (cta_res[5] >> 4) + 116;
tm.tm_mon = (cta_res[5] & 0xF) - 1;
if ((tm.tm_mon == 0) || (tm.tm_mon == 2) || (tm.tm_mon == 4) || (tm.tm_mon == 6) || (tm.tm_mon == 7) || (tm.tm_mon == 9) || (tm.tm_mon == 11))
{
tm.tm_mday = 31;
}
else if ((tm.tm_mon == 3) || (tm.tm_mon == 5) || (tm.tm_mon == 8) || (tm.tm_mon == 10))
{
tm.tm_mday = 30;
}
else if ((tm.tm_mon == 1) && (((cta_res[5] >> 4) % 4) == 0))
{
tm.tm_mday = 29;
}
else
{
tm.tm_mday = 28;
}
end_t = cs_timegm(&tm);
cs_add_entitlement(reader, reader->caid, l_provid, cta_res[1], 0, start_t, end_t, 2, 1);
}
}
}
insac[4] = 0;
insa4[2] = 0x02;
write_cmd(insa4, NULL); // select next provider
}
// return ERROR;
// Start process init CA 28
reader->initCA28=0;
int32_t lenboxkey = reader->boxkey_length;
int32_t lendeskey = reader->des_key_length;
if ((lenboxkey >= 4) && (lendeskey > 0))
{
uint8_t ins28[] = { 0xCA, 0x28, 0x00, 0x00, 0x04 }; //Init for nanoE0 ca28
ins28[4] = (uint8_t) lenboxkey;
uint8_t ins28_data[4];
memcpy(ins28_data, reader->boxkey, 4);
write_cmd(ins28, ins28_data); // unlock card to reply on E002xxyy
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
rdr_log(reader, "CA 28 initialisation successful!");
// init 3DES key
des_set_key(reader->des_key, reader->key_schedule1);
des_set_key(reader->des_key+8, reader->key_schedule2);
reader->initCA28=1;
}
else
{
rdr_log(reader, "CA 28 initialisation failed! CA 28 refused");
}
}
//end process init CA 28
return OK;
}
static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *client, EMM_PACKET *ep)
{
uint8_t *buffer = ep->emm;
int16_t *len = &ep->emmlen;
int32_t pos = 0, i;
int16_t k;
int32_t prov, provid = 0;
struct emm_rass *r_emm = NULL;
// Viaccess
if(*len > 500)
{
return 0;
}
switch(buffer[0])
{
case 0x8c:
case 0x8d:
// emm-s part 1
provid = b2i(3, ep->emm + 5); // extract provid from emm
provid &= 0xFFFFF0; // last digit is dont care
r_emm = find_rabuf(client, provid, (uint8_t) buffer[0], 1);
if(!r_emm)
{
cs_log("[viaccess] ERROR: Can't allocate EMM reassembly buffer.");
return 0;
}
if(!memcmp(&r_emm->emm, &buffer[0], *len)) // skip same shared emm, this make sure emmlen isnt replaced. emmlen = 0 means this shared emm has been used for reassembly
{
return 0;
}
memset(&r_emm->emm[0], 0, sizeof(r_emm->emm)); // zero it!
memcpy(&r_emm->emm[0], &buffer[0], *len); // put the fresh new shared emm
r_emm->emmlen = *len; // put the emmlen indicating that this shared emm isnt being reassembled
rdr_log_dump_dbg(rdr, D_EMM, r_emm->emm, r_emm->emmlen, "%s: received fresh emm-gh for provid %06X", __func__, provid);
return 0;
case 0x8e:
// emm-s part 2
for(prov = 0; prov < rdr->nprov ; prov++)
{
if(!memcmp(&buffer[3], &rdr->sa[prov][0], 3))
{
//matching sa found!
if(is_network_reader(rdr))
{
provid = b2i(4, ep->provid); // use provid from emm since we have nothing better!
provid &= 0xFFFFF0; // last digit is dont care
}
else
{
provid = b2i(4, rdr->prid[prov]); // get corresponding provid from reader since there is no provid in emm payload!
provid &= 0xFFFFF0; // last digit is dont care
}
r_emm = find_rabuf(client, provid, 0, 0); // nano = don't care, the shared 8c or 8d not been written gets returned!
if(!r_emm || !r_emm->emmlen)
{
continue; // match but no emm-gh found for this provider
}
else
{
break; // stop searching-> emm-gh found!
}
}
}
if(!r_emm || !r_emm->emmlen)
{
return 0; // stop -> no emm-gh found!
}
//extract nanos from emm-gh and emm-s
uint8_t emmbuf[512];
rdr_log_dbg(rdr, D_EMM, "%s: start extracting nanos", __func__);
//extract from emm-gh
for(i = 3; i < r_emm->emmlen; i += r_emm->emm[i + 1] + 2)
{
//copy nano (length determined by i+1)
memcpy(emmbuf + pos, r_emm->emm + i, r_emm->emm[i + 1] + 2);
pos += r_emm->emm[i + 1] + 2;
}
if(buffer[2] == 0x2c)
{
//add 9E 20 nano + first 32 uint8_ts of emm content
memcpy(emmbuf + pos, "\x9E\x20", 2);
memcpy(emmbuf + pos + 2, buffer + 7, 32);
pos += 34;
//add F0 08 nano + 8 subsequent uint8_ts of emm content
memcpy(emmbuf + pos, "\xF0\x08", 2);
memcpy(emmbuf + pos + 2, buffer + 39, 8);
pos += 10;
}
else if(buffer[2] == 0x34 && (((provid >> 8) == 0x0419) || ((provid >> 8) == 0x0702)))
{
//add 9E 20 nano + first 32 uint8_ts of emm content
memcpy(emmbuf + pos, "\x9E\x20", 2);
memcpy(emmbuf + pos + 2, buffer + 7, 32);
pos += 34;
//add F0 10 nano + 16 subsequent uint8_ts of emm content
memcpy(emmbuf + pos, "\xF0\x10", 2);
memcpy(emmbuf + pos + 2, buffer + 39, 16);
pos += 18;
}
else
{
//extract from variable emm-s
for(k = 7; k < (*len); k += buffer[k + 1] + 2)
{
//copy nano (length determined by k+1)
memcpy(emmbuf + pos, buffer + k, buffer[k + 1] + 2);
pos += buffer[k + 1] + 2;
}
}
rdr_log_dump_dbg(rdr, D_EMM, buffer, *len, "%s: %s emm-s", __func__, (buffer[2] == 0x2c) ? "fixed" : "variable");
emm_sort_nanos(buffer + 7, emmbuf, pos);
pos += 7;
//calculate emm length and set it on position 2
buffer[2] = pos - 3;
rdr_log_dump_dbg(rdr, D_EMM, r_emm->emm, r_emm->emmlen, "%s: emm-gh provid %06X", __func__, provid);
rdr_log_dump_dbg(rdr, D_EMM, buffer, pos, "%s: assembled emm", __func__);
*len = pos;
r_emm->emmlen = 0; // mark this shared 8c or 8d as being used for reassembly and send to reader!
break;
}
return 1;
}
const struct s_cardsystem reader_viaccess =
{
.desc = "viaccess",
.caids = (uint16_t[]){ 0x05, 0 },
.do_emm_reassembly = viaccess_reassemble_emm,
.do_emm = viaccess_do_emm,
.do_ecm = viaccess_do_ecm,
.card_info = viaccess_card_info,
.card_init = viaccess_card_init,
.get_emm_type = viaccess_get_emm_type,
.get_emm_filter = viaccess_get_emm_filter,
};
#endif