1 | #include "globals.h"
|
---|
2 | #include <math.h>
|
---|
3 | #ifdef READER_NAGRA_MERLIN
|
---|
4 | #include "cscrypt/bn.h"
|
---|
5 | #include "cscrypt/idea.h"
|
---|
6 | #include "cscrypt/sha256.h"
|
---|
7 | #include "cscrypt/aescbc.h"
|
---|
8 | #include "csctapi/icc_async.h"
|
---|
9 | #include "oscam-time.h"
|
---|
10 | #include "reader-common.h"
|
---|
11 | #include "oscam-work.h"
|
---|
12 | #include "cscrypt/des.h"
|
---|
13 | #include "cscrypt/mdc2.h"
|
---|
14 | #include "reader-nagracak7.h"
|
---|
15 |
|
---|
16 | const unsigned char exponent[] = {0x01, 0x00, 0x01};
|
---|
17 | const unsigned char d00ff[] = {0x00,0xff,0xff,0xFF};
|
---|
18 | const unsigned char irdid[] = {0x64,0x65,0x6D,0x6F};
|
---|
19 | const unsigned char data1[] = {0x00,0x00,0x00,0x01};
|
---|
20 |
|
---|
21 | struct nagra_data
|
---|
22 | {
|
---|
23 | IDEA_KEY_SCHEDULE ksSession;
|
---|
24 | int8_t is_pure_nagra;
|
---|
25 | int8_t is_tiger;
|
---|
26 | int8_t is_n3_na;
|
---|
27 | int8_t has_dt08;
|
---|
28 | int8_t swapCW;
|
---|
29 | uint8_t ExpiryDate[2];
|
---|
30 | uint8_t ActivationDate[2];
|
---|
31 | uint8_t plainDT08RSA[64];
|
---|
32 | uint8_t IdeaCamKey[16];
|
---|
33 | uint8_t sessi[16];
|
---|
34 | uint8_t signature[8];
|
---|
35 | uint8_t cam_state[3];
|
---|
36 | uint32_t Date_ird;
|
---|
37 | uint32_t Provider_ID_tiers;
|
---|
38 | uint16_t tiers;
|
---|
39 | uint32_t Expire_date_tiers_2;
|
---|
40 | uint32_t Begin_date_tiers_2;
|
---|
41 | uint16_t tiers_2;
|
---|
42 | int32_t num_records;
|
---|
43 | };
|
---|
44 |
|
---|
45 | // Datatypes
|
---|
46 | #define IRDINFO 0x03
|
---|
47 | #define TIERS 0x0C
|
---|
48 | #define SYSID 0x05
|
---|
49 | #define allproviders 0x06
|
---|
50 |
|
---|
51 | #define SYSTEM_NAGRA 0x1800
|
---|
52 | #define SYSTEM_MASK 0xFF00
|
---|
53 |
|
---|
54 | static time_t tier_date(uint64_t date, char *buf, int32_t l)
|
---|
55 | {
|
---|
56 | time_t ut = +694224000L + (date>>1);
|
---|
57 | if(buf){
|
---|
58 | struct tm t;
|
---|
59 | cs_gmtime_r(&ut, &t);
|
---|
60 | snprintf(buf, l, "%04d/%02d/%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
|
---|
61 | }
|
---|
62 | return ut;
|
---|
63 | }
|
---|
64 |
|
---|
65 | void rsa_decrypt(unsigned char *edata50, int len,unsigned char *out, unsigned char *key, int keylen)
|
---|
66 | {
|
---|
67 | BN_CTX *ctx0 = BN_CTX_new();
|
---|
68 | #ifdef WITH_LIBCRYPTO
|
---|
69 | BN_CTX_start(ctx0);
|
---|
70 | #endif
|
---|
71 | BIGNUM *bnN0 = BN_CTX_get(ctx0);
|
---|
72 | BIGNUM *bnE0 = BN_CTX_get(ctx0);
|
---|
73 | BIGNUM *bnCT0 = BN_CTX_get(ctx0);
|
---|
74 | BIGNUM *bnPT0 = BN_CTX_get(ctx0);
|
---|
75 | BN_bin2bn(&key[0], keylen, bnN0);
|
---|
76 | BN_bin2bn(exponent, 0x03, bnE0);
|
---|
77 | BN_bin2bn(&edata50[0], len, bnCT0);
|
---|
78 | BN_mod_exp(bnPT0, bnCT0, bnE0, bnN0, ctx0);
|
---|
79 | memset(out,0x00,len);
|
---|
80 | BN_bn2bin(bnPT0, out+ (len- BN_num_bytes(bnPT0)));
|
---|
81 | BN_CTX_end(ctx0);
|
---|
82 | BN_CTX_free(ctx0);
|
---|
83 | }
|
---|
84 |
|
---|
85 | static void addProvider(struct s_reader *reader, unsigned char *cta_res)
|
---|
86 | {
|
---|
87 | int32_t i;
|
---|
88 | int32_t toadd = 1;
|
---|
89 | for(i = 0; i < reader->nprov; i++){
|
---|
90 | if((cta_res[19] == reader->prid[i][2]) && (cta_res[20] == reader->prid[i][3])){
|
---|
91 | toadd = 0;
|
---|
92 | }
|
---|
93 | }
|
---|
94 | if(toadd){
|
---|
95 | reader->prid[reader->nprov][0] = 0;
|
---|
96 | reader->prid[reader->nprov][1] = 0;
|
---|
97 | reader->prid[reader->nprov][2] = cta_res[19];
|
---|
98 | reader->prid[reader->nprov][3] = cta_res[20];
|
---|
99 | memcpy(reader->sa[reader->nprov], reader->sa[0], 4);
|
---|
100 | reader->nprov += 1;
|
---|
101 | }
|
---|
102 | }
|
---|
103 |
|
---|
104 | typedef struct{
|
---|
105 | uint32_t Expire_date_tiers;
|
---|
106 | uint32_t Begin_date_tiers;
|
---|
107 | uint16_t tiers;
|
---|
108 | int32_t num_records;
|
---|
109 | uint32_t Provider_ID_tiers;
|
---|
110 | } tiers_rec;
|
---|
111 |
|
---|
112 | static int32_t ParseDataType(struct s_reader *reader, unsigned char dt, unsigned char *cta_res, uint16_t cta_lr)
|
---|
113 | {
|
---|
114 | struct nagra_data *csystem_data = reader->csystem_data;
|
---|
115 | char ds[20], de[16];
|
---|
116 | IDEA_KEY_SCHEDULE ks;
|
---|
117 | switch(dt)
|
---|
118 | {
|
---|
119 |
|
---|
120 | case TIERS:
|
---|
121 | if((cta_res[13] >= 0x20) && (cta_lr != 0x10))
|
---|
122 | {
|
---|
123 | uint16_t chid = csystem_data->tiers;
|
---|
124 | if(reader->caid==0x1860 || reader->caid == 0x1830 || reader->caid == 0x1843)
|
---|
125 | {
|
---|
126 | int32_t id = b2i(2,cta_res +19);
|
---|
127 | csystem_data->tiers = b2i(2,cta_res +23);
|
---|
128 | rdr_log_dbg(reader, D_READER, "Provid : %04X", id);
|
---|
129 | rdr_log_dbg(reader, D_READER, "ID : %04X", chid);
|
---|
130 | cs_add_entitlement(
|
---|
131 | reader,
|
---|
132 | reader->caid,
|
---|
133 | id,
|
---|
134 | chid,
|
---|
135 | 0,
|
---|
136 | tier_date(b2ll(4, cta_res + 42)-0x7f7, ds, 15), // noch nicht richtig
|
---|
137 | tier_date(b2ll(4, cta_res + 28)-0x7f7, de, 15),
|
---|
138 | 4,
|
---|
139 | 1);
|
---|
140 |
|
---|
141 | rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
|
---|
142 | addProvider(reader, cta_res);
|
---|
143 | }
|
---|
144 | if(reader->caid==0x186A || reader->caid == 0x1882 )
|
---|
145 | {
|
---|
146 | int32_t id = (cta_res[19] * 256) | cta_res[20];
|
---|
147 | cs_add_entitlement(
|
---|
148 | reader,
|
---|
149 | reader->caid,
|
---|
150 | id,
|
---|
151 | chid,
|
---|
152 | 0,
|
---|
153 | tier_date(b2ll(4, cta_res + 0x35)-0x7f7, ds, 15),
|
---|
154 | tier_date(b2ll(4, cta_res + 0x27)-0x7f7, de, 15),
|
---|
155 | 4,
|
---|
156 | 1);
|
---|
157 |
|
---|
158 | rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
|
---|
159 | addProvider(reader, cta_res);
|
---|
160 | }
|
---|
161 | }
|
---|
162 | break;
|
---|
163 |
|
---|
164 | //case 0x03:
|
---|
165 | case IRDINFO:
|
---|
166 | if(cta_res[13] == 0x4D || cta_res[13] == 0x50){
|
---|
167 | rdr_log_dump_dbg(reader, D_READER, cta_res+19, 2, "Provider ID :");
|
---|
168 | reader->card_valid_to=tier_date(b2ll(4, cta_res + 22)-0x7f7, ds, 15);
|
---|
169 | }
|
---|
170 | break;
|
---|
171 |
|
---|
172 | case 0x02:
|
---|
173 | reader->prid[0][0]=cta_res[17];
|
---|
174 | reader->prid[0][1]=cta_res[18];
|
---|
175 | reader->prid[0][2]=cta_res[19];
|
---|
176 | reader->prid[0][3]=cta_res[20];
|
---|
177 |
|
---|
178 | reader->prid[1][0] = 0x00;
|
---|
179 | reader->prid[1][1] = 0x00;
|
---|
180 | reader->prid[1][2] = 0x00;
|
---|
181 | reader->prid[1][3] = 0x00;
|
---|
182 | memcpy(reader->sa[1], reader->sa[0], 4);
|
---|
183 | reader->nprov += 1;
|
---|
184 | reader->caid = (SYSTEM_NAGRA | cta_res[25]);
|
---|
185 | break;
|
---|
186 |
|
---|
187 | //case 0x05:
|
---|
188 | case SYSID:
|
---|
189 | memcpy(reader->edata,cta_res+26,0x70);
|
---|
190 | reader->dt5num=cta_res[20];
|
---|
191 | rsa_decrypt(reader->edata,0x70,reader->out,mod1,sizeof(mod1));
|
---|
192 | if(reader->dt5num==0x00)
|
---|
193 | {
|
---|
194 | memcpy(reader->kdt05_00,&reader->out[18],0x5C+2);
|
---|
195 | memcpy(&reader->kdt05_00[0x5C+2],cta_res+26+0x70,6);
|
---|
196 | memcpy(reader->ideakey1,reader->out,16);
|
---|
197 | memcpy(reader->block3,cta_res+26+0x70+6,8);
|
---|
198 | idea_set_encrypt_key(reader->ideakey1, &ks);
|
---|
199 | memset(reader->v, 0, sizeof(reader->v));
|
---|
200 | idea_cbc_encrypt(reader->block3, reader->iout, 8, &ks, reader->v, IDEA_DECRYPT);
|
---|
201 | memcpy(&reader->kdt05_00[0x5C+2+6],reader->iout,8);
|
---|
202 | rdr_log_dump_dbg(reader, D_READER, reader->kdt05_00, sizeof(reader->kdt05_00), "DT05_00: ");
|
---|
203 | }
|
---|
204 | if(reader->dt5num==0x10)
|
---|
205 | {
|
---|
206 | memcpy(reader->kdt05_10,&reader->out[16],6*16);
|
---|
207 | memcpy(reader->ideakey1,reader->out,16);
|
---|
208 | memcpy(reader->block3,cta_res+26+0x70,8);
|
---|
209 | idea_set_encrypt_key(reader->ideakey1, &ks);
|
---|
210 | memset(reader->v, 0, sizeof(reader->v));
|
---|
211 | idea_cbc_encrypt(reader->block3, reader->iout, 8, &ks, reader->v, IDEA_DECRYPT);
|
---|
212 | memcpy(&reader->kdt05_10[6*16],reader->iout,8);
|
---|
213 | rdr_log_dump_dbg(reader, D_READER, reader->kdt05_10, sizeof(reader->kdt05_10), "DT05_10: ");
|
---|
214 | }
|
---|
215 | if(cta_res[8] != 0x07)
|
---|
216 | {
|
---|
217 | reader->prid[reader->nprov][0] = 0;
|
---|
218 | reader->prid[reader->nprov][1] = 0;
|
---|
219 | reader->prid[reader->nprov][2] = cta_res[19];
|
---|
220 | reader->prid[reader->nprov][3] = cta_res[20];
|
---|
221 | }
|
---|
222 | break;
|
---|
223 |
|
---|
224 | default:
|
---|
225 | return OK;
|
---|
226 | }
|
---|
227 | return ERROR;
|
---|
228 | }
|
---|
229 |
|
---|
230 | static int32_t CAS7do_cmd(struct s_reader *reader, unsigned char dt,unsigned char len,unsigned char *res, uint16_t *rlen,int32_t sub,unsigned char retlen)
|
---|
231 | {
|
---|
232 | //unsigned char dtdata[0x10];
|
---|
233 | memset(reader->dtdata,0xCC,len);
|
---|
234 |
|
---|
235 | reader->dtdata[7]=0x04;
|
---|
236 | reader->dtdata[8]=0x04;
|
---|
237 |
|
---|
238 | reader->dtdata[ 9]=(sub>>16)&0xFF;
|
---|
239 | reader->dtdata[10]=(sub>>8)&0xFF;
|
---|
240 | reader->dtdata[11]=(sub)&0xFF;
|
---|
241 |
|
---|
242 | reader->dtdata[12]=dt;
|
---|
243 |
|
---|
244 | do_cas7_cmd(reader,res,rlen,reader->dtdata,sizeof(reader->dtdata),retlen);
|
---|
245 |
|
---|
246 | return true;
|
---|
247 | }
|
---|
248 |
|
---|
249 | static int32_t CAS7GetDataType(struct s_reader *reader, unsigned char dt)
|
---|
250 | {
|
---|
251 | def_resp;
|
---|
252 |
|
---|
253 | int32_t sub=0x00;
|
---|
254 | unsigned char retlen=0x10;
|
---|
255 | while(true)
|
---|
256 | {
|
---|
257 | CAS7do_cmd(reader,dt,0x10,cta_res,&cta_lr,sub,retlen);
|
---|
258 | // check auf 90 am ende ??
|
---|
259 |
|
---|
260 | uint32_t newsub=(cta_res[9]<<16)+(cta_res[10]<<8)+(cta_res[11]);
|
---|
261 | if(newsub==0xFFFFFF)
|
---|
262 | {
|
---|
263 | break;
|
---|
264 | }
|
---|
265 |
|
---|
266 | if(cta_res[12]==dt) // seqcounter check ??
|
---|
267 | {
|
---|
268 | unsigned char oretlen=retlen;
|
---|
269 | retlen=cta_res[13]+0x10+0x2;
|
---|
270 | while(retlen%0x10!=0x00)retlen++;
|
---|
271 |
|
---|
272 | if(retlen==oretlen)
|
---|
273 | {
|
---|
274 | sub=newsub+1;
|
---|
275 | retlen=0x10;
|
---|
276 | ParseDataType(reader,dt,cta_res,cta_lr);
|
---|
277 | }
|
---|
278 | }
|
---|
279 | else
|
---|
280 | {
|
---|
281 | break;
|
---|
282 | }
|
---|
283 | }
|
---|
284 |
|
---|
285 | return true;
|
---|
286 | }
|
---|
287 |
|
---|
288 | void sub_6AD78(uint32_t *dinit) // gbox function
|
---|
289 | {
|
---|
290 | uint32_t v0=(uint32_t)*dinit;
|
---|
291 | double f0;
|
---|
292 | f0=v0;
|
---|
293 | double f12=16807;
|
---|
294 | double f15=2147483647;
|
---|
295 | f12=f0*f12;
|
---|
296 | double v12;
|
---|
297 | v12=fmod(f12,f15);
|
---|
298 | *dinit=v12;
|
---|
299 | }
|
---|
300 |
|
---|
301 | void calc_cas7_exponent(uint32_t *dinit, unsigned char *out, uint8_t len)
|
---|
302 | {
|
---|
303 | memset(out,0x00,len);
|
---|
304 |
|
---|
305 | sub_6AD78(dinit);
|
---|
306 |
|
---|
307 | int R4=0;
|
---|
308 | int R5=0;
|
---|
309 | while(true)
|
---|
310 | {
|
---|
311 | uint32_t R0=(uint32_t)*dinit;
|
---|
312 | int R3=R4+3;
|
---|
313 | R5+=4;
|
---|
314 | if(R3>len)break;
|
---|
315 |
|
---|
316 | out[R5-1]=((R0 )&0xFF);
|
---|
317 | out[R5-2]=((R0>> 8)&0xFF);
|
---|
318 | out[R5-3]=((R0>>16)&0xFF);
|
---|
319 | out[R5-4]=((R0>>24)&0xFF);
|
---|
320 | R4+=4;
|
---|
321 | sub_6AD78(dinit);
|
---|
322 |
|
---|
323 | }
|
---|
324 |
|
---|
325 | uint32_t R0=(uint32_t)*dinit;
|
---|
326 | while(R4<len)
|
---|
327 | {
|
---|
328 | out[R4]=R0&0xFF;
|
---|
329 | R4++;
|
---|
330 | R0>>=8;
|
---|
331 | }
|
---|
332 |
|
---|
333 | out[0]&=0x03;
|
---|
334 | out[0x10]|=0x01;
|
---|
335 |
|
---|
336 | }
|
---|
337 |
|
---|
338 | void CAS7_getCamKey(struct s_reader *reader)
|
---|
339 | {
|
---|
340 | def_resp;
|
---|
341 | uint8_t cmd0e[] = {0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x09,0x0E,0x83,0x00,0x00,0x00,0x00,0x00,0x64,0x65,0x6D,0x6F,0x34,0x11,0x9D,
|
---|
342 | 0x7E,0xEE,0xCE,0x53,0x09,0x80,0xAE,0x6B,0x5A,0xEE,0x3A,0x41,0xCE,0x09,0x75,0xEF,0xA6,0xBF,0x1E,0x98,0x4F,
|
---|
343 | 0xA4,0x11,0x6F,0x43,0xCA,0xCD,0xD0,0x6E,0x69,0xFA,0x25,0xC1,0xF9,0x11,0x8E,0x7A,0xD0,0x19,0xC0,0xEB,0x00,
|
---|
344 | 0xC0,0x57,0x2A,0x40,0xB7,0xFF,0x8A,0xBB,0x25,0x21,0xD7,0x50,0xE7,0x35,0xA1,0x85,0xCD,0xA6,0xD3,0xDE,0xB3,
|
---|
345 | 0x3D,0x16,0xD4,0x94,0x76,0x8A,0x82,0x8C,0x70,0x25,0xD4,0x00,0xD0,0x64,0x8C,0x26,0xB9,0x5F,0x44,0xFF,0x73,
|
---|
346 | 0x70,0xAB,0x43,0xF5,0x68,0xA2,0xB1,0xB5,0x8A,0x8E,0x02,0x5F,0x96,0x06,0xA8,0xC3,0x4F,0x15,0xCD,0x99,0xC2,
|
---|
347 | 0x69,0xB8,0x35,0x68,0x11,0x4C,0x84,0x3E,0x94,0x1E,0x00,0x08,0x00,0x00,0xCC,0xCC,0xCC,0xCC};
|
---|
348 | do_cas7_cmd(reader,cta_res,&cta_lr,cmd0e,sizeof(cmd0e),0x20);
|
---|
349 | reader->dword_83DBC= (cta_res[18]<<24);
|
---|
350 | reader->dword_83DBC+=(cta_res[19]<<16);
|
---|
351 | reader->dword_83DBC+=(cta_res[20]<< 8);
|
---|
352 | reader->dword_83DBC+=(cta_res[21] );
|
---|
353 | calc_cas7_exponent(&reader->dword_83DBC,reader->cas7expo,0x11);
|
---|
354 | memcpy(reader->cardid,cta_res+14,4);
|
---|
355 | rdr_log_dump_dbg(reader, D_READER, reader->cardid, 0x04, "CardSerial: ");
|
---|
356 | memcpy(reader->hexserial + 2, reader->cardid,4);
|
---|
357 | memcpy(reader->sa[0],reader->cardid,2);
|
---|
358 | unsigned long datal=(cta_res[9]<<24)+(cta_res[10]<<16)+(cta_res[11]<<8)+(cta_res[12]);
|
---|
359 | datal++;
|
---|
360 | reader->data2[0]=(datal>>24)&0xFF;
|
---|
361 | reader->data2[1]=(datal>>16)&0xFF;
|
---|
362 | reader->data2[2]=(datal>> 8)&0xFF;
|
---|
363 | reader->data2[3]=(datal )&0xFF;
|
---|
364 |
|
---|
365 | BN_CTX *ctx0 = BN_CTX_new();
|
---|
366 | #ifdef WITH_LIBCRYPTO
|
---|
367 | BN_CTX_start(ctx0);
|
---|
368 | #endif
|
---|
369 | BIGNUM *bnN0 = BN_CTX_get(ctx0);
|
---|
370 | BIGNUM *bnE0 = BN_CTX_get(ctx0);
|
---|
371 | BIGNUM *bnCT0 = BN_CTX_get(ctx0);
|
---|
372 | BIGNUM *bnPT0 = BN_CTX_get(ctx0);
|
---|
373 | BN_bin2bn(&mod50[0], 0x50, bnN0);
|
---|
374 | BN_bin2bn(&reader->cas7expo[0], 0x11, bnE0);
|
---|
375 | BN_bin2bn(&data50[0], 0x50, bnCT0);
|
---|
376 | BN_mod_exp(bnPT0, bnCT0, bnE0, bnN0, ctx0);
|
---|
377 | memset(reader->data,0x00,sizeof(reader->data));
|
---|
378 | BN_bn2bin(bnPT0, reader->data+ (0x50- BN_num_bytes(bnPT0)));
|
---|
379 | BN_CTX_end(ctx0);
|
---|
380 | BN_CTX_free(ctx0);
|
---|
381 |
|
---|
382 | memcpy(&reader->step1[0],d00ff,4);
|
---|
383 | memcpy(&reader->step1[4],reader->data,0x50);
|
---|
384 | memcpy(&reader->step1[4+0x50],irdid,0x04);
|
---|
385 | memcpy(&reader->step1[4+4+0x50],data1,0x04);
|
---|
386 | memcpy(&reader->step1[4+4+4+0x50],reader->data2,0x04);
|
---|
387 |
|
---|
388 | BN_CTX *ctx1 = BN_CTX_new();
|
---|
389 | #ifdef WITH_LIBCRYPTO
|
---|
390 | BN_CTX_start(ctx1);
|
---|
391 | #endif
|
---|
392 | BIGNUM *bnN1 = BN_CTX_get(ctx1);
|
---|
393 | BIGNUM *bnE1 = BN_CTX_get(ctx1);
|
---|
394 | BIGNUM *bnCT1 = BN_CTX_get(ctx1);
|
---|
395 | BIGNUM *bnPT1 = BN_CTX_get(ctx1);
|
---|
396 | BN_bin2bn(&key60[0], 0x60, bnN1);
|
---|
397 | BN_bin2bn(&exp60[0], 0x60, bnE1);
|
---|
398 | BN_bin2bn(&reader->step1[0], 0x60, bnCT1);
|
---|
399 | BN_mod_exp(bnPT1, bnCT1, bnE1, bnN1, ctx1);
|
---|
400 | BN_bn2bin(bnPT1, reader->data+ (0x60- BN_num_bytes(bnPT1)));
|
---|
401 | BN_CTX_end(ctx1);
|
---|
402 | BN_CTX_free(ctx1);
|
---|
403 |
|
---|
404 | memcpy(&reader->step2[0],d00ff,4);
|
---|
405 | memcpy(&reader->step2[4],reader->cardid,4);
|
---|
406 | memcpy(&reader->step2[8],reader->data,0x60);
|
---|
407 |
|
---|
408 | BN_CTX *ctx2 = BN_CTX_new();
|
---|
409 | #ifdef WITH_LIBCRYPTO
|
---|
410 | BN_CTX_start(ctx2);
|
---|
411 | #endif
|
---|
412 | BIGNUM *bnN2 = BN_CTX_get(ctx2);
|
---|
413 | BIGNUM *bnE2 = BN_CTX_get(ctx2);
|
---|
414 | BIGNUM *bnCT2 = BN_CTX_get(ctx2);
|
---|
415 | BIGNUM *bnPT2 = BN_CTX_get(ctx2);
|
---|
416 | BN_bin2bn(&reader->kdt05_10[0], 0x68, bnN2);
|
---|
417 | BN_bin2bn(&exponent[0], 3, bnE2);
|
---|
418 | BN_bin2bn(&reader->step2[0], 0x68, bnCT2);
|
---|
419 | BN_mod_exp(bnPT2, bnCT2, bnE2, bnN2, ctx2);
|
---|
420 | BN_bn2bin(bnPT2, reader->data+ (0x68- BN_num_bytes(bnPT2)));
|
---|
421 | BN_CTX_end(ctx2);
|
---|
422 | BN_CTX_free(ctx2);
|
---|
423 |
|
---|
424 | memcpy(&reader->step3[0],d00ff,4);
|
---|
425 | memcpy(&reader->step3[4],reader->data,0x68);
|
---|
426 |
|
---|
427 | BN_CTX *ctx3 = BN_CTX_new();
|
---|
428 | #ifdef WITH_LIBCRYPTO
|
---|
429 | BN_CTX_start(ctx3);
|
---|
430 | #endif
|
---|
431 | BIGNUM *bnN3 = BN_CTX_get(ctx3);
|
---|
432 | BIGNUM *bnE3 = BN_CTX_get(ctx3);
|
---|
433 | BIGNUM *bnCT3 = BN_CTX_get(ctx3);
|
---|
434 | BIGNUM *bnPT3 = BN_CTX_get(ctx3);
|
---|
435 | BN_bin2bn(&reader->kdt05_00[0], 0x6c, bnN3);
|
---|
436 | BN_bin2bn(&exponent[0], 3, bnE3);
|
---|
437 | BN_bin2bn(&reader->step3[0], 0x6c, bnCT3);
|
---|
438 | BN_mod_exp(bnPT3, bnCT3, bnE3, bnN3, ctx3);
|
---|
439 | BN_bn2bin(bnPT3, reader->data+ (0x6c- BN_num_bytes(bnPT3)));
|
---|
440 | BN_CTX_end(ctx3);
|
---|
441 | BN_CTX_free(ctx3);
|
---|
442 |
|
---|
443 | uint8_t cmd03[] = {0xCC,0xCC,0xCC,0xCC, 0x00,0x00,0x0A,0x03,0x6C,
|
---|
444 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
445 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
446 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
447 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
448 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
449 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
450 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
|
---|
451 | 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC };
|
---|
452 |
|
---|
453 | memcpy(&cmd03[9],reader->data,0x6c);
|
---|
454 | do_cas7_cmd(reader,cta_res,&cta_lr,cmd03,sizeof(cmd03),0x90);
|
---|
455 | memcpy(reader->encrypted,&cta_res[10],0x68);
|
---|
456 |
|
---|
457 | BN_CTX *ctx = BN_CTX_new();
|
---|
458 | #ifdef WITH_LIBCRYPTO
|
---|
459 | BN_CTX_start(ctx);
|
---|
460 | #endif
|
---|
461 | BIGNUM *bnN = BN_CTX_get(ctx);
|
---|
462 | BIGNUM *bnE = BN_CTX_get(ctx);
|
---|
463 | BIGNUM *bnCT = BN_CTX_get(ctx);
|
---|
464 | BIGNUM *bnPT = BN_CTX_get(ctx);
|
---|
465 | BN_bin2bn(&reader->kdt05_10[0], 104, bnN);
|
---|
466 | BN_bin2bn(&exponent[0], 3, bnE);
|
---|
467 | BN_bin2bn(&reader->encrypted[0], 104, bnCT);
|
---|
468 | BN_mod_exp(bnPT, bnCT, bnE, bnN, ctx);
|
---|
469 | memset(reader->result, 0, 104);
|
---|
470 | BN_bn2bin(bnPT, reader->result + (104 - BN_num_bytes(bnPT)));
|
---|
471 | BN_CTX_end(ctx);
|
---|
472 | BN_CTX_free(ctx);
|
---|
473 |
|
---|
474 | //uchar stillencrypted[0x50];
|
---|
475 | memcpy(reader->stillencrypted,&reader->result[12],0x50);
|
---|
476 |
|
---|
477 | //uchar resultrsa[0x50];
|
---|
478 | BN_CTX *ctxs = BN_CTX_new();
|
---|
479 | #ifdef WITH_LIBCRYPTO
|
---|
480 | BN_CTX_start(ctxs);
|
---|
481 | #endif
|
---|
482 | BIGNUM *bnNs = BN_CTX_get(ctxs);
|
---|
483 | BIGNUM *bnEs = BN_CTX_get(ctxs);
|
---|
484 | BIGNUM *bnCTs = BN_CTX_get(ctxs);
|
---|
485 | BIGNUM *bnPTs = BN_CTX_get(ctxs);
|
---|
486 | BN_bin2bn(&mod50[0], sizeof(mod50), bnNs);
|
---|
487 | BN_bin2bn(&reader->cas7expo[0], 0x11, bnEs);
|
---|
488 | BN_bin2bn(&reader->stillencrypted[0], 0x50, bnCTs);
|
---|
489 | BN_mod_exp(bnPTs, bnCTs, bnEs, bnNs, ctxs);
|
---|
490 | BN_bn2bin(bnPTs, reader->resultrsa + (0x50- BN_num_bytes(bnPTs)));
|
---|
491 | BN_CTX_end(ctxs);
|
---|
492 | BN_CTX_free(ctxs);
|
---|
493 |
|
---|
494 | unsigned char mdc_hash[MDC2_DIGEST_LENGTH];
|
---|
495 | memset(mdc_hash,0x00,MDC2_DIGEST_LENGTH);
|
---|
496 |
|
---|
497 | MDC2_CTX c;
|
---|
498 | MDC2_Init(&c);
|
---|
499 | MDC2_Update(&c, reader->resultrsa, sizeof(reader->resultrsa));
|
---|
500 | MDC2_Final(&(mdc_hash[0]), &c);
|
---|
501 |
|
---|
502 | memcpy(&reader->cas7_aes_key[16],mdc_hash,16);
|
---|
503 | memcpy(reader->cas7_aes_key,mdc_hash,16);
|
---|
504 | }
|
---|
505 |
|
---|
506 | static int32_t nagra7_card_init(struct s_reader *reader, ATR *newatr)
|
---|
507 | {
|
---|
508 | get_atr;
|
---|
509 | int8_t is_pure_nagra = 0;
|
---|
510 | int8_t is_tiger = 0;
|
---|
511 | int8_t is_n3_na = 0;
|
---|
512 | memset(reader->irdId, 0xff, 4);
|
---|
513 | memset(reader->hexserial, 0, 6);
|
---|
514 | reader->cas7_seq=0x00;
|
---|
515 | cs_clear_entitlement(reader);
|
---|
516 | if(memcmp(atr + 11, "DNASP4", 6) == 0)
|
---|
517 | {
|
---|
518 | memcpy(reader->rom, atr + 11, 15);
|
---|
519 | rdr_log(reader,"Rom revision: %.15s", reader->rom);
|
---|
520 | }
|
---|
521 | else
|
---|
522 | {
|
---|
523 | return ERROR;
|
---|
524 | }
|
---|
525 |
|
---|
526 | if(!reader->csystem_data)
|
---|
527 | {
|
---|
528 | if(!cs_malloc(&reader->csystem_data, sizeof(struct nagra_data)))
|
---|
529 | {
|
---|
530 | rdr_log(reader, "cs_malloc error");
|
---|
531 | return ERROR;
|
---|
532 | }
|
---|
533 | }
|
---|
534 | struct nagra_data *csystem_data = reader->csystem_data;
|
---|
535 | csystem_data->is_pure_nagra = is_pure_nagra;
|
---|
536 | csystem_data->is_tiger = is_tiger;
|
---|
537 | csystem_data->is_n3_na = is_n3_na;
|
---|
538 |
|
---|
539 | reader->nprov = 1;
|
---|
540 | CAS7GetDataType(reader, 0x09);
|
---|
541 | CAS7GetDataType(reader, 0x05);
|
---|
542 | CAS7_getCamKey(reader);
|
---|
543 | CAS7GetDataType(reader, 0x09);
|
---|
544 | CAS7GetDataType(reader, 0x02); // sysid+caid
|
---|
545 | CAS7GetDataType(reader, 0x03);
|
---|
546 | return OK;
|
---|
547 | }
|
---|
548 |
|
---|
549 | typedef struct
|
---|
550 | {
|
---|
551 | char date1[11];
|
---|
552 | char date2[11];
|
---|
553 | uint8_t type;
|
---|
554 | uint16_t value;
|
---|
555 | uint16_t price;
|
---|
556 | } ncmed_rec;
|
---|
557 |
|
---|
558 | static int32_t nagra7_card_info(struct s_reader *reader)
|
---|
559 | {
|
---|
560 | int32_t i;
|
---|
561 | char tmp[64];
|
---|
562 |
|
---|
563 | int crcdigits; // checksum digits
|
---|
564 | crcdigits = (((unsigned long long) b2ll(6, reader->hexserial + 2) % 2300) / 100 + ((unsigned long long) b2ll(6, reader->hexserial + 2)));
|
---|
565 | 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]);
|
---|
566 | 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]);
|
---|
567 | //rdr_log_sensitive(reader, "SER: {%s} (%llu-%i)", cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)),(unsigned long long) b2ll(4, reader->hexserial + 2), crcdigits);
|
---|
568 | rdr_log_sensitive(reader, "SER: {%s} {%llu}", cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)),(unsigned long long) b2ll(4, reader->hexserial + 2));
|
---|
569 | rdr_log_dbg(reader, D_READER, "checksum digits: %i", crcdigits);
|
---|
570 | rdr_log(reader, "CAID: %04X", reader->caid);
|
---|
571 | rdr_log(reader, "Prv.ID: %s(sysid)", cs_hexdump(1, reader->prid[0], 4, tmp, sizeof(tmp)));
|
---|
572 |
|
---|
573 | if (reader->irdId[0] == 0xFF && reader->irdId[1] == 0xFF && reader->irdId[2] == 0xFF && reader->irdId[3] == 0xFF)
|
---|
574 | {
|
---|
575 | rdr_log(reader, "IRD ID: FF FF FF FF");
|
---|
576 | }
|
---|
577 | else
|
---|
578 | {
|
---|
579 | rdr_log_sensitive(reader, "IRD ID: {%s}", cs_hexdump(1, reader->irdId, 4, tmp, sizeof(tmp)));
|
---|
580 | }
|
---|
581 |
|
---|
582 | cs_clear_entitlement(reader); //reset the entitlements
|
---|
583 | rdr_log(reader, "-----------------------------------------");
|
---|
584 | rdr_log(reader, "|id |tier |valid from |valid to |");
|
---|
585 | rdr_log(reader, "+----+--------+------------+------------+");
|
---|
586 |
|
---|
587 | CAS7GetDataType(reader, 0x0C);
|
---|
588 | rdr_log(reader, "-----------------------------------------");
|
---|
589 |
|
---|
590 | CAS7GetDataType(reader, 0x06);
|
---|
591 | for(i = 1; i < reader->nprov; i++)
|
---|
592 | {
|
---|
593 | rdr_log(reader, "Prv.ID: %s", cs_hexdump(1, reader->prid[i], 4, tmp, sizeof(tmp)));
|
---|
594 | }
|
---|
595 | if (reader->caid)
|
---|
596 | {
|
---|
597 | rdr_log(reader, "ready for requests");
|
---|
598 | }
|
---|
599 |
|
---|
600 | return OK;
|
---|
601 | }
|
---|
602 |
|
---|
603 | void nagra7_post_process(struct s_reader *reader)
|
---|
604 | {
|
---|
605 | struct nagra_data *csystem_data = reader->csystem_data;
|
---|
606 | if((csystem_data->cam_state[0]&64)==64)
|
---|
607 | {
|
---|
608 | rdr_log(reader, "renew Session Key: CAS7");
|
---|
609 | CAS7_getCamKey(reader);
|
---|
610 | }
|
---|
611 | }
|
---|
612 |
|
---|
613 | static int32_t nagra7_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
|
---|
614 | {
|
---|
615 | def_resp;
|
---|
616 | struct nagra_data *csystem_data = reader->csystem_data;
|
---|
617 |
|
---|
618 | uint8_t ecmreq[0xC0];
|
---|
619 | memset(ecmreq,0xCC,0xC0);
|
---|
620 |
|
---|
621 | ecmreq[ 7]=0x05;
|
---|
622 | ecmreq[ 8]=0x8A;
|
---|
623 | ecmreq[ 9]=0x00;
|
---|
624 | ecmreq[10]=0x00;
|
---|
625 | ecmreq[11]=0x00;
|
---|
626 | ecmreq[12]=0x00;
|
---|
627 | ecmreq[13]=0x01;
|
---|
628 | memcpy(&ecmreq[14],er->ecm + 4, er->ecm[4]+1);
|
---|
629 |
|
---|
630 | do_cas7_cmd(reader,cta_res,&cta_lr,ecmreq,sizeof(ecmreq),0xB0);
|
---|
631 | if(cta_res[cta_lr-2] != 0x90 && cta_res[cta_lr-1] != 0x00){
|
---|
632 | rdr_log(reader, "(ECM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
633 | reader->card_status = CARD_NEED_INIT;
|
---|
634 | add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
---|
635 | }
|
---|
636 |
|
---|
637 | if(cta_res[27]==0x5C)
|
---|
638 | {
|
---|
639 | uint8_t _cwe0[8];
|
---|
640 | uint8_t _cwe1[8];
|
---|
641 | int32_t i;
|
---|
642 | if (cta_res[78] == 0x01)
|
---|
643 | {
|
---|
644 | rdr_log (reader,"Swap dcw is at use !"); //; csystem_data->swapCW == 1;
|
---|
645 | memcpy(_cwe0,&cta_res[52],0x08);
|
---|
646 | memcpy(_cwe1,&cta_res[28],0x08);
|
---|
647 | }
|
---|
648 | else
|
---|
649 | {
|
---|
650 | memcpy(_cwe0,&cta_res[28],0x08);
|
---|
651 | memcpy(_cwe1,&cta_res[52],0x08);
|
---|
652 | }
|
---|
653 | if (array_has_nonzero_byte(_cwe_key, 128) > 0)
|
---|
654 | {
|
---|
655 | i = cta_res[24];
|
---|
656 | memcpy(_cwe_key, _cwe_key+(i*16), 16);
|
---|
657 | rdr_log_dump_dbg(reader, D_READER, _cwe_key, sizeof(_cwe_key), "Using CWPK-%d from config:",i);
|
---|
658 | }
|
---|
659 | _3DES(_cwe0,_cwe_key);
|
---|
660 | _3DES(_cwe1,_cwe_key);
|
---|
661 | int chkok=1;
|
---|
662 |
|
---|
663 | if(((_cwe0[0]+_cwe0[1]+_cwe0[2])&0xFF)!=_cwe0[3])
|
---|
664 | {
|
---|
665 | chkok=0;
|
---|
666 | rdr_log_dbg(reader, D_READER, "CW0 checksum error [0]");
|
---|
667 | }
|
---|
668 | if(((_cwe0[4]+_cwe0[5]+_cwe0[6])&0xFF)!=_cwe0[7])
|
---|
669 | {
|
---|
670 | chkok=0;
|
---|
671 | rdr_log_dbg(reader, D_READER, "CW0 checksum error [1]");
|
---|
672 | }
|
---|
673 | if(((_cwe1[0]+_cwe1[1]+_cwe1[2])&0xFF)!=_cwe1[3])
|
---|
674 | {
|
---|
675 | chkok=0;
|
---|
676 | rdr_log_dbg(reader, D_READER, "CW1 checksum error [0]");
|
---|
677 | }
|
---|
678 | if(((_cwe1[4]+_cwe1[5]+_cwe1[6])&0xFF)!=_cwe1[7])
|
---|
679 | {
|
---|
680 | chkok=0;
|
---|
681 | rdr_log_dbg(reader, D_READER, "CW1 checksum error [1]");
|
---|
682 | }
|
---|
683 |
|
---|
684 | csystem_data->cam_state[0]=cta_res[4];
|
---|
685 | if(chkok==1)
|
---|
686 | {
|
---|
687 | rdr_log_dbg(reader, D_READER, "CW Decrypt ok");
|
---|
688 | memcpy(ea->cw,_cwe0,0x08);
|
---|
689 | memcpy(ea->cw+8,_cwe1,0x08);
|
---|
690 | return OK;
|
---|
691 | }
|
---|
692 | }
|
---|
693 |
|
---|
694 | return ERROR;
|
---|
695 | }
|
---|
696 |
|
---|
697 | int32_t nagra7_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr) //returns 1 if shared emm matches SA, unique emm matches serial, or global or unknown
|
---|
698 | {
|
---|
699 | switch(ep->emm[0])
|
---|
700 | {
|
---|
701 | case 0x83:
|
---|
702 | case 0x87:
|
---|
703 | memset(ep->hexserial, 0, 8);
|
---|
704 | ep->hexserial[0] = ep->emm[5];
|
---|
705 | ep->hexserial[1] = ep->emm[4];
|
---|
706 | ep->hexserial[2] = ep->emm[3];
|
---|
707 | if(ep->emm[7] == 0x10)
|
---|
708 | {
|
---|
709 | ep->type = SHARED;
|
---|
710 | return (!memcmp(rdr->hexserial + 2, ep->hexserial, 3));
|
---|
711 | }
|
---|
712 | else
|
---|
713 | {
|
---|
714 | ep->hexserial[3] = ep->emm[6];
|
---|
715 | ep->type = UNIQUE;
|
---|
716 | return (!memcmp(rdr->hexserial + 2, ep->hexserial, 4));
|
---|
717 | }
|
---|
718 | case 0x82:
|
---|
719 | case 0x84:
|
---|
720 | ep->type = GLOBAL;
|
---|
721 | return 1;
|
---|
722 | default:
|
---|
723 | ep->type = UNKNOWN;
|
---|
724 | return 1;
|
---|
725 | }
|
---|
726 | }
|
---|
727 |
|
---|
728 | static int32_t nagra7_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
|
---|
729 | {
|
---|
730 | if(*emm_filters == NULL)
|
---|
731 | {
|
---|
732 | const unsigned int max_filter_count = 3;
|
---|
733 | if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
|
---|
734 | {
|
---|
735 | return ERROR;
|
---|
736 | }
|
---|
737 |
|
---|
738 | struct s_csystem_emm_filter *filters = *emm_filters;
|
---|
739 | *filter_count = 0;
|
---|
740 |
|
---|
741 | int32_t idx = 0;
|
---|
742 |
|
---|
743 | filters[idx].type = EMM_GLOBAL;
|
---|
744 | filters[idx].enabled = 1;
|
---|
745 | filters[idx].filter[0] = 0x86;
|
---|
746 | filters[idx].mask[0] = 0xF9; // 0x82, 0x84 and 0x86
|
---|
747 | idx++;
|
---|
748 |
|
---|
749 | filters[idx].type = EMM_SHARED;
|
---|
750 | filters[idx].enabled = 1;
|
---|
751 | filters[idx].filter[0] = 0x87;
|
---|
752 | filters[idx].filter[1] = rdr->hexserial[4];
|
---|
753 | filters[idx].filter[2] = rdr->hexserial[3];
|
---|
754 | filters[idx].filter[3] = rdr->hexserial[2];
|
---|
755 | filters[idx].filter[4] = 0x00;
|
---|
756 | filters[idx].filter[5] = 0x10;
|
---|
757 | filters[idx].mask[0] = 0xFB; // 0x83 and 0x87
|
---|
758 | memset(&filters[idx].mask[1], 0xFF, 5);
|
---|
759 | idx++;
|
---|
760 |
|
---|
761 | filters[idx].type = EMM_UNIQUE;
|
---|
762 | filters[idx].enabled = 1;
|
---|
763 | filters[idx].filter[0] = 0x87;
|
---|
764 | filters[idx].filter[1] = rdr->hexserial[4];
|
---|
765 | filters[idx].filter[2] = rdr->hexserial[3];
|
---|
766 | filters[idx].filter[3] = rdr->hexserial[2];
|
---|
767 | filters[idx].filter[4] = rdr->hexserial[5];
|
---|
768 | filters[idx].filter[5] = 0x00;
|
---|
769 | filters[idx].mask[0] = 0xFB; // 0x83 and 0x87
|
---|
770 | memset(&filters[idx].mask[1], 0xFF, 5);
|
---|
771 | idx++;
|
---|
772 |
|
---|
773 | *filter_count = idx;
|
---|
774 | }
|
---|
775 |
|
---|
776 | return OK;
|
---|
777 | }
|
---|
778 |
|
---|
779 | static int32_t nagra7_do_emm(struct s_reader *reader, EMM_PACKET *ep)
|
---|
780 | {
|
---|
781 | def_resp;
|
---|
782 | uint8_t emmreq[0xC0];
|
---|
783 | memset(emmreq,0xCC,0xC0);
|
---|
784 | emmreq[ 7]=0x05;
|
---|
785 | emmreq[ 8]=0x8A;
|
---|
786 | emmreq[ 9]=0x00;
|
---|
787 | emmreq[10]=0x00;
|
---|
788 | emmreq[11]=0x00;
|
---|
789 | emmreq[12]=0x00;
|
---|
790 | emmreq[13]=0x01;
|
---|
791 | memcpy(&emmreq[14],ep->emm + 9, ep->emm[9]+1);
|
---|
792 | do_cas7_cmd(reader,cta_res,&cta_lr,emmreq,sizeof(emmreq),0xB0);
|
---|
793 | if(cta_res[cta_lr-2] != 0x90 && cta_res[cta_lr-1] != 0x00){
|
---|
794 | rdr_log(reader, "(EMM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
795 | reader->card_status = CARD_NEED_INIT;
|
---|
796 | add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
---|
797 | }
|
---|
798 | return OK;
|
---|
799 | }
|
---|
800 |
|
---|
801 | const struct s_cardsystem reader_nagracak7 =
|
---|
802 | {
|
---|
803 | .desc = "Nagra_Merlin",
|
---|
804 | .caids = (uint16_t[]){ 0x18, 0x0 },
|
---|
805 | .do_emm = nagra7_do_emm,
|
---|
806 | .do_ecm = nagra7_do_ecm,
|
---|
807 | .post_process = nagra7_post_process,
|
---|
808 | .card_info = nagra7_card_info,
|
---|
809 | .card_init = nagra7_card_init,
|
---|
810 | .get_emm_type = nagra7_get_emm_type,
|
---|
811 | .get_emm_filter = nagra7_get_emm_filter,
|
---|
812 | };
|
---|
813 |
|
---|
814 | #endif
|
---|