1 | /*
|
---|
2 | * Bulcrypt card reader for OSCAM
|
---|
3 | * Copyright (C) 2012 Unix Solutions Ltd.
|
---|
4 | *
|
---|
5 | * Authors: Anton Tinchev (atl@unixsol.org)
|
---|
6 | * Georgi Chorbadzhiyski (gf@unixsol.org)
|
---|
7 | *
|
---|
8 | * This program is free software: you can redistribute it and/or modify
|
---|
9 | * it under the terms of the GNU General Public License as published by
|
---|
10 | * the Free Software Foundation, either version 3 of the License, or
|
---|
11 | * (at your option) any later version.
|
---|
12 | *
|
---|
13 | * This program is distributed in the hope that it will be useful,
|
---|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | * GNU General Public License for more details.
|
---|
17 | *
|
---|
18 | * You should have received a copy of the GNU General Public License
|
---|
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
20 | *
|
---|
21 | * =========================================================================
|
---|
22 | *
|
---|
23 | * For more information read the code and the comments. We have tried to
|
---|
24 | * write clear code with lots of comments so it is easy for others to
|
---|
25 | * understand what is going on. There are some things marked *FIXME*,
|
---|
26 | * that are mostly unknown or not fully understand.
|
---|
27 | *
|
---|
28 | * WHAT WAS TESTED AND WAS WORKING:
|
---|
29 | * - Cards with bulcrypt v1 ("cherga"/carpet) are working (we have cards
|
---|
30 | * that report CardType: 0x4c and 0x75.
|
---|
31 | * - Cards return valid code words for subscribed channels.
|
---|
32 | * - Tested with channels encrypted with CAID 0x5581 and 0x4aee on
|
---|
33 | * Hellas 39E. Both MPEG2 (SD) and H.264 (SD and HD) channels were
|
---|
34 | * decrypted.
|
---|
35 | * - Brand new cards were inited without ever being put into providers STBs.
|
---|
36 | * as long the protocol you are using is sending EMMs to the card.
|
---|
37 | * - AU was working (subscription dates and packages were updated)
|
---|
38 | * as long the protocol you are using is sending EMMs to the card.
|
---|
39 | *
|
---|
40 | * WHAT WE DON'T KNOW (YET!):
|
---|
41 | * - How to deobfuscate v2 codewords.
|
---|
42 | *
|
---|
43 | * PERSONAL MESSAGES:
|
---|
44 | * - Many thanks to ilian_71 @ satfriends forum for the protocol info.
|
---|
45 | * - Shouts to yuriks for oscam-ymod, pity it is violating the GPL.
|
---|
46 | *
|
---|
47 | */
|
---|
48 |
|
---|
49 | #include "globals.h"
|
---|
50 | #ifdef READER_BULCRYPT
|
---|
51 | #include "oscam-work.h"
|
---|
52 | #include "reader-common.h"
|
---|
53 |
|
---|
54 | static const uint8_t atr_carpet[] = { 0x3b, 0x20, 0x00 };
|
---|
55 |
|
---|
56 | // *FIXME* We do not know how every 4th byte of the sess_key is calculated.
|
---|
57 | // Currently they are correct thou and code words checksums are correct are
|
---|
58 | // the deobfuscation.
|
---|
59 | static const uint8_t sess_key[] = { 0xF2, 0x21, 0xC5, 0x69, 0x28, 0x86, 0xFB, 0x9E,
|
---|
60 | 0xC0, 0x20, 0x28, 0x06, 0xD2, 0x23, 0x72, 0x31 };
|
---|
61 |
|
---|
62 | static const uint8_t cmd_set_key[] = { 0xDE, 0x1C, 0x00, 0x00, 0x0A, 0x12, 0x08, 0x56,
|
---|
63 | 0x47, 0x38, 0x29, 0x10, 0xAF, 0xBE, 0xCD };
|
---|
64 |
|
---|
65 | static const uint8_t cmd_set_key_v2[] = { 0xDE, 0x1C, 0x00, 0x00, 0x0A, 0x12, 0x08, 0x00,
|
---|
66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
---|
67 | // Response: 90 00
|
---|
68 |
|
---|
69 | // V2
|
---|
70 | static const uint8_t cmd_card_v2_key1[] = { 0xDE, 0x12, 0x00, 0x00, 0x00, 0x00 };
|
---|
71 | static const uint8_t cmd_card_v2_key2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x12, 0x00 };
|
---|
72 |
|
---|
73 | static const uint8_t cmd_cardtype1[] = { 0xDE, 0x16, 0x00, 0x00, 0x00, 0x00 };
|
---|
74 | static const uint8_t cmd_cardtype2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x03, 0x00 };
|
---|
75 | // Response1: 90 03
|
---|
76 | // Response2: 01 01 4C 90 00 or 01 01 xx 90 00
|
---|
77 | // xx - 4C or 75 (Card type)
|
---|
78 |
|
---|
79 | static const uint8_t cmd_unkn_0a1[] = { 0xDE, 0x0A, 0x00, 0x00, 0x00, 0x00 };
|
---|
80 | static const uint8_t cmd_unkn_0a2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x03, 0x00 };
|
---|
81 | // Response1: 90 03
|
---|
82 | // Response2: 08 01 00 90 00
|
---|
83 |
|
---|
84 | static const uint8_t cmd_cardsn1[] = { 0xDE, 0x18, 0x00, 0x00, 0x00, 0x00 };
|
---|
85 | static const uint8_t cmd_cardsn2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x06, 0x00 };
|
---|
86 | // Response1: 90 06
|
---|
87 | // Response2: 02 04 xx xx xx xy 90 00
|
---|
88 | // xx - Card HEX serial
|
---|
89 | // y - Unknown *FIXME*
|
---|
90 |
|
---|
91 | static const uint8_t cmd_ascsn1[] = { 0xDE, 0x1A, 0x00, 0x00, 0x00, 0x00 };
|
---|
92 | static const uint8_t cmd_ascsn2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x0F, 0x00 };
|
---|
93 | // Response1: 90 0F
|
---|
94 | // Response2: 05 0D xx xx 20 xx xx xx xx xx xx 20 xx xx xx 90 00
|
---|
95 | // xx - Card ASCII serial
|
---|
96 |
|
---|
97 | static const uint8_t cmd_ecm_empty[] = { 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00 };
|
---|
98 | // Response: 90 00
|
---|
99 |
|
---|
100 | static const uint8_t cmd_ecm[] = { 0xDE, 0x20, 0x00, 0x00, 0x4c };
|
---|
101 | // The last byte is ECM length
|
---|
102 |
|
---|
103 | static const uint8_t cmd_ecm_get_cw[] = { 0xDE, 0x1E, 0x00, 0x00, 0x13, 0x00 };
|
---|
104 | // Response: 0A 11 80 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 90 00
|
---|
105 | // 80 - Returned codeword type? *FIXME*
|
---|
106 | // xx - Obfuscated CW
|
---|
107 |
|
---|
108 | static const uint8_t cmd_emm1[] = { 0xDE, 0x02, 0x82, 0x00, 0xb0 };
|
---|
109 | // Response: 90 00 (EMM written OK) or
|
---|
110 | // Response: 90 0A (Subscription data was updated)
|
---|
111 | // The last byte is EMM length (0xb0)
|
---|
112 |
|
---|
113 | static const uint8_t cmd_emm2[] = { 0xDE, 0x04, 0x00, 0x00, 0xb0 };
|
---|
114 | // Response: 90 00 (EMM written OK)
|
---|
115 | // cmd_emm[2] = emm_cmd1
|
---|
116 | // cmd_emm[3] = emm_cmd2
|
---|
117 | // The last byte is EMM length (0xb0)
|
---|
118 |
|
---|
119 | static const uint8_t cmd_sub_info1[] = { 0xDE, 0x06, 0x00, 0x00, 0x00, 0x00 };
|
---|
120 | static const uint8_t cmd_sub_info2[] = { 0xDE, 0x1E, 0x00, 0x00, 0x2B, 0x00 };
|
---|
121 | // See bulcrypt_card_info() for reponse description
|
---|
122 |
|
---|
123 | struct bulcrypt_data
|
---|
124 | {
|
---|
125 | uint8_t bulcrypt_version;
|
---|
126 | };
|
---|
127 |
|
---|
128 | static int32_t bulcrypt_card_init(struct s_reader *reader, ATR *newatr)
|
---|
129 | {
|
---|
130 | int i;
|
---|
131 | char tmp[1024];
|
---|
132 | char card_serial[16];
|
---|
133 | const uint8_t *set_key_command;
|
---|
134 | uint8_t card_type;
|
---|
135 |
|
---|
136 | get_atr
|
---|
137 | def_resp
|
---|
138 |
|
---|
139 | if(memcmp(atr, atr_carpet, MIN(sizeof(atr_carpet), atr_size)) != 0)
|
---|
140 | {
|
---|
141 | if(atr_size == 3)
|
---|
142 | {
|
---|
143 | rdr_log(reader, "ATR_len=3 but ATR is unknown: %s",
|
---|
144 | cs_hexdump(1, atr, atr_size, tmp, sizeof(tmp)));
|
---|
145 | }
|
---|
146 | return ERROR;
|
---|
147 | }
|
---|
148 |
|
---|
149 | if(!cs_malloc(&reader->csystem_data, sizeof(struct bulcrypt_data)))
|
---|
150 | { return ERROR; }
|
---|
151 |
|
---|
152 | struct bulcrypt_data *csystem_data = reader->csystem_data;
|
---|
153 |
|
---|
154 | reader->nprov = 1;
|
---|
155 | memset(reader->prid, 0, sizeof(reader->prid));
|
---|
156 | memset(reader->hexserial, 0, sizeof(reader->hexserial));
|
---|
157 | memset(card_serial, 0, sizeof(card_serial));
|
---|
158 |
|
---|
159 | rdr_log(reader, "Bulcrypt card detected, checking card version.");
|
---|
160 |
|
---|
161 | // Do we have Bulcrypt V2 card?
|
---|
162 | write_cmd(cmd_card_v2_key1, NULL);
|
---|
163 | write_cmd(cmd_card_v2_key2, NULL);
|
---|
164 | if(cta_lr < 18 || (cta_res[0] != 0x11 && cta_res[1] != 0x10))
|
---|
165 | {
|
---|
166 | // The card is v1
|
---|
167 | csystem_data->bulcrypt_version = 1;
|
---|
168 | set_key_command = cmd_set_key;
|
---|
169 | }
|
---|
170 | else
|
---|
171 | {
|
---|
172 | // The card is v2
|
---|
173 | csystem_data->bulcrypt_version = 2;
|
---|
174 | set_key_command = cmd_set_key_v2;
|
---|
175 | }
|
---|
176 |
|
---|
177 | // Set CW obfuscation key
|
---|
178 | write_cmd(set_key_command, set_key_command + 5);
|
---|
179 | if(cta_lr < 2 || (cta_res[0] != 0x90 && cta_res[1] != 0x00))
|
---|
180 | {
|
---|
181 | rdr_log(reader, "(cmd_set_key) Unexpected card answer: %s",
|
---|
182 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
183 | return ERROR;
|
---|
184 | }
|
---|
185 |
|
---|
186 | rdr_log(reader, "Bulcrypt v%d card detected.%s", csystem_data->bulcrypt_version,
|
---|
187 | csystem_data->bulcrypt_version != 1 ? " *UNSUPPORTED CARD VERSION*" : "");
|
---|
188 |
|
---|
189 | // Read card type
|
---|
190 | write_cmd(cmd_cardtype1, NULL);
|
---|
191 | write_cmd(cmd_cardtype2, NULL);
|
---|
192 | if(cta_lr < 5 || (cta_res[0] != 0x01 && cta_res[1] != 0x01))
|
---|
193 | {
|
---|
194 | rdr_log(reader, "(cmd_cardtype) Unexpected card answer: %s",
|
---|
195 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
196 | return ERROR;
|
---|
197 | }
|
---|
198 | card_type = cta_res[2]; // We have seen 0x4c and 0x75
|
---|
199 |
|
---|
200 | // *FIXME* Unknown command
|
---|
201 | write_cmd(cmd_unkn_0a1, NULL);
|
---|
202 | write_cmd(cmd_unkn_0a2, NULL);
|
---|
203 |
|
---|
204 | // Read card HEX serial
|
---|
205 | write_cmd(cmd_cardsn1, NULL);
|
---|
206 | write_cmd(cmd_cardsn2, NULL);
|
---|
207 | if(cta_lr < 6 || (cta_res[0] != 0x02 && cta_res[1] != 0x04))
|
---|
208 | {
|
---|
209 | rdr_log(reader, "(card_sn) Unexpected card answer: %s",
|
---|
210 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
211 | return ERROR;
|
---|
212 | }
|
---|
213 | memcpy(reader->hexserial, cta_res + 2, 4);
|
---|
214 | // Skip bottom four bits (they are 0x0b on our cards)
|
---|
215 | reader->hexserial[3] = reader->hexserial[3] & 0xF0;
|
---|
216 |
|
---|
217 | // Read card ASCII serial
|
---|
218 | write_cmd(cmd_ascsn1, NULL);
|
---|
219 | write_cmd(cmd_ascsn2, NULL);
|
---|
220 |
|
---|
221 | if(cta_lr < 15 || (cta_res[0] != 0x05 && cta_res[1] != 0x0d))
|
---|
222 | {
|
---|
223 | rdr_log(reader, "(asc_sn) Unexpected card answer: %s",
|
---|
224 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
225 | return ERROR;
|
---|
226 | }
|
---|
227 | memcpy(card_serial, cta_res + 2, 13);
|
---|
228 | cta_lr = strlen(card_serial);
|
---|
229 |
|
---|
230 | for(i = 0; i < cta_lr; i++)
|
---|
231 | {
|
---|
232 | if(card_serial[i] == ' ')
|
---|
233 | { continue; }
|
---|
234 |
|
---|
235 | // Sanity check
|
---|
236 | if(!isdigit((uint8_t)card_serial[i]))
|
---|
237 | { card_serial[i] = '*'; }
|
---|
238 | }
|
---|
239 |
|
---|
240 | // Write empty ECM, *FIXME* why are we doing this? To prepare the card somehow?
|
---|
241 | write_cmd(cmd_ecm_empty, NULL);
|
---|
242 |
|
---|
243 | // The HEX serial have nothing to do with Serial (they do not match)
|
---|
244 | rdr_log_sensitive(reader, "CAID: 0x4AEE|0x5581, CardType: 0x%02x, Serial: {%s}, HexSerial: {%02X %02X %02X %02X}",
|
---|
245 | card_type,
|
---|
246 | card_serial,
|
---|
247 | reader->hexserial[0], reader->hexserial[1], reader->hexserial[2], reader->hexserial[3]);
|
---|
248 |
|
---|
249 | rdr_log(reader, "Ready for requests.");
|
---|
250 |
|
---|
251 | return OK;
|
---|
252 | }
|
---|
253 |
|
---|
254 | static int cw_is_valid(struct s_reader *reader, uint8_t *cw)
|
---|
255 | {
|
---|
256 | unsigned int i = 0, cnt = 0;
|
---|
257 | do
|
---|
258 | {
|
---|
259 | if(cw[i++] == 0)
|
---|
260 | { cnt++; }
|
---|
261 | }
|
---|
262 | while(i < 8);
|
---|
263 |
|
---|
264 | if(cnt == 8)
|
---|
265 | {
|
---|
266 | rdr_log(reader, "Invalid CW (all zeroes)");
|
---|
267 | return ERROR;
|
---|
268 | }
|
---|
269 |
|
---|
270 | uint8_t cksum1 = cw[0] + cw[1] + cw[2];
|
---|
271 | uint8_t cksum2 = cw[4] + cw[5] + cw[6];
|
---|
272 | if(cksum1 != cw[3] || cksum2 != cw[7])
|
---|
273 | {
|
---|
274 | if(cksum1 != cw[3])
|
---|
275 | { rdr_log(reader, "Invalid CW (cksum1 mismatch expected 0x%02x got 0x%02x)", cksum1, cw[3]); }
|
---|
276 | if(cksum2 != cw[7])
|
---|
277 | { rdr_log(reader, "Invalid CW (cksum2 mismatch expected 0x%02x got 0x%02x)", cksum2, cw[7]); }
|
---|
278 | return ERROR;
|
---|
279 | }
|
---|
280 |
|
---|
281 | return OK;
|
---|
282 | }
|
---|
283 |
|
---|
284 | /*
|
---|
285 | Bulcrypt ECM structure:
|
---|
286 |
|
---|
287 | 80 70 - ECM header (80 | 81)
|
---|
288 | 4c - ECM length after this field (0x4c == 76 bytes)
|
---|
289 | 4f 8d 87 0b - unixts == 1334675211 == Tue Apr 17 18:06:51 EEST 2012
|
---|
290 | 00 66 - *FIXME* Program number?
|
---|
291 | 00 7d - *FIXME*
|
---|
292 | ce 70 - ECM counter
|
---|
293 | 0b 88 - ECM type
|
---|
294 | xx yy zz .. - Encrypted ECM payload (64 bytes)
|
---|
295 |
|
---|
296 | */
|
---|
297 | static int32_t bulcrypt_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
|
---|
298 | {
|
---|
299 | char tmp[512];
|
---|
300 | uint8_t ecm_cmd[256];
|
---|
301 | struct bulcrypt_data *csystem_data = reader->csystem_data;
|
---|
302 |
|
---|
303 | def_resp
|
---|
304 |
|
---|
305 | int32_t ecm_len = check_sct_len(er->ecm, 3);
|
---|
306 | if(ecm_len < 64 || ecm_len > 188)
|
---|
307 | {
|
---|
308 | rdr_log(reader, "Wrong ECM length: %d", ecm_len);
|
---|
309 | return ERROR;
|
---|
310 | }
|
---|
311 |
|
---|
312 | // CMD: DE 20 00 00 4C
|
---|
313 | memcpy(ecm_cmd, cmd_ecm, sizeof(cmd_ecm));
|
---|
314 | ecm_cmd[4] = er->ecm[2]; // Set ECM length
|
---|
315 | memcpy(ecm_cmd + sizeof(cmd_ecm), er->ecm + 3, ecm_cmd[4]);
|
---|
316 |
|
---|
317 | // Send ECM
|
---|
318 | write_cmd(ecm_cmd, ecm_cmd + 5);
|
---|
319 | if(cta_lr != 2)
|
---|
320 | {
|
---|
321 | rdr_log(reader, "(ecm_cmd) Unexpected card answer: %s",
|
---|
322 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
323 | return ERROR;
|
---|
324 | }
|
---|
325 |
|
---|
326 | if(cta_res[0] == 0x90 && cta_res[1] == 0x03)
|
---|
327 | {
|
---|
328 | rdr_log(reader, "No active subscription.");
|
---|
329 | return ERROR;
|
---|
330 | }
|
---|
331 |
|
---|
332 | if(!(cta_res[0] == 0x90 && cta_res[1] == 0x13))
|
---|
333 | {
|
---|
334 | rdr_log(reader, "(ecm_cmd) Unexpected card answer: %s",
|
---|
335 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
336 | return ERROR;
|
---|
337 | }
|
---|
338 |
|
---|
339 | // Call get_cw
|
---|
340 | write_cmd(cmd_ecm_get_cw, NULL);
|
---|
341 |
|
---|
342 | // rdr_log(reader, "CW_LOG: %s", cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
343 | if(cta_lr < 20 || (cta_res[0] != 0x0a && cta_res[1] != 0x11))
|
---|
344 | {
|
---|
345 | rdr_log(reader, "(get_cw) Unexpected card answer: %s",
|
---|
346 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
347 | return ERROR;
|
---|
348 | }
|
---|
349 |
|
---|
350 | // *FIXME* is the bellow info true?
|
---|
351 | // 0x80 (ver 1) is supported
|
---|
352 | // 0xc0 (ver 2) is *NOT* supported currently
|
---|
353 | if(cta_res[2] == 0xc0)
|
---|
354 | {
|
---|
355 | rdr_log(reader, "Possibly unsupported codeword (bulcrypt v2): %s",
|
---|
356 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
357 | // *FIXME* commented for testing, this really should be an error
|
---|
358 | //return ERROR;
|
---|
359 | }
|
---|
360 |
|
---|
361 | // Remove code word obfuscation
|
---|
362 | uint8_t *cw = cta_res + 3;
|
---|
363 | if(csystem_data->bulcrypt_version == 1)
|
---|
364 | {
|
---|
365 | int i;
|
---|
366 | for(i = 0 ; i < 16; i++)
|
---|
367 | {
|
---|
368 | cw[i] = cw[i] ^ sess_key[i];
|
---|
369 | }
|
---|
370 | }
|
---|
371 |
|
---|
372 | if(er->ecm[0] == 0x81)
|
---|
373 | {
|
---|
374 | // Even/Odd CWs should be exchanged
|
---|
375 | memcpy(ea->cw, cw + 8, 8);
|
---|
376 | memcpy(ea->cw + 8, cw, 8);
|
---|
377 | }
|
---|
378 | else
|
---|
379 | {
|
---|
380 | memcpy(ea->cw, cw, 8);
|
---|
381 | memcpy(ea->cw + 8, cw + 8, 8);
|
---|
382 | }
|
---|
383 |
|
---|
384 | // Check if DCW is valid
|
---|
385 | if(!cw_is_valid(reader, ea->cw) || !cw_is_valid(reader, ea->cw + 8))
|
---|
386 | { return ERROR; }
|
---|
387 |
|
---|
388 | return OK;
|
---|
389 | }
|
---|
390 |
|
---|
391 | /*
|
---|
392 | Bulcrypt EMMs structure
|
---|
393 |
|
---|
394 | All EMMs are with section length 183 (0xb7)
|
---|
395 | 3 bytes section header
|
---|
396 | 7 bytes EMM header
|
---|
397 | 173 bytes payload
|
---|
398 |
|
---|
399 | 82 70 - UNUQUE_EMM_82|8a
|
---|
400 | b4 - Payload length (0xb4 == 180)
|
---|
401 | xx xx xx xy - Card HEX SN (the last 4 bits (y) must be masked)
|
---|
402 | payload
|
---|
403 |
|
---|
404 | 85 70 - GLOBAL_EMM_85|8b
|
---|
405 | b4 - Payload length (0xb4 == 180)
|
---|
406 | xx xx yy yy - Card HEX SN (the last 16 bits (y) must be masked)
|
---|
407 | payload
|
---|
408 |
|
---|
409 | 84 70 - SHARED_EMM_84
|
---|
410 | b4 - Payload length (0xb4 == 180)
|
---|
411 | xx xx - Card HEX SN Prefix
|
---|
412 | yy -
|
---|
413 | zz -
|
---|
414 | payload
|
---|
415 |
|
---|
416 | Padding EMM:
|
---|
417 | 8f 70 b4 ff ff ff ff ff ff ff ff ff .. .. (ff to the end)
|
---|
418 |
|
---|
419 | Stats for EMMs collected for a period of 1 hours and 24 minutes
|
---|
420 |
|
---|
421 | 2279742 - 82 70 b4 - unique_82
|
---|
422 | 19051 - 8a 70 b4 - unique_8a (polaris equivallent of 0x82)
|
---|
423 | 199949 - 84 70 b4 - shared_84
|
---|
424 | 595309 - 85 70 b4 - global_85
|
---|
425 | 6417 - 8b 70 b4 - global_8b (polaris equivallent of 0x85)
|
---|
426 | 74850 - 8f 70 b4 - filler
|
---|
427 |
|
---|
428 | Total EMMs for the period: 3175317
|
---|
429 | */
|
---|
430 |
|
---|
431 | #define BULCRYPT_EMM_UNIQUE_82 0x82 // Addressed at single card (updates subscription info)
|
---|
432 | #define BULCRYPT_EMM_UNIQUE_8a 0x8a // Addressed at single card (like 0x82) used for Polaris
|
---|
433 | #define BULCRYPT_EMM_SHARED_84 0x84 // Addressed to 4096 cards (updates keys)
|
---|
434 | #define BULCRYPT_EMM_GLOBAL_85 0x85 // Addressed at 4096 cards (updates packages)
|
---|
435 | #define BULCRYPT_EMM_GLOBAL_8b 0x8b // Addressed at 4096 cards (like 0x85) used for Polaris
|
---|
436 | #define BULCRYPT_EMM_FILLER 0x8f // Filler to pad the EMM stream
|
---|
437 |
|
---|
438 | static int32_t bulcrypt_get_emm_type(EMM_PACKET *ep, struct s_reader *reader)
|
---|
439 | {
|
---|
440 | char dump_emm_sn[64];
|
---|
441 | int32_t emm_len = check_sct_len(ep->emm, 3);
|
---|
442 |
|
---|
443 | memset(ep->hexserial, 0, 8);
|
---|
444 |
|
---|
445 | if(emm_len < 176)
|
---|
446 | {
|
---|
447 | rdr_log_dbg(reader, D_TRACE | D_EMM, "emm_len < 176 (%u): %s",
|
---|
448 | emm_len, cs_hexdump(1, ep->emm, 12, dump_emm_sn, sizeof(dump_emm_sn)));
|
---|
449 | ep->type = UNKNOWN;
|
---|
450 | return 0;
|
---|
451 | }
|
---|
452 |
|
---|
453 | ep->type = UNKNOWN;
|
---|
454 | switch(ep->emm[0])
|
---|
455 | {
|
---|
456 | case BULCRYPT_EMM_UNIQUE_82:
|
---|
457 | ep->type = UNIQUE;
|
---|
458 | break; // Bulsatcom
|
---|
459 |
|
---|
460 | case BULCRYPT_EMM_UNIQUE_8a:
|
---|
461 | ep->type = UNIQUE;
|
---|
462 | break; // Polaris
|
---|
463 |
|
---|
464 | case BULCRYPT_EMM_SHARED_84:
|
---|
465 | ep->type = SHARED;
|
---|
466 | break;
|
---|
467 |
|
---|
468 | case BULCRYPT_EMM_GLOBAL_85:
|
---|
469 | ep->type = GLOBAL;
|
---|
470 | break; // Bulsatcom
|
---|
471 |
|
---|
472 | case BULCRYPT_EMM_GLOBAL_8b:
|
---|
473 | ep->type = GLOBAL;
|
---|
474 | break; // Polaris
|
---|
475 | }
|
---|
476 |
|
---|
477 | bool ret = false;
|
---|
478 | if(ep->type == UNIQUE)
|
---|
479 | {
|
---|
480 | // The serial numbers looks like this:
|
---|
481 | // aa bb cc dd
|
---|
482 | memcpy(ep->hexserial, ep->emm + 3, 4);
|
---|
483 | ret = reader->hexserial[0] == ep->hexserial[0] &&
|
---|
484 | reader->hexserial[1] == ep->hexserial[1] &&
|
---|
485 | reader->hexserial[2] == ep->hexserial[2] &&
|
---|
486 | ((reader->hexserial[3] & 0xF0) == (ep->hexserial[3] & 0xF0));
|
---|
487 | }
|
---|
488 | else
|
---|
489 | {
|
---|
490 | // To match EMM_84, EMM_85, EMM_8b
|
---|
491 | // aa bb -- --
|
---|
492 | memcpy(ep->hexserial, ep->emm + 3, 2);
|
---|
493 | ret = reader->hexserial[0] == ep->hexserial[0] &&
|
---|
494 | reader->hexserial[1] == ep->hexserial[1];
|
---|
495 | }
|
---|
496 |
|
---|
497 | if(ret)
|
---|
498 | {
|
---|
499 | char dump_card_sn[64];
|
---|
500 | cs_hexdump(1, reader->hexserial, 4, dump_card_sn, sizeof(dump_card_sn));
|
---|
501 | cs_hexdump(1, ep->hexserial, 4, dump_emm_sn, sizeof(dump_emm_sn));
|
---|
502 | rdr_log_sensitive(reader, "EMM_%s-%02x, emm_sn = {%s}, card_sn = {%s}",
|
---|
503 | ep->type == UNIQUE ? "UNIQUE" :
|
---|
504 | ep->type == SHARED ? "SHARED" :
|
---|
505 | ep->type == GLOBAL ? "GLOBAL" : "??????",
|
---|
506 | ep->emm[0],
|
---|
507 | dump_emm_sn,
|
---|
508 | dump_card_sn);
|
---|
509 | }
|
---|
510 |
|
---|
511 | return ret;
|
---|
512 | }
|
---|
513 |
|
---|
514 | static int32_t bulcrypt_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
|
---|
515 | {
|
---|
516 | if(*emm_filters == NULL)
|
---|
517 | {
|
---|
518 | const unsigned int max_filter_count = 5;
|
---|
519 | if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
|
---|
520 | { return ERROR; }
|
---|
521 |
|
---|
522 | struct s_csystem_emm_filter *filters = *emm_filters;
|
---|
523 | *filter_count = 0;
|
---|
524 |
|
---|
525 | int32_t idx = 0;
|
---|
526 |
|
---|
527 | filters[idx].type = EMM_UNIQUE;
|
---|
528 | filters[idx].enabled = 1;
|
---|
529 | filters[idx].filter[0] = 0x82;
|
---|
530 | filters[idx].filter[1] = rdr->hexserial[0];
|
---|
531 | filters[idx].filter[2] = rdr->hexserial[1];
|
---|
532 | filters[idx].filter[3] = rdr->hexserial[2];
|
---|
533 | filters[idx].filter[4] = rdr->hexserial[3];
|
---|
534 | filters[idx].mask[0] = 0xFF;
|
---|
535 | filters[idx].mask[1] = 0xFF;
|
---|
536 | filters[idx].mask[2] = 0xFF;
|
---|
537 | filters[idx].mask[3] = 0xFF;
|
---|
538 | filters[idx].mask[4] = 0xF0;
|
---|
539 | idx++;
|
---|
540 |
|
---|
541 | filters[idx].type = EMM_UNIQUE;
|
---|
542 | filters[idx].enabled = 1;
|
---|
543 | filters[idx].filter[0] = 0x8a;
|
---|
544 | filters[idx].filter[1] = rdr->hexserial[0];
|
---|
545 | filters[idx].filter[2] = rdr->hexserial[1];
|
---|
546 | filters[idx].filter[3] = rdr->hexserial[2];
|
---|
547 | filters[idx].filter[4] = rdr->hexserial[3];
|
---|
548 | filters[idx].mask[0] = 0xFF;
|
---|
549 | filters[idx].mask[1] = 0xFF;
|
---|
550 | filters[idx].mask[2] = 0xFF;
|
---|
551 | filters[idx].mask[3] = 0xFF;
|
---|
552 | filters[idx].mask[4] = 0xF0;
|
---|
553 | idx++;
|
---|
554 |
|
---|
555 | filters[idx].type = EMM_SHARED;
|
---|
556 | filters[idx].enabled = 1;
|
---|
557 | filters[idx].filter[0] = 0x84;
|
---|
558 | filters[idx].filter[1] = rdr->hexserial[0];
|
---|
559 | filters[idx].filter[2] = rdr->hexserial[1];
|
---|
560 | filters[idx].mask[0] = 0xFF;
|
---|
561 | filters[idx].mask[1] = 0xFF;
|
---|
562 | filters[idx].mask[2] = 0xFF;
|
---|
563 | idx++;
|
---|
564 |
|
---|
565 | filters[idx].type = EMM_GLOBAL;
|
---|
566 | filters[idx].enabled = 1;
|
---|
567 | filters[idx].filter[0] = 0x85;
|
---|
568 | filters[idx].filter[1] = rdr->hexserial[0];
|
---|
569 | filters[idx].filter[2] = rdr->hexserial[1];
|
---|
570 | filters[idx].mask[0] = 0xFF;
|
---|
571 | filters[idx].mask[1] = 0xFF;
|
---|
572 | filters[idx].mask[2] = 0xFF;
|
---|
573 | idx++;
|
---|
574 |
|
---|
575 | filters[idx].type = EMM_GLOBAL;
|
---|
576 | filters[idx].enabled = 1;
|
---|
577 | filters[idx].filter[0] = 0x8b;
|
---|
578 | filters[idx].filter[1] = rdr->hexserial[0];
|
---|
579 | filters[idx].filter[2] = rdr->hexserial[1];
|
---|
580 | filters[idx].mask[0] = 0xFF;
|
---|
581 | filters[idx].mask[1] = 0xFF;
|
---|
582 | filters[idx].mask[2] = 0xFF;
|
---|
583 | idx++;
|
---|
584 |
|
---|
585 | *filter_count = idx;
|
---|
586 | }
|
---|
587 |
|
---|
588 | return OK;
|
---|
589 | }
|
---|
590 |
|
---|
591 | static int32_t bulcrypt_do_emm(struct s_reader *reader, EMM_PACKET *ep)
|
---|
592 | {
|
---|
593 | char tmp[512];
|
---|
594 | uint8_t emm_cmd[1024];
|
---|
595 |
|
---|
596 | def_resp
|
---|
597 |
|
---|
598 | // DE 04 xx yy B0
|
---|
599 | // xx == EMM type (emm[0])
|
---|
600 | // yy == EMM type2 (emm[5])
|
---|
601 | // B0 == EMM len (176)
|
---|
602 | memcpy(emm_cmd, cmd_emm1, sizeof(cmd_emm1));
|
---|
603 | memcpy(emm_cmd + sizeof(cmd_emm1), ep->emm + 7, 176);
|
---|
604 |
|
---|
605 | switch(ep->emm[0])
|
---|
606 | {
|
---|
607 | case BULCRYPT_EMM_UNIQUE_82:
|
---|
608 | emm_cmd[2] = ep->emm[0]; // 0x82
|
---|
609 | break;
|
---|
610 |
|
---|
611 | case BULCRYPT_EMM_UNIQUE_8a: // Polaris equivallent of 0x82
|
---|
612 | emm_cmd[2] = 0x82;
|
---|
613 | emm_cmd[3] = 0x0b;
|
---|
614 | break;
|
---|
615 |
|
---|
616 | case BULCRYPT_EMM_SHARED_84:
|
---|
617 | emm_cmd[2] = ep->emm[0]; // 0x84
|
---|
618 | emm_cmd[3] = ep->emm[5]; // 0x0b
|
---|
619 | break;
|
---|
620 |
|
---|
621 | case BULCRYPT_EMM_GLOBAL_85:
|
---|
622 | case BULCRYPT_EMM_GLOBAL_8b: // Polaris 0x85 equivallent of 0x85
|
---|
623 | memcpy(emm_cmd, cmd_emm2, sizeof(cmd_emm2));
|
---|
624 | emm_cmd[2] = ep->emm[5]; // 0xXX (Last bytes of the serial)
|
---|
625 | emm_cmd[3] = ep->emm[6]; // 0x0b
|
---|
626 | break;
|
---|
627 | }
|
---|
628 |
|
---|
629 | // Write emm
|
---|
630 | write_cmd(emm_cmd, emm_cmd + 5);
|
---|
631 | if(cta_lr != 2 || cta_res[0] != 0x90 || (cta_res[1] != 0x00 && cta_res[1] != 0x0a && cta_res[1] != 0x12))
|
---|
632 | {
|
---|
633 | rdr_log(reader, "(emm_cmd) Unexpected card answer: %s",
|
---|
634 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
635 | return ERROR;
|
---|
636 | }
|
---|
637 |
|
---|
638 | // V2 answers of 82 EMM
|
---|
639 | if(cta_res[0] == 0x90 && cta_res[1] == 0x12)
|
---|
640 | {
|
---|
641 | write_cmd(cmd_card_v2_key2, NULL);
|
---|
642 | if(cta_res[18] == 0x90 && cta_res[19] == 0x12)
|
---|
643 | {
|
---|
644 | write_cmd(cmd_card_v2_key2, NULL);
|
---|
645 | }
|
---|
646 | }
|
---|
647 |
|
---|
648 | if(ep->emm[0] == BULCRYPT_EMM_UNIQUE_82 && cta_res[0] == 0x90 && (cta_res[1] == 0x0a || cta_res[1] == 0x00))
|
---|
649 | {
|
---|
650 | rdr_log(reader, "Your subscription data was updated.");
|
---|
651 | add_job(reader->client, ACTION_READER_CARDINFO, NULL, 0);
|
---|
652 | }
|
---|
653 |
|
---|
654 | return OK;
|
---|
655 | }
|
---|
656 |
|
---|
657 | static char *dec2bin_str(unsigned int d, char *s)
|
---|
658 | {
|
---|
659 | unsigned int i, r = 8;
|
---|
660 | memset(s, 0, 9);
|
---|
661 | for(i = 1; i < 256; i <<= 1)
|
---|
662 | { s[--r] = (d & i) == i ? '+' : '-'; }
|
---|
663 | return s;
|
---|
664 | }
|
---|
665 |
|
---|
666 | static int32_t bulcrypt_card_info(struct s_reader *reader)
|
---|
667 | {
|
---|
668 | char tmp[512];
|
---|
669 | time_t last_upd_ts, subs_end_ts;
|
---|
670 | struct tm tm;
|
---|
671 | def_resp
|
---|
672 |
|
---|
673 | rdr_log(reader, "Reading subscription info.");
|
---|
674 |
|
---|
675 | cs_clear_entitlement(reader);
|
---|
676 |
|
---|
677 | write_cmd(cmd_sub_info1, NULL);
|
---|
678 | write_cmd(cmd_sub_info2, NULL);
|
---|
679 |
|
---|
680 | if(cta_lr < 45)
|
---|
681 | {
|
---|
682 | rdr_log(reader, "(info_cmd) Unexpected card answer: %s",
|
---|
683 | cs_hexdump(1, cta_res, cta_lr, tmp, sizeof(tmp)));
|
---|
684 | return ERROR;
|
---|
685 | }
|
---|
686 |
|
---|
687 | // Response contains:
|
---|
688 | // 13 29 0B
|
---|
689 | // 4F 8F 00 E9 - Unix ts set by UNIQUE_EMM_82
|
---|
690 | // 3C 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF
|
---|
691 | // 3C 84 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF
|
---|
692 | // 90 2B
|
---|
693 |
|
---|
694 | last_upd_ts = b2i(4, cta_res + 3);
|
---|
695 | subs_end_ts = last_upd_ts + (31 * 86400); // *FIXME* this is just a guess
|
---|
696 |
|
---|
697 | reader->card_valid_to = subs_end_ts;
|
---|
698 |
|
---|
699 | gmtime_r(&last_upd_ts, &tm);
|
---|
700 | memset(tmp, 0, sizeof(tmp));
|
---|
701 | strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S %Z", &tm);
|
---|
702 | rdr_log(reader, "Subscription data last update : %s", tmp);
|
---|
703 |
|
---|
704 | gmtime_r(&subs_end_ts, &tm);
|
---|
705 | memset(tmp, 0, sizeof(tmp));
|
---|
706 | strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S %Z", &tm);
|
---|
707 | rdr_log(reader, "Subscription should be active to : %s", tmp);
|
---|
708 |
|
---|
709 | unsigned int subs1 = b2i(2, cta_res + 3 + 4 + 16);
|
---|
710 | unsigned int subs2 = b2i(2, cta_res + 3 + 4 + 16 + 18);
|
---|
711 |
|
---|
712 | if(subs1 == 0xffff)
|
---|
713 | {
|
---|
714 | rdr_log(reader, "No active subscriptions (0x%04x, 0x%04x)", subs1, subs2);
|
---|
715 | }
|
---|
716 | else
|
---|
717 | {
|
---|
718 | unsigned int i;
|
---|
719 | rdr_log(reader, "Subscription data 1 (0x%04x): %s",
|
---|
720 | subs1, dec2bin_str(subs1, tmp));
|
---|
721 | rdr_log(reader, "Subscription data 2 (0x%04x): %s",
|
---|
722 | subs2, dec2bin_str(subs2, tmp));
|
---|
723 |
|
---|
724 | // Configure your tiers to get subscription packets name resolution
|
---|
725 | // # Example oscam.tiers file
|
---|
726 | // 5581:0001|Economic
|
---|
727 | // 5581:0002|Standard
|
---|
728 | // 5581:0004|Premium
|
---|
729 | // 5581:0008|HBO
|
---|
730 | // 5581:0010|Cinemax
|
---|
731 | // 5581:0020|Unknown Package 20
|
---|
732 | // 5581:0040|Film Plus - Sport Plus HD & Hobby TV HD
|
---|
733 | // 5581:0080|Unknown Package 80
|
---|
734 | for(i = 1; i < 256; i <<= 1)
|
---|
735 | {
|
---|
736 | if((subs1 & i) == i)
|
---|
737 | {
|
---|
738 | cs_add_entitlement(reader, 0x4AEE,
|
---|
739 | 0, /* provid */
|
---|
740 | i, /* id */
|
---|
741 | 0, /* class */
|
---|
742 | last_upd_ts, /* start_ts */
|
---|
743 | subs_end_ts, /* end_ts */
|
---|
744 | 4, /* type: Tier */
|
---|
745 | 1 /* add */
|
---|
746 | );
|
---|
747 | cs_add_entitlement(reader, 0x5581,
|
---|
748 | 0, /* provid */
|
---|
749 | i, /* id */
|
---|
750 | 0, /* class */
|
---|
751 | last_upd_ts, /* start_ts */
|
---|
752 | subs_end_ts, /* end_ts */
|
---|
753 | 4, /* type: Tier */
|
---|
754 | 1 /* add */
|
---|
755 | );
|
---|
756 | get_tiername(i, 0x4aee, tmp);
|
---|
757 | if(tmp[0] == 0x00)
|
---|
758 | { get_tiername(i, 0x5581, tmp); }
|
---|
759 | rdr_log(reader, "Package %02x is active: %s", i, tmp);
|
---|
760 | }
|
---|
761 | }
|
---|
762 | }
|
---|
763 |
|
---|
764 | rdr_log(reader, "End subscription info.");
|
---|
765 | return OK;
|
---|
766 | }
|
---|
767 |
|
---|
768 | const struct s_cardsystem reader_bulcrypt =
|
---|
769 | {
|
---|
770 | .desc = "bulcrypt",
|
---|
771 | .caids = (uint16_t[]){ 0x5581, 0x4AEE, 0 },
|
---|
772 | .do_emm = bulcrypt_do_emm,
|
---|
773 | .do_ecm = bulcrypt_do_ecm,
|
---|
774 | .card_info = bulcrypt_card_info,
|
---|
775 | .card_init = bulcrypt_card_init,
|
---|
776 | .get_emm_type = bulcrypt_get_emm_type,
|
---|
777 | .get_emm_filter = bulcrypt_get_emm_filter,
|
---|
778 | };
|
---|
779 |
|
---|
780 | #endif
|
---|