Line 0
Link Here
|
|
|
1 |
#define MODULE_LOG_PREFIX "emu" |
2 |
|
3 |
#include "globals.h" |
4 |
#include "ffdecsa/ffdecsa.h" |
5 |
#include "cscrypt/bn.h" |
6 |
#include "cscrypt/des.h" |
7 |
#include "cscrypt/idea.h" |
8 |
#include "cscrypt/md5.h" |
9 |
|
10 |
#ifdef WITH_EMU |
11 |
#include "oscam-aes.h" |
12 |
#include "oscam-string.h" |
13 |
#include "oscam-config.h" |
14 |
#include "oscam-conf-chk.h" |
15 |
#include "oscam-time.h" |
16 |
#include "module-newcamd-des.h" |
17 |
#include "reader-dre-common.h" |
18 |
// from reader-viaccess.c: |
19 |
void hdSurEncPhase1_D2_0F_11(uint8_t *CWs); |
20 |
void hdSurEncPhase2_D2_0F_11(uint8_t *CWs); |
21 |
void hdSurEncPhase1_D2_13_15(uint8_t *cws); |
22 |
void hdSurEncPhase2_D2_13_15(uint8_t *cws); |
23 |
#else |
24 |
#include "cscrypt/viades.h" |
25 |
#include "via3surenc.h" |
26 |
#include "dre2overcrypt.h" |
27 |
#endif |
28 |
|
29 |
#include "module-emulator-osemu.h" |
30 |
#include "module-emulator-stream.h" |
31 |
|
32 |
// Version info |
33 |
uint32_t GetOSemuVersion(void) |
34 |
{ |
35 |
return atoi("$Version: 766 $"+10); |
36 |
} |
37 |
|
38 |
/* |
39 |
* Key DB |
40 |
* |
41 |
* The Emu reader gets keys from the OSCcam-Emu binary and the "SoftCam.Key" file. |
42 |
* |
43 |
* The keys are stored in structures of type "KeyDataContainer", one per CAS. Each |
44 |
* container points to a dynamically allocated array of type "KeyData", which holds |
45 |
* the actual keys. The array initially holds up to 64 keys (64 * KeyData), and it |
46 |
* is expanded by 16 every time it's filled with keys. The "KeyDataContainer" also |
47 |
* includes info about the number of keys it contains ("KeyCount") and the maximum |
48 |
* number of keys it can store ("KeyMax"). |
49 |
* |
50 |
* The "KeyData" structure on the other hand, stores the actual key information, |
51 |
* including the "identifier", "provider", "keyName", "key" and "keyLength". There |
52 |
* is also a "nextKey" pointer to a similar "KeyData" structure which is only used |
53 |
* for Irdeto multiple keys, in a linked list style structure. For all other CAS, |
54 |
* the "nextKey" is a "NULL" pointer. |
55 |
* |
56 |
* For storing keys, the "SetKey" function is used. Duplicate keys are not allowed. |
57 |
* When storing a key that is already present in the database, its "key" value is |
58 |
* updated with the new one. For reading keys from the database, the "FindKey" |
59 |
* function is used. To delete all keys in a container, the "DeleteKeysInContainer" |
60 |
* function can be called. |
61 |
*/ |
62 |
|
63 |
static char *emu_keyfile_path = NULL; |
64 |
|
65 |
void set_emu_keyfile_path(const char *path) |
66 |
{ |
67 |
if(emu_keyfile_path != NULL) { |
68 |
free(emu_keyfile_path); |
69 |
} |
70 |
emu_keyfile_path = (char*)malloc(strlen(path)+1); |
71 |
if(emu_keyfile_path == NULL) { |
72 |
return; |
73 |
} |
74 |
memcpy(emu_keyfile_path, path, strlen(path)); |
75 |
emu_keyfile_path[strlen(path)] = 0; |
76 |
} |
77 |
|
78 |
int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen) |
79 |
{ |
80 |
uint32_t i, tmp; |
81 |
for(i=0; i<inLen/2; i++) { |
82 |
if(sscanf(in + i*2, "%02X", &tmp) != 1) { |
83 |
return 0; |
84 |
} |
85 |
out[i] = (uint8_t)tmp; |
86 |
} |
87 |
return 1; |
88 |
} |
89 |
|
90 |
KeyDataContainer CwKeys = { NULL, 0, 0 }; |
91 |
KeyDataContainer ViKeys = { NULL, 0, 0 }; |
92 |
KeyDataContainer NagraKeys = { NULL, 0, 0 }; |
93 |
KeyDataContainer IrdetoKeys = { NULL, 0, 0 }; |
94 |
KeyDataContainer NDSKeys = { NULL, 0, 0 }; |
95 |
KeyDataContainer BissKeys = { NULL, 0, 0 }; |
96 |
KeyDataContainer PowervuKeys = { NULL, 0, 0 }; |
97 |
KeyDataContainer DreKeys = { NULL, 0, 0 }; |
98 |
KeyDataContainer TandbergKeys = { NULL, 0, 0 }; |
99 |
|
100 |
static KeyDataContainer *GetKeyContainer(char identifier) |
101 |
{ |
102 |
switch(identifier) { |
103 |
case 'W': |
104 |
return &CwKeys; |
105 |
case 'V': |
106 |
return &ViKeys; |
107 |
case 'N': |
108 |
return &NagraKeys; |
109 |
case 'I': |
110 |
return &IrdetoKeys; |
111 |
case 'S': |
112 |
return &NDSKeys; |
113 |
case 'F': |
114 |
return &BissKeys; |
115 |
case 'P': |
116 |
return &PowervuKeys; |
117 |
case 'D': |
118 |
return &DreKeys; |
119 |
case 'T': |
120 |
return &TandbergKeys; |
121 |
default: |
122 |
return NULL; |
123 |
} |
124 |
} |
125 |
|
126 |
static void Date2Str(char *dateStr, uint8_t len, int8_t offset, uint8_t format) |
127 |
{ |
128 |
// Creates a formatted date string for use in various functions. |
129 |
// A positive or negative time offset (in hours) can be set as well |
130 |
// as the format of the output string. |
131 |
|
132 |
time_t rawtime; |
133 |
struct tm timeinfo; |
134 |
|
135 |
time(&rawtime); |
136 |
rawtime += (time_t) offset * 60 * 60; // Add a positive or negative offset |
137 |
localtime_r(&rawtime, &timeinfo); |
138 |
|
139 |
switch (format) |
140 |
{ |
141 |
case 1: // Use in WriteKeyToFile() |
142 |
strftime(dateStr, len, "%c", &timeinfo); |
143 |
break; |
144 |
|
145 |
case 2: // Used in BissAnnotate() |
146 |
strftime(dateStr, len, "%F @ %R", &timeinfo); |
147 |
break; |
148 |
|
149 |
case 3: // Used in SetKey(), BissAnnotate() |
150 |
strftime(dateStr, len, "%y%m%d%H", &timeinfo); |
151 |
break; |
152 |
} |
153 |
} |
154 |
|
155 |
static void WriteKeyToFile(char identifier, uint32_t provider, const char *keyName, uint8_t *key, uint32_t keyLength, char* comment) |
156 |
{ |
157 |
char line[1200], dateText[100]; |
158 |
uint32_t pathLength; |
159 |
struct dirent *pDirent; |
160 |
DIR *pDir; |
161 |
char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1], *keyValue; |
162 |
FILE *file = NULL; |
163 |
uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); |
164 |
|
165 |
pathLength = strlen(emu_keyfile_path); |
166 |
path = (char*)malloc(pathLength+1); |
167 |
if(path == NULL) { |
168 |
return; |
169 |
} |
170 |
strncpy(path, emu_keyfile_path, pathLength+1); |
171 |
|
172 |
pathLength = strlen(path); |
173 |
if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { |
174 |
// cut file name |
175 |
path[pathLength-fileNameLen] = '\0'; |
176 |
} |
177 |
|
178 |
pathLength = strlen(path); |
179 |
if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { |
180 |
// cut trailing / |
181 |
path[pathLength-1] = '\0'; |
182 |
} |
183 |
|
184 |
pDir = opendir(path); |
185 |
if (pDir == NULL) { |
186 |
cs_log("Cannot open key file path: %s", path); |
187 |
free(path); |
188 |
return; |
189 |
} |
190 |
|
191 |
while((pDirent = readdir(pDir)) != NULL) { |
192 |
if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { |
193 |
strncpy(filename, pDirent->d_name, sizeof(filename)); |
194 |
break; |
195 |
} |
196 |
} |
197 |
closedir(pDir); |
198 |
|
199 |
if(pDirent == NULL) { |
200 |
strncpy(filename, EMU_KEY_FILENAME, sizeof(filename)); |
201 |
} |
202 |
|
203 |
pathLength = strlen(path)+1+strlen(filename)+1; |
204 |
filepath = (char*)malloc(pathLength); |
205 |
if(filepath == NULL) { |
206 |
free(path); |
207 |
return; |
208 |
} |
209 |
snprintf(filepath, pathLength, "%s/%s", path, filename); |
210 |
free(path); |
211 |
|
212 |
cs_log("Writing key file: %s", filepath); |
213 |
|
214 |
file = fopen(filepath, "a"); |
215 |
free(filepath); |
216 |
if(file == NULL) { |
217 |
return; |
218 |
} |
219 |
|
220 |
Date2Str(dateText, sizeof(dateText), 0, 1); |
221 |
|
222 |
keyValue = (char*)malloc((keyLength*2)+1); |
223 |
if(keyValue == NULL) { |
224 |
fclose(file); |
225 |
return; |
226 |
} |
227 |
cs_hexdump(0, key, keyLength, keyValue, (keyLength*2)+1); |
228 |
|
229 |
if(comment) |
230 |
{ |
231 |
snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s %s\n", identifier, provider, keyName, keyValue, dateText, comment); |
232 |
} |
233 |
else |
234 |
{ |
235 |
snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s\n", identifier, provider, keyName, keyValue, dateText); |
236 |
} |
237 |
|
238 |
cs_log("Key written: %c %.4X %s %s", identifier, provider, keyName, keyValue); |
239 |
|
240 |
free(keyValue); |
241 |
|
242 |
fwrite(line, strlen(line), 1, file); |
243 |
fclose(file); |
244 |
} |
245 |
|
246 |
int32_t SetKey(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, |
247 |
uint8_t writeKey, char *comment, struct s_reader *rdr) |
248 |
{ |
249 |
uint32_t i, j; |
250 |
uint8_t *tmpKey = NULL; |
251 |
KeyDataContainer *KeyDB; |
252 |
KeyData *tmpKeyData, *newKeyData; |
253 |
identifier = (char)toupper((int)identifier); |
254 |
|
255 |
KeyDB = GetKeyContainer(identifier); |
256 |
if(KeyDB == NULL) { |
257 |
return 0; |
258 |
} |
259 |
|
260 |
keyName = strtoupper(keyName); |
261 |
|
262 |
if (identifier == 'F') // Prepare BISS keys before saving to the db |
263 |
{ |
264 |
// Convert legacy BISS "00" & "01" keynames |
265 |
if (0 == strcmp(keyName, "00") || 0 == strcmp(keyName, "01")) |
266 |
{ |
267 |
keyName = "00000000"; |
268 |
} |
269 |
|
270 |
// All keyNames should have a length of 8 after converting |
271 |
if (strlen(keyName) != 8) |
272 |
{ |
273 |
cs_log("WARNING: Wrong key format in %s: F %08X %s", EMU_KEY_FILENAME, provider, keyName); |
274 |
return 0; |
275 |
} |
276 |
|
277 |
// Verify date-coded keyName (if enabled), ignoring old (expired) keys |
278 |
if (rdr->emu_datecodedenabled) |
279 |
{ |
280 |
char timeStr[9]; |
281 |
Date2Str(timeStr, sizeof(timeStr), 0, 3); |
282 |
|
283 |
// Reject old date-coded keys, but allow our "00000000" evergreen label |
284 |
if (strcmp("00000000", keyName) != 0 && strcmp(timeStr, keyName) >= 0) |
285 |
{ |
286 |
return 0; |
287 |
} |
288 |
} |
289 |
} |
290 |
|
291 |
// fix checksum for BISS keys with a length of 6 |
292 |
if (identifier == 'F' && keyLength == 6) |
293 |
{ |
294 |
tmpKey = (uint8_t*)malloc(8*sizeof(uint8_t)); |
295 |
if(tmpKey == NULL) { |
296 |
return 0; |
297 |
} |
298 |
|
299 |
tmpKey[0] = orgKey[0]; |
300 |
tmpKey[1] = orgKey[1]; |
301 |
tmpKey[2] = orgKey[2]; |
302 |
tmpKey[3] = ((orgKey[0] + orgKey[1] + orgKey[2]) & 0xff); |
303 |
tmpKey[4] = orgKey[3]; |
304 |
tmpKey[5] = orgKey[4]; |
305 |
tmpKey[6] = orgKey[5]; |
306 |
tmpKey[7] = ((orgKey[3] + orgKey[4] + orgKey[5]) & 0xff); |
307 |
|
308 |
keyLength = 8; |
309 |
} |
310 |
else // All keys with a length of 8, including BISS |
311 |
{ |
312 |
tmpKey = (uint8_t*)malloc(keyLength*sizeof(uint8_t)); |
313 |
if(tmpKey == NULL) { |
314 |
return 0; |
315 |
} |
316 |
|
317 |
memcpy(tmpKey, orgKey, keyLength); |
318 |
} |
319 |
|
320 |
// fix patched mgcamd format for Irdeto |
321 |
if(identifier == 'I' && provider < 0xFFFF) { |
322 |
provider = provider<<8; |
323 |
} |
324 |
|
325 |
// key already exists on db, update its value |
326 |
for(i=0; i<KeyDB->keyCount; i++) { |
327 |
|
328 |
if(KeyDB->EmuKeys[i].provider != provider) { |
329 |
continue; |
330 |
} |
331 |
|
332 |
// Don't match keyName (i.e. expiration date) for BISS |
333 |
if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { |
334 |
continue; |
335 |
} |
336 |
|
337 |
// allow multiple keys for Irdeto |
338 |
if(identifier == 'I') |
339 |
{ |
340 |
// reject duplicates |
341 |
tmpKeyData = &KeyDB->EmuKeys[i]; |
342 |
do { |
343 |
if(memcmp(tmpKeyData->key, tmpKey, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) { |
344 |
free(tmpKey); |
345 |
return 0; |
346 |
} |
347 |
tmpKeyData = tmpKeyData->nextKey; |
348 |
} |
349 |
while(tmpKeyData != NULL); |
350 |
|
351 |
// add new key |
352 |
newKeyData = (KeyData*)malloc(sizeof(KeyData)); |
353 |
if(newKeyData == NULL) { |
354 |
free(tmpKey); |
355 |
return 0; |
356 |
} |
357 |
newKeyData->identifier = identifier; |
358 |
newKeyData->provider = provider; |
359 |
if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { |
360 |
strncpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); |
361 |
} |
362 |
else { |
363 |
memcpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); |
364 |
} |
365 |
newKeyData->keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; |
366 |
newKeyData->key = tmpKey; |
367 |
newKeyData->keyLength = keyLength; |
368 |
newKeyData->nextKey = NULL; |
369 |
|
370 |
tmpKeyData = &KeyDB->EmuKeys[i]; |
371 |
j = 0; |
372 |
while(tmpKeyData->nextKey != NULL) { |
373 |
if(j == 0xFE) |
374 |
{ |
375 |
break; |
376 |
} |
377 |
tmpKeyData = tmpKeyData->nextKey; |
378 |
j++; |
379 |
} |
380 |
if(tmpKeyData->nextKey) |
381 |
{ |
382 |
NULLFREE(tmpKeyData->nextKey->key); |
383 |
NULLFREE(tmpKeyData->nextKey); |
384 |
} |
385 |
tmpKeyData->nextKey = newKeyData; |
386 |
|
387 |
if(writeKey) { |
388 |
WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); |
389 |
} |
390 |
} |
391 |
else // identifier != 'I' |
392 |
{ |
393 |
free(KeyDB->EmuKeys[i].key); |
394 |
KeyDB->EmuKeys[i].key = tmpKey; |
395 |
KeyDB->EmuKeys[i].keyLength = keyLength; |
396 |
|
397 |
if (identifier == 'F') // Update keyName (i.e. expiration date) for BISS |
398 |
{ |
399 |
strncpy(KeyDB->EmuKeys[i].keyName, keyName, EMU_MAX_CHAR_KEYNAME); |
400 |
} |
401 |
|
402 |
if(writeKey) { |
403 |
WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); |
404 |
} |
405 |
} |
406 |
|
407 |
return 1; |
408 |
} |
409 |
|
410 |
// key does not exist on db |
411 |
if(KeyDB->keyCount+1 > KeyDB->keyMax) |
412 |
{ |
413 |
if(KeyDB->EmuKeys == NULL) // db is empty |
414 |
{ |
415 |
KeyDB->EmuKeys = (KeyData*)malloc(sizeof(KeyData)*(KeyDB->keyMax+64)); |
416 |
if(KeyDB->EmuKeys == NULL) { |
417 |
free(tmpKey); |
418 |
return 0; |
419 |
} |
420 |
KeyDB->keyMax+=64; |
421 |
} |
422 |
else // db is full, expand it |
423 |
{ |
424 |
tmpKeyData = (KeyData*)realloc(KeyDB->EmuKeys, sizeof(KeyData)*(KeyDB->keyMax+16)); |
425 |
if(tmpKeyData == NULL) { |
426 |
free(tmpKey); |
427 |
return 0; |
428 |
} |
429 |
KeyDB->EmuKeys = tmpKeyData; |
430 |
KeyDB->keyMax+=16; |
431 |
} |
432 |
} |
433 |
|
434 |
KeyDB->EmuKeys[KeyDB->keyCount].identifier = identifier; |
435 |
KeyDB->EmuKeys[KeyDB->keyCount].provider = provider; |
436 |
if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { |
437 |
strncpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); |
438 |
} |
439 |
else { |
440 |
memcpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); |
441 |
} |
442 |
KeyDB->EmuKeys[KeyDB->keyCount].keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; |
443 |
KeyDB->EmuKeys[KeyDB->keyCount].key = tmpKey; |
444 |
KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength; |
445 |
KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL; |
446 |
KeyDB->keyCount++; |
447 |
|
448 |
if(writeKey) { |
449 |
WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); |
450 |
} |
451 |
|
452 |
return 1; |
453 |
} |
454 |
|
455 |
int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, |
456 |
uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider) |
457 |
{ |
458 |
uint32_t i; |
459 |
uint16_t j; |
460 |
uint8_t provider_matching_key_count = 0; |
461 |
KeyDataContainer *KeyDB; |
462 |
KeyData *tmpKeyData; |
463 |
|
464 |
KeyDB = GetKeyContainer(identifier); |
465 |
if(KeyDB == NULL) { |
466 |
return 0; |
467 |
} |
468 |
|
469 |
for(i=0; i<KeyDB->keyCount; i++) { |
470 |
|
471 |
if((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) { |
472 |
continue; |
473 |
} |
474 |
|
475 |
// Don't match keyName (i.e. expiration date) for BISS |
476 |
if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { |
477 |
continue; |
478 |
} |
479 |
|
480 |
//matchLength cannot be used when multiple keys are allowed |
481 |
//for a single provider/keyName combination. |
482 |
//Currently this is only the case for Irdeto keys. |
483 |
if(matchLength && KeyDB->EmuKeys[i].keyLength != maxKeyLength) { |
484 |
continue; |
485 |
} |
486 |
|
487 |
if(providerIgnoreMask) { |
488 |
if(provider_matching_key_count < keyRef) { |
489 |
provider_matching_key_count++; |
490 |
continue; |
491 |
} |
492 |
else { |
493 |
keyRef = 0; |
494 |
} |
495 |
} |
496 |
|
497 |
tmpKeyData = &KeyDB->EmuKeys[i]; |
498 |
|
499 |
j = 0; |
500 |
while(j<keyRef && tmpKeyData->nextKey != NULL) { |
501 |
j++; |
502 |
tmpKeyData = tmpKeyData->nextKey; |
503 |
} |
504 |
|
505 |
if(j == keyRef) { |
506 |
memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength); |
507 |
if(tmpKeyData->keyLength < maxKeyLength) { |
508 |
memset(key+tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength); |
509 |
} |
510 |
|
511 |
if (identifier == 'F') // Report the keyName of found key back to BissGetKey() |
512 |
{ |
513 |
strncpy(keyName, tmpKeyData->keyName, EMU_MAX_CHAR_KEYNAME); |
514 |
} |
515 |
|
516 |
if(getProvider != NULL) { |
517 |
(*getProvider) = tmpKeyData->provider; |
518 |
} |
519 |
return 1; |
520 |
} |
521 |
else { |
522 |
break; |
523 |
} |
524 |
} |
525 |
|
526 |
if (isCriticalKey) |
527 |
{ |
528 |
cs_log("Key not found: %c %X %s", identifier, provider, keyName); |
529 |
} |
530 |
|
531 |
return 0; |
532 |
} |
533 |
|
534 |
static int32_t UpdateKey(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, uint8_t writeKey, char *comment) |
535 |
{ |
536 |
uint32_t keyRef = 0; |
537 |
uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); |
538 |
if(tmpKey == NULL) |
539 |
{ |
540 |
return 0; |
541 |
} |
542 |
|
543 |
while(FindKey(identifier, provider, 0, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL)) |
544 |
{ |
545 |
if(memcmp(tmpKey, key, keyLength) == 0) |
546 |
{ |
547 |
free(tmpKey); |
548 |
return 0; |
549 |
} |
550 |
|
551 |
keyRef++; |
552 |
} |
553 |
|
554 |
free(tmpKey); |
555 |
return SetKey(identifier, provider, keyName, key, keyLength, writeKey, comment, NULL); |
556 |
} |
557 |
|
558 |
static int32_t UpdateKeysByProviderMask(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, |
559 |
uint32_t keyLength, char *comment) |
560 |
{ |
561 |
int32_t ret = 0; |
562 |
uint32_t foundProvider = 0; |
563 |
uint32_t keyRef = 0; |
564 |
uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); |
565 |
if(tmpKey == NULL) |
566 |
{ |
567 |
return 0; |
568 |
} |
569 |
|
570 |
while(FindKey(identifier, (provider & ~providerIgnoreMask), providerIgnoreMask, keyName, tmpKey, keyLength, 0, keyRef, 0, &foundProvider)) |
571 |
{ |
572 |
keyRef++; |
573 |
|
574 |
if(memcmp(tmpKey, key, keyLength) == 0) |
575 |
{ |
576 |
continue; |
577 |
} |
578 |
|
579 |
if(SetKey(identifier, foundProvider, keyName, key, keyLength, 1, comment, NULL)) |
580 |
{ |
581 |
ret = 1; |
582 |
} |
583 |
} |
584 |
|
585 |
free(tmpKey); |
586 |
return ret; |
587 |
} |
588 |
|
589 |
int32_t DeleteKeysInContainer(char identifier) |
590 |
{ |
591 |
// Deletes all keys stored in memory for the specified identifier, |
592 |
// but keeps the container itself, re-initialized at { NULL, 0, 0 }. |
593 |
// Returns the count of deleted keys. |
594 |
|
595 |
uint32_t oldKeyCount, i; |
596 |
KeyData *tmpKeyData; |
597 |
KeyDataContainer *KeyDB = GetKeyContainer(identifier); |
598 |
|
599 |
if (KeyDB == NULL || KeyDB->EmuKeys == NULL || KeyDB->keyCount == 0) |
600 |
{ |
601 |
return 0; |
602 |
} |
603 |
|
604 |
for (i = 0; i < KeyDB->keyCount; i++) |
605 |
{ |
606 |
// For Irdeto multiple keys only (linked list structure) |
607 |
while (KeyDB->EmuKeys[i].nextKey != NULL) |
608 |
{ |
609 |
tmpKeyData = KeyDB->EmuKeys[i].nextKey; |
610 |
KeyDB->EmuKeys[i].nextKey = KeyDB->EmuKeys[i].nextKey->nextKey; |
611 |
free(tmpKeyData->key); // Free key |
612 |
free(tmpKeyData); // Free KeyData |
613 |
} |
614 |
|
615 |
// For single keys (all identifiers, including Irdeto) |
616 |
free(KeyDB->EmuKeys[i].key); // Free key |
617 |
} |
618 |
|
619 |
// Free the KeyData array |
620 |
NULLFREE(KeyDB->EmuKeys); |
621 |
oldKeyCount = KeyDB->keyCount; |
622 |
KeyDB->keyCount = 0; |
623 |
KeyDB->keyMax = 0; |
624 |
|
625 |
return oldKeyCount; |
626 |
} |
627 |
|
628 |
void clear_emu_keydata(void) |
629 |
{ |
630 |
uint32_t total = 0; |
631 |
|
632 |
total = CwKeys.keyCount; |
633 |
total += ViKeys.keyCount; |
634 |
total += NagraKeys.keyCount; |
635 |
total += IrdetoKeys.keyCount; |
636 |
total += NDSKeys.keyCount; |
637 |
total += BissKeys.keyCount; |
638 |
total += PowervuKeys.keyCount; |
639 |
total += DreKeys.keyCount; |
640 |
total += TandbergKeys.keyCount; |
641 |
|
642 |
if (total != 0) |
643 |
{ |
644 |
cs_log("Freeing keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ |
645 |
CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ |
646 |
IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ |
647 |
PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); |
648 |
|
649 |
DeleteKeysInContainer('W'); |
650 |
DeleteKeysInContainer('V'); |
651 |
DeleteKeysInContainer('N'); |
652 |
DeleteKeysInContainer('I'); |
653 |
DeleteKeysInContainer('S'); |
654 |
DeleteKeysInContainer('F'); |
655 |
DeleteKeysInContainer('P'); |
656 |
DeleteKeysInContainer('D'); |
657 |
DeleteKeysInContainer('T'); |
658 |
} |
659 |
} |
660 |
|
661 |
uint8_t read_emu_keyfile(struct s_reader *rdr, const char *opath) |
662 |
{ |
663 |
char line[1200], keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; |
664 |
uint32_t pathLength, provider, keyLength; |
665 |
uint8_t *key; |
666 |
struct dirent *pDirent; |
667 |
DIR *pDir; |
668 |
char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1]; |
669 |
FILE *file = NULL; |
670 |
char identifier; |
671 |
uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); |
672 |
|
673 |
pathLength = strlen(opath); |
674 |
path = (char*)malloc(pathLength+1); |
675 |
if(path == NULL) { |
676 |
return 0; |
677 |
} |
678 |
strncpy(path, opath, pathLength+1); |
679 |
|
680 |
pathLength = strlen(path); |
681 |
if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { |
682 |
// cut file name |
683 |
path[pathLength-fileNameLen] = '\0'; |
684 |
} |
685 |
|
686 |
pathLength = strlen(path); |
687 |
if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { |
688 |
// cut trailing / |
689 |
path[pathLength-1] = '\0'; |
690 |
} |
691 |
|
692 |
pDir = opendir(path); |
693 |
if (pDir == NULL) { |
694 |
cs_log("Cannot open key file path: %s", path); |
695 |
free(path); |
696 |
return 0; |
697 |
} |
698 |
|
699 |
while((pDirent = readdir(pDir)) != NULL) { |
700 |
if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { |
701 |
strncpy(filename, pDirent->d_name, sizeof(filename)); |
702 |
break; |
703 |
} |
704 |
} |
705 |
closedir(pDir); |
706 |
|
707 |
if(pDirent == NULL) { |
708 |
cs_log("Key file not found in: %s", path); |
709 |
free(path); |
710 |
return 0; |
711 |
} |
712 |
|
713 |
pathLength = strlen(path)+1+strlen(filename)+1; |
714 |
filepath = (char*)malloc(pathLength); |
715 |
if(filepath == NULL) { |
716 |
free(path); |
717 |
return 0; |
718 |
} |
719 |
snprintf(filepath, pathLength, "%s/%s", path, filename); |
720 |
free(path); |
721 |
|
722 |
cs_log("Reading key file: %s", filepath); |
723 |
|
724 |
file = fopen(filepath, "r"); |
725 |
free(filepath); |
726 |
if(file == NULL) { |
727 |
return 0; |
728 |
} |
729 |
|
730 |
set_emu_keyfile_path(opath); |
731 |
|
732 |
while(fgets(line, 1200, file)) { |
733 |
if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { |
734 |
continue; |
735 |
} |
736 |
|
737 |
keyLength = strlen(keyString)/2; |
738 |
key = (uint8_t*)malloc(keyLength); |
739 |
if(key == NULL) { |
740 |
fclose(file); |
741 |
return 0; |
742 |
} |
743 |
|
744 |
if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK |
745 |
{ |
746 |
SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); |
747 |
} |
748 |
else // Non-hex characters in keyString |
749 |
{ |
750 |
if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. |
751 |
identifier != '=' && identifier != '-' && |
752 |
identifier != ' ') && |
753 |
!(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines |
754 |
{ |
755 |
// Alert user regarding faulty line |
756 |
cs_log("WARNING: non-hex value in %s at %c %04X %s %s", EMU_KEY_FILENAME, identifier, provider, keyName, keyString); |
757 |
} |
758 |
} |
759 |
free(key); |
760 |
} |
761 |
fclose(file); |
762 |
|
763 |
return 1; |
764 |
} |
765 |
|
766 |
#if !defined(__APPLE__) && !defined(__ANDROID__) |
767 |
extern uint8_t SoftCamKey_Data[] __asm__("_binary_SoftCam_Key_start"); |
768 |
extern uint8_t SoftCamKey_DataEnd[] __asm__("_binary_SoftCam_Key_end"); |
769 |
|
770 |
void read_emu_keymemory(struct s_reader *rdr) |
771 |
{ |
772 |
char *keyData, *line, *saveptr, keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; |
773 |
uint32_t provider, keyLength; |
774 |
uint8_t *key; |
775 |
char identifier; |
776 |
|
777 |
keyData = (char*)malloc(SoftCamKey_DataEnd-SoftCamKey_Data+1); |
778 |
if(keyData == NULL) { |
779 |
return; |
780 |
} |
781 |
memcpy(keyData, SoftCamKey_Data, SoftCamKey_DataEnd-SoftCamKey_Data); |
782 |
keyData[SoftCamKey_DataEnd-SoftCamKey_Data] = 0x00; |
783 |
|
784 |
line = strtok_r(keyData, "\n", &saveptr); |
785 |
while(line != NULL) { |
786 |
if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { |
787 |
line = strtok_r(NULL, "\n", &saveptr); |
788 |
continue; |
789 |
} |
790 |
keyLength = strlen(keyString)/2; |
791 |
key = (uint8_t*)malloc(keyLength); |
792 |
if(key == NULL) { |
793 |
free(keyData); |
794 |
return; |
795 |
} |
796 |
|
797 |
if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK |
798 |
{ |
799 |
SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); |
800 |
} |
801 |
else // Non-hex characters in keyString |
802 |
{ |
803 |
if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. |
804 |
identifier != '=' && identifier != '-' && |
805 |
identifier != ' ') && |
806 |
!(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines |
807 |
{ |
808 |
// Alert user regarding faulty line |
809 |
cs_log("WARNING: non-hex value in internal keyfile at %c %04X %s %s", identifier, provider, keyName, keyString); |
810 |
} |
811 |
} |
812 |
free(key); |
813 |
line = strtok_r(NULL, "\n", &saveptr); |
814 |
} |
815 |
free(keyData); |
816 |
} |
817 |
#endif |
818 |
|
819 |
void read_emu_eebin(const char *path, const char *name) |
820 |
{ |
821 |
char tmp[256]; |
822 |
FILE *file = NULL; |
823 |
uint8_t i, buffer[64][32], dummy[2][32]; |
824 |
uint32_t prvid; |
825 |
|
826 |
// Set path |
827 |
if (path != NULL) |
828 |
{ |
829 |
snprintf(tmp, 256, "%s%s", path, name); |
830 |
} |
831 |
else // No path set, use SoftCam.Keys's path |
832 |
{ |
833 |
snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); |
834 |
} |
835 |
|
836 |
// Read file to buffer |
837 |
if ((file = fopen(tmp, "rb")) != NULL) |
838 |
{ |
839 |
cs_log("Reading key file: %s", tmp); |
840 |
|
841 |
if (fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) |
842 |
{ |
843 |
cs_log("Corrupt key file: %s", tmp); |
844 |
fclose(file); |
845 |
return; |
846 |
} |
847 |
|
848 |
fclose(file); |
849 |
} |
850 |
else |
851 |
{ |
852 |
if (path != NULL) |
853 |
{ |
854 |
cs_log("Cannot open key file: %s", tmp); |
855 |
} |
856 |
|
857 |
return; |
858 |
} |
859 |
|
860 |
// Save keys to db |
861 |
memset(dummy[0], 0x00, 32); |
862 |
memset(dummy[1], 0xFF, 32); |
863 |
prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; |
864 |
|
865 |
for (i = 0; i < 32; i++) // Set "3B" type keys |
866 |
{ |
867 |
// Write keys if they have "real" values |
868 |
if ((memcmp(buffer[i], dummy[0], 32) !=0) && (memcmp(buffer[i], dummy[1], 32) != 0)) |
869 |
{ |
870 |
snprintf(tmp, 5, "3B%02X", i); |
871 |
SetKey('D', prvid, tmp, buffer[i], 32, 0, NULL, NULL); |
872 |
} |
873 |
} |
874 |
|
875 |
for (i = 0; i < 32; i++) // Set "56" type keys |
876 |
{ |
877 |
// Write keys if they have "real" values |
878 |
if ((memcmp(buffer[32 + i], dummy[0], 32) !=0) && (memcmp(buffer[32 + i], dummy[1], 32) != 0)) |
879 |
{ |
880 |
snprintf(tmp, 5, "56%02X", i); |
881 |
SetKey('D', prvid, tmp, buffer[32 + i], 32, 0, NULL, NULL); |
882 |
} |
883 |
} |
884 |
} |
885 |
|
886 |
void read_emu_deskey(uint8_t *dreOverKey, uint8_t len) |
887 |
{ |
888 |
uint8_t i; |
889 |
|
890 |
if (len == 128) |
891 |
{ |
892 |
cs_log("Reading DreCrypt overcrypt (ADEC) key"); |
893 |
|
894 |
for (i = 0; i < 16; i++) |
895 |
{ |
896 |
SetKey('D', i, "OVER", dreOverKey + (i * 8), 8, 0, NULL, NULL); |
897 |
} |
898 |
} |
899 |
else if ((len != 0 && len < 128) || len > 128) |
900 |
{ |
901 |
cs_log("DreCrypt overcrypt (ADEC) key has wrong length"); |
902 |
} |
903 |
} |
904 |
|
905 |
// Shared functions |
906 |
|
907 |
static inline uint16_t GetEcmLen(const uint8_t *ecm) |
908 |
{ |
909 |
return (((ecm[1] & 0x0f)<< 8) | ecm[2]) +3; |
910 |
} |
911 |
|
912 |
static void ReverseMem(uint8_t *in, int32_t len) |
913 |
{ |
914 |
uint8_t temp; |
915 |
int32_t i; |
916 |
for(i = 0; i < (len / 2); i++) { |
917 |
temp = in[i]; |
918 |
in[i] = in[len - i - 1]; |
919 |
in[len - i - 1] = temp; |
920 |
} |
921 |
} |
922 |
|
923 |
static void ReverseMemInOut(uint8_t *out, const uint8_t *in, int32_t n) |
924 |
{ |
925 |
if(n>0) { |
926 |
out+=n; |
927 |
do { |
928 |
*(--out)=*(in++); |
929 |
} |
930 |
while(--n); |
931 |
} |
932 |
} |
933 |
|
934 |
static int8_t EmuRSAInput(BIGNUM *d, const uint8_t *in, int32_t n, int8_t le) |
935 |
{ |
936 |
int8_t result = 0; |
937 |
|
938 |
if(le) { |
939 |
uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*n); |
940 |
if(tmp == NULL) { |
941 |
return 0; |
942 |
} |
943 |
ReverseMemInOut(tmp,in,n); |
944 |
result = BN_bin2bn(tmp,n,d)!=0; |
945 |
free(tmp); |
946 |
} |
947 |
else { |
948 |
result = BN_bin2bn(in,n,d)!=0; |
949 |
} |
950 |
return result; |
951 |
} |
952 |
|
953 |
static int32_t EmuRSAOutput(uint8_t *out, int32_t n, BIGNUM *r, int8_t le) |
954 |
{ |
955 |
int32_t s = BN_num_bytes(r); |
956 |
if(s>n) { |
957 |
uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t)*s); |
958 |
if(buff == NULL) { |
959 |
return 0; |
960 |
} |
961 |
BN_bn2bin(r,buff); |
962 |
memcpy(out,buff+s-n,n); |
963 |
free(buff); |
964 |
} |
965 |
else if(s<n) { |
966 |
int32_t l=n-s; |
967 |
memset(out,0,l); |
968 |
BN_bn2bin(r,out+l); |
969 |
} |
970 |
else { |
971 |
BN_bn2bin(r,out); |
972 |
} |
973 |
if(le) { |
974 |
ReverseMem(out,n); |
975 |
} |
976 |
return s; |
977 |
} |
978 |
|
979 |
static int32_t EmuRSA(uint8_t *out, const uint8_t *in, int32_t n, BIGNUM *exp, BIGNUM *mod, int8_t le) |
980 |
{ |
981 |
BN_CTX *ctx; |
982 |
BIGNUM *r, *d; |
983 |
int32_t result = 0; |
984 |
|
985 |
ctx = BN_CTX_new(); |
986 |
r = BN_new(); |
987 |
d = BN_new(); |
988 |
|
989 |
if(EmuRSAInput(d,in,n,le) && BN_mod_exp(r,d,exp,mod,ctx)) { |
990 |
result = EmuRSAOutput(out,n,r,le); |
991 |
} |
992 |
|
993 |
BN_free(d); |
994 |
BN_free(r); |
995 |
BN_CTX_free(ctx); |
996 |
return result; |
997 |
} |
998 |
|
999 |
static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2) |
1000 |
{ |
1001 |
uint32_t i; |
1002 |
switch(len) |
1003 |
{ |
1004 |
case 16: |
1005 |
for(i = 8; i < 16; ++i) |
1006 |
{ |
1007 |
data[i] = v1[i] ^ v2[i]; |
1008 |
} |
1009 |
case 8: |
1010 |
for(i = 4; i < 8; ++i) |
1011 |
{ |
1012 |
data[i] = v1[i] ^ v2[i]; |
1013 |
} |
1014 |
case 4: |
1015 |
for(i = 0; i < 4; ++i) |
1016 |
{ |
1017 |
data[i] = v1[i] ^ v2[i]; |
1018 |
} |
1019 |
break; |
1020 |
default: |
1021 |
while(len--) { *data++ = *v1++ ^ *v2++; } |
1022 |
break; |
1023 |
} |
1024 |
} |
1025 |
|
1026 |
static int8_t isValidDCW(uint8_t *dw) |
1027 |
{ |
1028 |
if (((dw[0]+dw[1]+dw[2]) & 0xFF) != dw[3]) { |
1029 |
return 0; |
1030 |
} |
1031 |
if (((dw[4]+dw[5]+dw[6]) & 0xFF) != dw[7]) { |
1032 |
return 0; |
1033 |
} |
1034 |
if (((dw[8]+dw[9]+dw[10]) & 0xFF) != dw[11]) { |
1035 |
return 0; |
1036 |
} |
1037 |
if (((dw[12]+dw[13]+dw[14]) & 0xFF) != dw[15]) { |
1038 |
return 0; |
1039 |
} |
1040 |
return 1; |
1041 |
} |
1042 |
|
1043 |
static inline uint8_t GetBit(uint8_t byte, uint8_t bitnb) |
1044 |
{ |
1045 |
return ((byte&(1<<bitnb)) ? 1: 0); |
1046 |
} |
1047 |
|
1048 |
static inline uint8_t SetBit(uint8_t val, uint8_t bitnb, uint8_t biton) |
1049 |
{ |
1050 |
return (biton ? (val | (1<<bitnb)) : (val & ~(1<<bitnb))); |
1051 |
} |
1052 |
|
1053 |
static void ExpandDesKey(unsigned char *key) |
1054 |
{ |
1055 |
uint8_t i, j, parity; |
1056 |
uint8_t tmpKey[7]; |
1057 |
|
1058 |
memcpy(tmpKey, key, 7); |
1059 |
|
1060 |
key[0] = (tmpKey[0] & 0xFE); |
1061 |
key[1] = ((tmpKey[0] << 7) | ((tmpKey[1] >> 1) & 0xFE)); |
1062 |
key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE)); |
1063 |
key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE)); |
1064 |
key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE)); |
1065 |
key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE)); |
1066 |
key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE)); |
1067 |
key[7] = (tmpKey[6] << 1); |
1068 |
|
1069 |
for (i = 0; i < 8; i++) |
1070 |
{ |
1071 |
parity = 1; |
1072 |
for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) { parity = ~parity & 0x01; } |
1073 |
key[i] |= parity; |
1074 |
} |
1075 |
} |
1076 |
|
1077 |
// Cryptoworks EMU |
1078 |
static int8_t GetCwKey(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) |
1079 |
{ |
1080 |
|
1081 |
char keyName[EMU_MAX_CHAR_KEYNAME]; |
1082 |
uint32_t tmp; |
1083 |
|
1084 |
if((ident >> 4) == 0xD02A) { |
1085 |
keyIndex &=0xFE; // map to even number key indexes |
1086 |
} |
1087 |
if((ident >> 4) == 0xD00C) { |
1088 |
ident = 0x0D00C0; // map provider C? to C0 |
1089 |
} |
1090 |
else if(keyIndex == 6 && ((ident >> 8) == 0x0D05)) { |
1091 |
ident = 0x0D0504; // always use provider 04 system key |
1092 |
} |
1093 |
|
1094 |
tmp = keyIndex; |
1095 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp); |
1096 |
if(FindKey('W', ident, 0, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) { |
1097 |
return 1; |
1098 |
} |
1099 |
|
1100 |
return 0; |
1101 |
} |
1102 |
|
1103 |
static const uint8_t cw_sbox1[64] = { |
1104 |
0xD8,0xD7,0x83,0x3D,0x1C,0x8A,0xF0,0xCF,0x72,0x4C,0x4D,0xF2,0xED,0x33,0x16,0xE0, |
1105 |
0x8F,0x28,0x7C,0x82,0x62,0x37,0xAF,0x59,0xB7,0xE0,0x00,0x3F,0x09,0x4D,0xF3,0x94, |
1106 |
0x16,0xA5,0x58,0x83,0xF2,0x4F,0x67,0x30,0x49,0x72,0xBF,0xCD,0xBE,0x98,0x81,0x7F, |
1107 |
0xA5,0xDA,0xA7,0x7F,0x89,0xC8,0x78,0xA7,0x8C,0x05,0x72,0x84,0x52,0x72,0x4D,0x38 |
1108 |
}; |
1109 |
static const uint8_t cw_sbox2[64] = { |
1110 |
0xD8,0x35,0x06,0xAB,0xEC,0x40,0x79,0x34,0x17,0xFE,0xEA,0x47,0xA3,0x8F,0xD5,0x48, |
1111 |
0x0A,0xBC,0xD5,0x40,0x23,0xD7,0x9F,0xBB,0x7C,0x81,0xA1,0x7A,0x14,0x69,0x6A,0x96, |
1112 |
0x47,0xDA,0x7B,0xE8,0xA1,0xBF,0x98,0x46,0xB8,0x41,0x45,0x9E,0x5E,0x20,0xB2,0x35, |
1113 |
0xE4,0x2F,0x9A,0xB5,0xDE,0x01,0x65,0xF8,0x0F,0xB2,0xD2,0x45,0x21,0x4E,0x2D,0xDB |
1114 |
}; |
1115 |
static const uint8_t cw_sbox3[64] = { |
1116 |
0xDB,0x59,0xF4,0xEA,0x95,0x8E,0x25,0xD5,0x26,0xF2,0xDA,0x1A,0x4B,0xA8,0x08,0x25, |
1117 |
0x46,0x16,0x6B,0xBF,0xAB,0xE0,0xD4,0x1B,0x89,0x05,0x34,0xE5,0x74,0x7B,0xBB,0x44, |
1118 |
0xA9,0xC6,0x18,0xBD,0xE6,0x01,0x69,0x5A,0x99,0xE0,0x87,0x61,0x56,0x35,0x76,0x8E, |
1119 |
0xF7,0xE8,0x84,0x13,0x04,0x7B,0x9B,0xA6,0x7A,0x1F,0x6B,0x5C,0xA9,0x86,0x54,0xF9 |
1120 |
}; |
1121 |
static const uint8_t cw_sbox4[64] = { |
1122 |
0xBC,0xC1,0x41,0xFE,0x42,0xFB,0x3F,0x10,0xB5,0x1C,0xA6,0xC9,0xCF,0x26,0xD1,0x3F, |
1123 |
0x02,0x3D,0x19,0x20,0xC1,0xA8,0xBC,0xCF,0x7E,0x92,0x4B,0x67,0xBC,0x47,0x62,0xD0, |
1124 |
0x60,0x9A,0x9E,0x45,0x79,0x21,0x89,0xA9,0xC3,0x64,0x74,0x9A,0xBC,0xDB,0x43,0x66, |
1125 |
0xDF,0xE3,0x21,0xBE,0x1E,0x16,0x73,0x5D,0xA2,0xCD,0x8C,0x30,0x67,0x34,0x9C,0xCB |
1126 |
}; |
1127 |
static const uint8_t AND_bit1[8] = {0x00,0x40,0x04,0x80,0x21,0x10,0x02,0x08}; |
1128 |
static const uint8_t AND_bit2[8] = {0x80,0x08,0x01,0x40,0x04,0x20,0x10,0x02}; |
1129 |
static const uint8_t AND_bit3[8] = {0x82,0x40,0x01,0x10,0x00,0x20,0x04,0x08}; |
1130 |
static const uint8_t AND_bit4[8] = {0x02,0x10,0x04,0x40,0x80,0x08,0x01,0x20}; |
1131 |
|
1132 |
static void CW_SWAP_KEY(uint8_t *key) |
1133 |
{ |
1134 |
uint8_t k[8]; |
1135 |
memcpy(k, key, 8); |
1136 |
memcpy(key, key + 8, 8); |
1137 |
memcpy(key + 8, k, 8); |
1138 |
} |
1139 |
|
1140 |
static void CW_SWAP_DATA(uint8_t *k) |
1141 |
{ |
1142 |
uint8_t d[4]; |
1143 |
memcpy(d, k + 4, 4); |
1144 |
memcpy(k + 4 ,k ,4); |
1145 |
memcpy(k, d, 4); |
1146 |
} |
1147 |
|
1148 |
static void CW_DES_ROUND(uint8_t *d, uint8_t *k) |
1149 |
{ |
1150 |
uint8_t aa[44] = {1,0,3,1,2,2,3,2,1,3,1,1,3,0,1,2,3,1,3,2,2,0,7,6,5,4,7,6,5,7,6,5,6,7,5,7,5,7,6,6,7,5,4,4}; |
1151 |
uint8_t bb[44] = {0x80,0x08,0x10,0x02,0x08,0x40,0x01,0x20,0x40,0x80,0x04,0x10,0x04,0x01,0x01,0x02,0x20,0x20,0x02,0x01, |
1152 |
0x80,0x04,0x02,0x02,0x08,0x02,0x10,0x80,0x01,0x20,0x08,0x80,0x01,0x08,0x40,0x01,0x02,0x80,0x10,0x40,0x40,0x10,0x08,0x01 |
1153 |
}; |
1154 |
uint8_t ff[4] = {0x02,0x10,0x04,0x04}; |
1155 |
uint8_t l[24] = {0,2,4,6,7,5,3,1,4,5,6,7,7,6,5,4,7,4,5,6,4,7,6,5}; |
1156 |
|
1157 |
uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0, *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l+8, *p3 = l+16; |
1158 |
|
1159 |
for (m = 0; m < 2; m++) { |
1160 |
for(i = 0; i < 4; i++) { |
1161 |
des_td[*p1++] = |
1162 |
(m) ? ((d[*p2++]*2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00): (d[*p2++]/2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00); |
1163 |
} |
1164 |
} |
1165 |
|
1166 |
for (i = 0; i < 8; i++) { |
1167 |
c = (c) ? 0 : 1; |
1168 |
r = (c) ? 6 : 7; |
1169 |
n = (i) ? i-1 : 1; |
1170 |
o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n]; |
1171 |
for (m = 1; m < r; m++) { |
1172 |
o = (c) ? (o*2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o/2) | ((k[*a++] & *b++) ? 0x80 : 0x00); |
1173 |
} |
1174 |
n = (i) ? n+1 : 0; |
1175 |
des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n] )/4; |
1176 |
} |
1177 |
|
1178 |
for( i = 0; i < 8; i++) { |
1179 |
d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]); |
1180 |
d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]); |
1181 |
d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]); |
1182 |
d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]); |
1183 |
} |
1184 |
|
1185 |
CW_SWAP_DATA(d); |
1186 |
} |
1187 |
|
1188 |
static void CW_48_Key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype) |
1189 |
{ |
1190 |
uint8_t Round_Counter, i = 8, *key128 = inkey, *key48 = inkey + 0x10; |
1191 |
Round_Counter = 7 - (algotype & 7); |
1192 |
|
1193 |
memset(outkey, 0, 16); |
1194 |
memcpy(outkey, key48, 6); |
1195 |
|
1196 |
for( ; i > Round_Counter; i--) { |
1197 |
if (i > 1) { |
1198 |
outkey[i-2] = key128[i]; |
1199 |
} |
1200 |
} |
1201 |
} |
1202 |
|
1203 |
static void CW_LS_DES_KEY(uint8_t *key,uint8_t Rotate_Counter) |
1204 |
{ |
1205 |
uint8_t round[] = {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}; |
1206 |
uint8_t i, n; |
1207 |
uint16_t k[8]; |
1208 |
|
1209 |
n = round[Rotate_Counter]; |
1210 |
|
1211 |
for (i = 0; i < 8; i++) { |
1212 |
k[i] = key[i]; |
1213 |
} |
1214 |
|
1215 |
for (i = 1; i < n + 1; i++) { |
1216 |
k[7] = (k[7]*2) | ((k[4] & 0x008) ? 1 : 0); |
1217 |
k[6] = (k[6]*2) | ((k[7] & 0xF00) ? 1 : 0); |
1218 |
k[7] &=0xff; |
1219 |
k[5] = (k[5]*2) | ((k[6] & 0xF00) ? 1 : 0); |
1220 |
k[6] &=0xff; |
1221 |
k[4] = ((k[4]*2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF; |
1222 |
k[5] &= 0xff; |
1223 |
k[3] = (k[3]*2) | ((k[0] & 0x008) ? 1 : 0); |
1224 |
k[2] = (k[2]*2) | ((k[3] & 0xF00) ? 1 : 0); |
1225 |
k[3] &= 0xff; |
1226 |
k[1] = (k[1]*2) | ((k[2] & 0xF00) ? 1 : 0); |
1227 |
k[2] &= 0xff; |
1228 |
k[0] = ((k[0]*2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF; |
1229 |
k[1] &= 0xff; |
1230 |
} |
1231 |
for (i = 0; i < 8; i++) { |
1232 |
key[i] = (uint8_t) k[i]; |
1233 |
} |
1234 |
} |
1235 |
|
1236 |
static void CW_RS_DES_KEY(uint8_t *k, uint8_t Rotate_Counter) |
1237 |
{ |
1238 |
uint8_t i,c; |
1239 |
for (i = 1; i < Rotate_Counter+1; i++) { |
1240 |
c = (k[3] & 0x10) ? 0x80 : 0; |
1241 |
k[3] /= 2; |
1242 |
if (k[2] & 1) { |
1243 |
k[3] |= 0x80; |
1244 |
} |
1245 |
k[2] /= 2; |
1246 |
if (k[1] & 1) { |
1247 |
k[2] |= 0x80; |
1248 |
} |
1249 |
k[1] /= 2; |
1250 |
if (k[0] & 1) { |
1251 |
k[1] |= 0x80; |
1252 |
} |
1253 |
k[0] /= 2; |
1254 |
k[0] |= c ; |
1255 |
c = (k[7] & 0x10) ? 0x80 : 0; |
1256 |
k[7] /= 2; |
1257 |
if (k[6] & 1) { |
1258 |
k[7] |= 0x80; |
1259 |
} |
1260 |
k[6] /= 2; |
1261 |
if (k[5] & 1) { |
1262 |
k[6] |= 0x80; |
1263 |
} |
1264 |
k[5] /= 2; |
1265 |
if (k[4] & 1) { |
1266 |
k[5] |= 0x80; |
1267 |
} |
1268 |
k[4] /= 2; |
1269 |
k[4] |= c; |
1270 |
} |
1271 |
} |
1272 |
|
1273 |
static void CW_RS_DES_SUBKEY(uint8_t *k, uint8_t Rotate_Counter) |
1274 |
{ |
1275 |
uint8_t round[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; |
1276 |
CW_RS_DES_KEY(k, round[Rotate_Counter]); |
1277 |
} |
1278 |
|
1279 |
static void CW_PREP_KEY(uint8_t *key ) |
1280 |
{ |
1281 |
uint8_t DES_key[8],j; |
1282 |
int32_t Round_Counter = 6,i,a; |
1283 |
key[7] = 6; |
1284 |
memset(DES_key, 0 , 8); |
1285 |
do { |
1286 |
a = 7; |
1287 |
i = key[7]; |
1288 |
j = key[Round_Counter]; |
1289 |
do { |
1290 |
DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1: 0) ) & 0xFF; |
1291 |
j /=2; |
1292 |
i--; |
1293 |
if (i < 0) { |
1294 |
i = 6; |
1295 |
} |
1296 |
a--; |
1297 |
} |
1298 |
while (a >= 0); |
1299 |
key[7] = i; |
1300 |
Round_Counter--; |
1301 |
} |
1302 |
while ( Round_Counter >= 0 ); |
1303 |
a = DES_key[4]; |
1304 |
DES_key[4] = DES_key[6]; |
1305 |
DES_key[6] = a; |
1306 |
DES_key[7] = (DES_key[3] * 16) & 0xFF; |
1307 |
memcpy(key,DES_key,8); |
1308 |
CW_RS_DES_KEY(key,4); |
1309 |
} |
1310 |
|
1311 |
static void CW_L2DES(uint8_t *data, uint8_t *key, uint8_t algo) |
1312 |
{ |
1313 |
uint8_t i, k0[22], k1[22]; |
1314 |
memcpy(k0,key,22); |
1315 |
memcpy(k1,key,22); |
1316 |
CW_48_Key(k0, k1,algo); |
1317 |
CW_PREP_KEY(k1); |
1318 |
for (i = 0; i< 2; i++) { |
1319 |
CW_LS_DES_KEY( k1,15); |
1320 |
CW_DES_ROUND( data ,k1); |
1321 |
} |
1322 |
} |
1323 |
|
1324 |
static void CW_R2DES(uint8_t *data, uint8_t *key, uint8_t algo) |
1325 |
{ |
1326 |
uint8_t i, k0[22],k1[22]; |
1327 |
memcpy(k0,key,22); |
1328 |
memcpy(k1,key,22); |
1329 |
CW_48_Key(k0, k1, algo); |
1330 |
CW_PREP_KEY(k1); |
1331 |
for (i = 0; i< 2; i++) { |
1332 |
CW_LS_DES_KEY(k1,15); |
1333 |
} |
1334 |
for (i = 0; i< 2; i++) { |
1335 |
CW_DES_ROUND( data ,k1); |
1336 |
CW_RS_DES_SUBKEY(k1,1); |
1337 |
} |
1338 |
CW_SWAP_DATA(data); |
1339 |
} |
1340 |
|
1341 |
static void CW_DES(uint8_t *data, uint8_t *inkey, uint8_t m) |
1342 |
{ |
1343 |
uint8_t key[22], i; |
1344 |
memcpy(key, inkey + 9, 8); |
1345 |
CW_PREP_KEY( key ); |
1346 |
for (i = 16; i > 0; i--) { |
1347 |
if (m == 1) { |
1348 |
CW_LS_DES_KEY(key, (uint8_t) (i-1)); |
1349 |
} |
1350 |
CW_DES_ROUND( data ,key); |
1351 |
if (m == 0) { |
1352 |
CW_RS_DES_SUBKEY(key, (uint8_t) (i-1)); |
1353 |
} |
1354 |
} |
1355 |
} |
1356 |
|
1357 |
static void CW_DEC_ENC(uint8_t *d, uint8_t *k, uint8_t a,uint8_t m) |
1358 |
{ |
1359 |
uint8_t n = m & 1; |
1360 |
CW_L2DES(d , k, a); |
1361 |
CW_DES (d , k, n); |
1362 |
CW_R2DES(d , k, a); |
1363 |
if (m & 2) { |
1364 |
CW_SWAP_KEY(k); |
1365 |
} |
1366 |
} |
1367 |
|
1368 |
static void Cryptoworks3DES(uint8_t *data, uint8_t *key) |
1369 |
{ |
1370 |
uint32_t ks1[32], ks2[32]; |
1371 |
|
1372 |
des_set_key(key, ks1); |
1373 |
des_set_key(key+8, ks2); |
1374 |
|
1375 |
des(data, ks1, 0); |
1376 |
des(data, ks2, 1); |
1377 |
des(data, ks1, 0); |
1378 |
} |
1379 |
|
1380 |
static uint8_t CryptoworksProcessNano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, uint8_t nanoLength, uint8_t nano80Algo) |
1381 |
{ |
1382 |
int32_t i, j; |
1383 |
uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16]; |
1384 |
if(nanoLength < 11) { |
1385 |
return 0; |
1386 |
} |
1387 |
if(caid == 0x0D00 && provider != 0xA0 && !GetCwKey(k0D00C000, 0x0D00C0, 0, 16, 1)) { |
1388 |
return 0; |
1389 |
} |
1390 |
|
1391 |
if(nano80Algo > 1) { |
1392 |
return 0; |
1393 |
} |
1394 |
|
1395 |
memset(t, 0, 8); |
1396 |
memcpy(dat1, data, 8); |
1397 |
|
1398 |
if(caid == 0x0D00 && provider != 0xA0) { |
1399 |
memcpy(key, k0D00C000, 16); |
1400 |
} |
1401 |
else { |
1402 |
memcpy(key, opKey, 16); |
1403 |
} |
1404 |
Cryptoworks3DES(data, key); |
1405 |
memcpy(desKey, data, 8); |
1406 |
|
1407 |
memcpy(data, dat1, 8); |
1408 |
if(caid == 0x0D00 && provider != 0xA0) { |
1409 |
memcpy(key, &k0D00C000[8], 8); |
1410 |
memcpy(&key[8], k0D00C000, 8); |
1411 |
} |
1412 |
else { |
1413 |
memcpy(key, &opKey[8], 8); |
1414 |
memcpy(&key[8], opKey, 8); |
1415 |
} |
1416 |
Cryptoworks3DES(data, key); |
1417 |
memcpy(&desKey[8], data, 8); |
1418 |
|
1419 |
for(i=8; i+7<nanoLength; i+=8) { |
1420 |
memcpy(dat1, &data[i], 8); |
1421 |
memcpy(dat2, dat1, 8); |
1422 |
memcpy(key, desKey, 16); |
1423 |
Cryptoworks3DES(dat1, key); |
1424 |
for(j=0; j<8; j++) { |
1425 |
dat1[j] ^= t[j]; |
1426 |
} |
1427 |
memcpy(&data[i], dat1, 8); |
1428 |
memcpy(t, dat2, 8); |
1429 |
} |
1430 |
|
1431 |
return data[10] + 5; |
1432 |
} |
1433 |
|
1434 |
static void CryptoworksSignature(const uint8_t *data, uint32_t length, uint8_t *key, uint8_t *signature) |
1435 |
{ |
1436 |
uint32_t i, sigPos; |
1437 |
int8_t algo, first; |
1438 |
|
1439 |
algo = data[0] & 7; |
1440 |
if(algo == 7) { |
1441 |
algo = 6; |
1442 |
} |
1443 |
memset(signature, 0, 8); |
1444 |
first = 1; |
1445 |
sigPos = 0; |
1446 |
for(i=0; i<length; i++) { |
1447 |
signature[sigPos] ^= data[i]; |
1448 |
sigPos++; |
1449 |
|
1450 |
if(sigPos > 7) { |
1451 |
if (first) { |
1452 |
CW_L2DES(signature, key, algo); |
1453 |
} |
1454 |
CW_DES(signature, key, 1); |
1455 |
|
1456 |
sigPos = 0; |
1457 |
first = 0; |
1458 |
} |
1459 |
} |
1460 |
if(sigPos > 0) { |
1461 |
CW_DES(signature, key, 1); |
1462 |
} |
1463 |
CW_R2DES(signature, key, algo); |
1464 |
} |
1465 |
|
1466 |
static void CryptoworksDecryptDes(uint8_t *data, uint8_t algo, uint8_t *key) |
1467 |
{ |
1468 |
int32_t i; |
1469 |
uint8_t k[22], t[8]; |
1470 |
|
1471 |
algo &= 7; |
1472 |
if(algo<7) { |
1473 |
CW_DEC_ENC(data, key, algo, 0); |
1474 |
} |
1475 |
else { |
1476 |
memcpy(k, key, 22); |
1477 |
for(i=0; i<3; i++) { |
1478 |
CW_DEC_ENC(data, k, algo, i&1); |
1479 |
memcpy(t,k,8); |
1480 |
memcpy(k,k+8,8); |
1481 |
memcpy(k+8,t,8); |
1482 |
} |
1483 |
} |
1484 |
} |
1485 |
|
1486 |
static int8_t CryptoworksECM(uint32_t caid, uint8_t *ecm, uint8_t *cw) |
1487 |
{ |
1488 |
uint32_t ident; |
1489 |
uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1; |
1490 |
int32_t provider = -1; |
1491 |
uint16_t i, j, ecmLen = GetEcmLen(ecm); |
1492 |
|
1493 |
if(ecmLen < 8) { |
1494 |
return 1; |
1495 |
} |
1496 |
if(ecm[7] != ecmLen - 8) { |
1497 |
return 1; |
1498 |
} |
1499 |
|
1500 |
memset(key, 0, 22); |
1501 |
|
1502 |
for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { |
1503 |
if(ecm[i] == 0x83 && i+2 < ecmLen) { |
1504 |
provider = ecm[i+2] & 0xFC; |
1505 |
keyIndex = ecm[i+2] & 3; |
1506 |
keyIndex = keyIndex ? 1 : 0; |
1507 |
} |
1508 |
else if(ecm[i] == 0x84 && i+3 < ecmLen) { |
1509 |
//nano80Provider = ecm[i+2] & 0xFC; |
1510 |
//nano80KeyIndex = ecm[i+2] & 3; |
1511 |
//nano80KeyIndex = nano80KeyIndex ? 1 : 0; |
1512 |
nano80Algo = ecm[i+3]; |
1513 |
} |
1514 |
} |
1515 |
|
1516 |
if(provider < 0) { |
1517 |
switch(caid) { |
1518 |
case 0x0D00: |
1519 |
provider = 0xC0; |
1520 |
break; |
1521 |
case 0x0D02: |
1522 |
provider = 0xA0; |
1523 |
break; |
1524 |
case 0x0D03: |
1525 |
provider = 0x04; |
1526 |
break; |
1527 |
case 0x0D05: |
1528 |
provider = 0x04; |
1529 |
break; |
1530 |
default: |
1531 |
return 1; |
1532 |
} |
1533 |
} |
1534 |
|
1535 |
ident = (caid << 8) | provider; |
1536 |
if(!GetCwKey(key, ident, keyIndex, 16, 1)) { |
1537 |
return 2; |
1538 |
} |
1539 |
if(!GetCwKey(&key[16], ident, 6, 6, 1)) { |
1540 |
return 2; |
1541 |
} |
1542 |
|
1543 |
for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { |
1544 |
if(ecm[i] == 0x80 && i+2+7 < ecmLen && i+2+ecm[i+1] <= ecmLen |
1545 |
&& (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) { |
1546 |
nanoLength = ecm[i+1]; |
1547 |
newEcmLength = CryptoworksProcessNano80(ecm+i+2, caid, provider, key, nanoLength, nano80Algo); |
1548 |
if(newEcmLength == 0 || newEcmLength > ecmLen-(i+2+3)) { |
1549 |
return 1; |
1550 |
} |
1551 |
ecm[i+2+3] = 0x81; |
1552 |
ecm[i+2+4] = 0x70; |
1553 |
ecm[i+2+5] = newEcmLength; |
1554 |
ecm[i+2+6] = 0x81; |
1555 |
ecm[i+2+7] = 0xFF; |
1556 |
return CryptoworksECM(caid, ecm+i+2+3, cw); |
1557 |
} |
1558 |
} |
1559 |
|
1560 |
if(ecmLen - 15 < 1) { |
1561 |
return 1; |
1562 |
} |
1563 |
CryptoworksSignature(ecm + 5, ecmLen - 15, key, signature); |
1564 |
for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { |
1565 |
switch(ecm[i]) { |
1566 |
case 0xDA: |
1567 |
case 0xDB: |
1568 |
case 0xDC: |
1569 |
if(i+2+ecm[i+1] > ecmLen) { |
1570 |
break; |
1571 |
} |
1572 |
for(j=0; j+7<ecm[i+1]; j+=8) { |
1573 |
CryptoworksDecryptDes(&ecm[i+2+j], ecm[5], key); |
1574 |
} |
1575 |
break; |
1576 |
case 0xDF: |
1577 |
if(i+2+8 > ecmLen) { |
1578 |
break; |
1579 |
} |
1580 |
if(memcmp(&ecm[i+2], signature, 8)) { |
1581 |
return 6; |
1582 |
} |
1583 |
break; |
1584 |
} |
1585 |
} |
1586 |
|
1587 |
for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { |
1588 |
switch(ecm[i]) { |
1589 |
case 0xDB: |
1590 |
if(i+2+ecm[i+1] <= ecmLen && ecm[i+1] == 16) { |
1591 |
memcpy(cw, &ecm[i+2], 16); |
1592 |
return 0; |
1593 |
} |
1594 |
break; |
1595 |
} |
1596 |
} |
1597 |
|
1598 |
return 5; |
1599 |
} |
1600 |
|
1601 |
// SoftNDS EMU |
1602 |
static const uint8_t nds_const[]= {0x0F,0x1E,0x2D,0x3C,0x4B,0x5A,0x69,0x78,0x87,0x96,0xA5,0xB4,0xC3,0xD2,0xE1,0xF0}; |
1603 |
|
1604 |
uint8_t viasat_const[]= { |
1605 |
0x15,0x85,0xC5,0xE4,0xB8,0x52,0xEC,0xF7,0xC3,0xD9,0x08,0xBA,0x22,0x4A,0x66,0xF2, |
1606 |
0x82,0x15,0x4F,0xB2,0x18,0x48,0x63,0x97,0xDC,0x19,0xD8,0x51,0x9A,0x39,0xFC,0xCA, |
1607 |
0x1C,0x24,0xD0,0x65,0xA9,0x66,0x2D,0xD6,0x53,0x3B,0x86,0xBA,0x40,0xEA,0x4C,0x6D, |
1608 |
0xD9,0x1E,0x41,0x14,0xFE,0x15,0xAF,0xC3,0x18,0xC5,0xF8,0xA7,0xA8,0x01,0x00,0x01, |
1609 |
}; |
1610 |
|
1611 |
static int8_t SoftNDSECM(uint16_t caid, uint8_t *ecm, uint8_t *dw) |
1612 |
{ |
1613 |
int32_t i; |
1614 |
uint8_t *tDW, irdEcmLen, offsetCw = 0, offsetP2 = 0; |
1615 |
uint8_t digest[16], md5_const[64]; |
1616 |
MD5_CTX mdContext; |
1617 |
uint16_t ecmLen = GetEcmLen(ecm); |
1618 |
|
1619 |
if(ecmLen < 7) { |
1620 |
return 1; |
1621 |
} |
1622 |
|
1623 |
if(ecm[3] != 0x00 || ecm[4] != 0x00 || ecm[5] != 0x01) { |
1624 |
return 1; |
1625 |
} |
1626 |
|
1627 |
irdEcmLen = ecm[6]; |
1628 |
if(irdEcmLen < (10+3+8+4) || irdEcmLen+6 >= ecmLen) { |
1629 |
return 1; |
1630 |
} |
1631 |
|
1632 |
for(i=0; 10+i+2 < irdEcmLen; i++) { |
1633 |
if(ecm[17+i] == 0x0F && ecm[17+i+1] == 0x40 && ecm[17+i+2] == 0x00) { |
1634 |
offsetCw = 17+i+3; |
1635 |
offsetP2 = offsetCw+9; |
1636 |
} |
1637 |
} |
1638 |
|
1639 |
if(offsetCw == 0 || offsetP2 == 0) { |
1640 |
return 1; |
1641 |
} |
1642 |
|
1643 |
if(offsetP2-7+4 > irdEcmLen) { |
1644 |
return 1; |
1645 |
} |
1646 |
|
1647 |
if(caid == 0x090F || caid == 0x093E) { |
1648 |
memcpy(md5_const, viasat_const, 64); |
1649 |
} |
1650 |
else if(!FindKey('S', caid, 0, "00", md5_const, 64, 1, 0, 0, NULL)) { |
1651 |
return 2; |
1652 |
} |
1653 |
|
1654 |
memset(dw,0,16); |
1655 |
tDW = &dw[ecm[0] == 0x81 ? 8 : 0]; |
1656 |
|
1657 |
MD5_Init(&mdContext); |
1658 |
MD5_Update(&mdContext, ecm+7, 10); |
1659 |
MD5_Update(&mdContext, ecm+offsetP2, 4); |
1660 |
MD5_Update(&mdContext, md5_const, 64); |
1661 |
MD5_Update(&mdContext, nds_const, 16); |
1662 |
MD5_Final(digest, &mdContext); |
1663 |
|
1664 |
for (i=0; i<8; i++) { |
1665 |
tDW[i] = digest[i+8] ^ ecm[offsetCw+i]; |
1666 |
} |
1667 |
|
1668 |
if(((tDW[0]+tDW[1]+tDW[2])&0xFF)-tDW[3]) { |
1669 |
return 6; |
1670 |
} |
1671 |
if(((tDW[4]+tDW[5]+tDW[6])&0xFF)-tDW[7]) { |
1672 |
return 6; |
1673 |
} |
1674 |
|
1675 |
return 0; |
1676 |
} |
1677 |
|
1678 |
// Viaccess EMU |
1679 |
static int8_t GetViaKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) |
1680 |
{ |
1681 |
|
1682 |
char keyStr[EMU_MAX_CHAR_KEYNAME]; |
1683 |
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); |
1684 |
if(FindKey('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { |
1685 |
return 1; |
1686 |
} |
1687 |
|
1688 |
if(ident == 0xD00040 && FindKey('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { |
1689 |
return 1; |
1690 |
} |
1691 |
|
1692 |
return 0; |
1693 |
} |
1694 |
|
1695 |
static void Via1Mod(const uint8_t* key2, uint8_t* data) |
1696 |
{ |
1697 |
int32_t kb, db; |
1698 |
for (db=7; db>=0; db--) { |
1699 |
for (kb=7; kb>3; kb--) { |
1700 |
int32_t a0=kb^db; |
1701 |
int32_t pos=7; |
1702 |
if (a0&4) { |
1703 |
a0^=7; |
1704 |
pos^=7; |
1705 |
} |
1706 |
a0=(a0^(kb&3)) + (kb&3); |
1707 |
if (!(a0&4)) { |
1708 |
data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); |
1709 |
} |
1710 |
} |
1711 |
} |
1712 |
for (db=0; db<8; db++) { |
1713 |
for (kb=0; kb<4; kb++) { |
1714 |
int32_t a0=kb^db; |
1715 |
int32_t pos=7; |
1716 |
if (a0&4) { |
1717 |
a0^=7; |
1718 |
pos^=7; |
1719 |
} |
1720 |
a0=(a0^(kb&3)) + (kb&3); |
1721 |
if (!(a0&4)) { |
1722 |
data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); |
1723 |
} |
1724 |
} |
1725 |
} |
1726 |
} |
1727 |
|
1728 |
static void Via1Decode(uint8_t *data, uint8_t *key) |
1729 |
{ |
1730 |
Via1Mod(key+8, data); |
1731 |
nc_des(key, DES_ECM_CRYPT, data); |
1732 |
Via1Mod(key+8, data); |
1733 |
} |
1734 |
|
1735 |
static void Via1Hash(uint8_t *data, uint8_t *key) |
1736 |
{ |
1737 |
Via1Mod(key+8, data); |
1738 |
nc_des(key, DES_ECM_HASH, data); |
1739 |
Via1Mod(key+8, data); |
1740 |
} |
1741 |
|
1742 |
static inline void Via1DoHash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey) |
1743 |
{ |
1744 |
hashbuffer[*pH] ^= data; |
1745 |
(*pH)++; |
1746 |
|
1747 |
if(*pH == 8) { |
1748 |
Via1Hash(hashbuffer, hashkey); |
1749 |
*pH = 0; |
1750 |
} |
1751 |
} |
1752 |
|
1753 |
static int8_t Via1Decrypt(uint8_t* ecm, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) |
1754 |
{ |
1755 |
uint8_t work_key[16]; |
1756 |
uint8_t *data, *des_data1, *des_data2; |
1757 |
uint16_t ecmLen = GetEcmLen(ecm); |
1758 |
int32_t msg_pos; |
1759 |
int32_t encStart = 0, hash_start, i; |
1760 |
uint8_t signature[8], hashbuffer[8], prepared_key[16], hashkey[16]; |
1761 |
uint8_t tmp, k, pH, foundData = 0; |
1762 |
|
1763 |
if (ident == 0) { |
1764 |
return 4; |
1765 |
} |
1766 |
memset(work_key, 0, 16); |
1767 |
if(!GetViaKey(work_key, ident, '0', desKeyIndex, 8, 1)) { |
1768 |
return 2; |
1769 |
} |
1770 |
|
1771 |
if(ecmLen < 11) { |
1772 |
return 1; |
1773 |
} |
1774 |
data = ecm+9; |
1775 |
des_data1 = dw; |
1776 |
des_data2 = dw+8; |
1777 |
|
1778 |
msg_pos = 0; |
1779 |
pH = 0; |
1780 |
memset(hashbuffer, 0, sizeof(hashbuffer)); |
1781 |
memcpy(hashkey, work_key, sizeof(hashkey)); |
1782 |
memset(signature, 0, 8); |
1783 |
|
1784 |
while(9+msg_pos+2 < ecmLen) { |
1785 |
switch (data[msg_pos]) { |
1786 |
case 0xea: |
1787 |
if(9+msg_pos+2+15 < ecmLen) { |
1788 |
encStart = msg_pos + 2; |
1789 |
memcpy(des_data1, &data[msg_pos+2], 8); |
1790 |
memcpy(des_data2, &data[msg_pos+2+8], 8); |
1791 |
foundData |= 1; |
1792 |
} |
1793 |
break; |
1794 |
case 0xf0: |
1795 |
if(9+msg_pos+2+7 < ecmLen) { |
1796 |
memcpy(signature, &data[msg_pos+2], 8); |
1797 |
foundData |= 2; |
1798 |
} |
1799 |
break; |
1800 |
} |
1801 |
msg_pos += data[msg_pos+1]+2; |
1802 |
} |
1803 |
|
1804 |
if(foundData != 3) { |
1805 |
return 1; |
1806 |
} |
1807 |
|
1808 |
pH=i=0; |
1809 |
|
1810 |
if(data[0] == 0x9f && 10+data[1] <= ecmLen) { |
1811 |
Via1DoHash(hashbuffer, &pH, data[i++], hashkey); |
1812 |
Via1DoHash(hashbuffer, &pH, data[i++], hashkey); |
1813 |
|
1814 |
for (hash_start=0; hash_start < data[1]; hash_start++) { |
1815 |
Via1DoHash(hashbuffer, &pH, data[i++], hashkey); |
1816 |
} |
1817 |
|
1818 |
while (pH != 0) { |
1819 |
Via1DoHash(hashbuffer, &pH, 0, hashkey); |
1820 |
} |
1821 |
} |
1822 |
|
1823 |
if (work_key[7] == 0) { |
1824 |
for (; i < encStart + 16; i++) { |
1825 |
Via1DoHash(hashbuffer, &pH, data[i], hashkey); |
1826 |
} |
1827 |
memcpy(prepared_key, work_key, 8); |
1828 |
} |
1829 |
else { |
1830 |
prepared_key[0] = work_key[2]; |
1831 |
prepared_key[1] = work_key[3]; |
1832 |
prepared_key[2] = work_key[4]; |
1833 |
prepared_key[3] = work_key[5]; |
1834 |
prepared_key[4] = work_key[6]; |
1835 |
prepared_key[5] = work_key[0]; |
1836 |
prepared_key[6] = work_key[1]; |
1837 |
prepared_key[7] = work_key[7]; |
1838 |
memcpy(prepared_key+8, work_key+8, 8); |
1839 |
|
1840 |
if (work_key[7] & 1) { |
1841 |
for (; i < encStart; i++) { |
1842 |
Via1DoHash(hashbuffer, &pH, data[i], hashkey); |
1843 |
} |
1844 |
|
1845 |
k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5; |
1846 |
|
1847 |
for (i=0; i<8; i++) { |
1848 |
tmp = des_data1[i]; |
1849 |
des_data1[i] = (k & hashbuffer[pH] ) ^ tmp; |
1850 |
Via1DoHash(hashbuffer, &pH, tmp, hashkey); |
1851 |
} |
1852 |
|
1853 |
for (i = 0; i < 8; i++) { |
1854 |
tmp = des_data2[i]; |
1855 |
des_data2[i] = (k & hashbuffer[pH] ) ^ tmp; |
1856 |
Via1DoHash(hashbuffer, &pH, tmp, hashkey); |
1857 |
} |
1858 |
} |
1859 |
else { |
1860 |
for (; i < encStart + 16; i++) { |
1861 |
Via1DoHash(hashbuffer, &pH, data[i], hashkey); |
1862 |
} |
1863 |
} |
1864 |
} |
1865 |
Via1Decode(des_data1, prepared_key); |
1866 |
Via1Decode(des_data2, prepared_key); |
1867 |
Via1Hash(hashbuffer, hashkey); |
1868 |
if(memcmp(signature, hashbuffer, 8)) { |
1869 |
return 6; |
1870 |
} |
1871 |
return 0; |
1872 |
} |
1873 |
|
1874 |
static int8_t Via26ProcessDw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex) |
1875 |
{ |
1876 |
uint8_t pv1,pv2, i; |
1877 |
uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8]; |
1878 |
uint32_t ks1[32], ks2[32]; |
1879 |
|
1880 |
if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { |
1881 |
return 2; |
1882 |
} |
1883 |
if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { |
1884 |
return 2; |
1885 |
} |
1886 |
if(!GetViaKey(KeyDes1, ident, 'D', 1, 16, 1)) { |
1887 |
return 2; |
1888 |
} |
1889 |
if(!GetViaKey(KeyDes2, ident, '0', desKeyIndex, 16, 1)) { |
1890 |
return 2; |
1891 |
} |
1892 |
if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { |
1893 |
return 2; |
1894 |
} |
1895 |
|
1896 |
for (i=0; i<8; i++) { |
1897 |
pv1 = indata[i]; |
1898 |
Tmp[i] = T1Key[pv1]; |
1899 |
} |
1900 |
for (i=0; i<8; i++) { |
1901 |
pv1 = P1Key[i]; |
1902 |
pv2 = Tmp[pv1]; |
1903 |
indata[i]=pv2; |
1904 |
} |
1905 |
|
1906 |
des_set_key(KeyDes1, ks1); |
1907 |
des(indata, ks1, 1); |
1908 |
|
1909 |
for (i=0; i<8; i++) { |
1910 |
indata[i] ^= XorKey[i]; |
1911 |
} |
1912 |
|
1913 |
des_set_key(KeyDes2, ks1); |
1914 |
des_set_key(KeyDes2+8, ks2); |
1915 |
des(indata, ks1, 0); |
1916 |
des(indata, ks2, 1); |
1917 |
des(indata, ks1, 0); |
1918 |
|
1919 |
for (i=0; i<8; i++) { |
1920 |
indata[i] ^= XorKey[i]; |
1921 |
} |
1922 |
|
1923 |
des_set_key(KeyDes1, ks1); |
1924 |
des(indata, ks1, 0); |
1925 |
|
1926 |
for (i=0; i<8; i++) { |
1927 |
pv1 = indata[i]; |
1928 |
pv2 = P1Key[i]; |
1929 |
Tmp[pv2] = pv1; |
1930 |
} |
1931 |
for (i=0; i<8; i++) { |
1932 |
pv1 = Tmp[i]; |
1933 |
pv2 = T1Key[pv1]; |
1934 |
indata[i] = pv2; |
1935 |
} |
1936 |
return 0; |
1937 |
} |
1938 |
|
1939 |
static int8_t Via26Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) |
1940 |
{ |
1941 |
uint8_t tmpData[8], C1[8]; |
1942 |
uint8_t *pXorVector; |
1943 |
int32_t i,j; |
1944 |
|
1945 |
if (ident == 0) { |
1946 |
return 4; |
1947 |
} |
1948 |
if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { |
1949 |
return 2; |
1950 |
} |
1951 |
|
1952 |
for (i=0; i<2; i++) { |
1953 |
memcpy(tmpData, source+ i*8, 8); |
1954 |
Via26ProcessDw(tmpData, ident, desKeyIndex); |
1955 |
if (i!=0) { |
1956 |
pXorVector = source; |
1957 |
} |
1958 |
else { |
1959 |
pXorVector = &C1[0]; |
1960 |
} |
1961 |
for (j=0; j<8; j++) { |
1962 |
dw[i*8+j] = tmpData[j]^pXorVector[j]; |
1963 |
} |
1964 |
} |
1965 |
return 0; |
1966 |
} |
1967 |
|
1968 |
static void Via3Core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) |
1969 |
{ |
1970 |
uint8_t i; |
1971 |
uint32_t lR2, lR3, lR4, lR6, lR7; |
1972 |
|
1973 |
switch (ident) { |
1974 |
case 0x032820: { |
1975 |
for (i=0; i<4; i++) { |
1976 |
data[i]^= XorKey[(Off+i) & 0x07]; |
1977 |
} |
1978 |
lR2 = (data[0]^0xBD)+data[0]; |
1979 |
lR3 = (data[3]^0xEB)+data[3]; |
1980 |
lR2 = (lR2-lR3)^data[2]; |
1981 |
lR3 = ((0x39*data[1])<<2); |
1982 |
data[4] = (lR2|lR3)+data[2]; |
1983 |
lR3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0]; |
1984 |
lR2 = (data[1]^0xED)+data[1]; |
1985 |
lR7 = ((data[3]+0x29)^data[3])*lR2; |
1986 |
data[5] = lR7+lR3; |
1987 |
lR2 = ((data[2]^0x33)+data[2]) & 0x0A; |
1988 |
lR3 = (data[0]+0xAD)^data[0]; |
1989 |
lR3 = lR3+lR2; |
1990 |
lR2 = data[3]*data[3]; |
1991 |
lR7 = (lR2 | 1) + data[1]; |
1992 |
data[6] = (lR3|lR7)+data[1]; |
1993 |
lR3 = data[1] & 0x07; |
1994 |
lR2 = (lR3-data[2]) & (data[0] | lR2 |0x01); |
1995 |
data[7] = lR2+data[3]; |
1996 |
for (i=0; i<4; i++) { |
1997 |
data[i+4] = T1Key[data[i+4]]; |
1998 |
} |
1999 |
} |
2000 |
break; |
2001 |
case 0x030B00: { |
2002 |
for (i=0; i<4; i++) { |
2003 |
data[i]^= XorKey[(Off+i) & 0x07]; |
2004 |
} |
2005 |
lR6 = (data[3] + 0x6E) ^ data[3]; |
2006 |
lR6 = (lR6*(data[2] << 1)) + 0x17; |
2007 |
lR3 = (data[1] + 0x77) ^ data[1]; |
2008 |
lR4 = (data[0] + 0xD7) ^ data[0]; |
2009 |
data[4] = ((lR4 & lR3) | lR6) + data[0]; |
2010 |
lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; |
2011 |
lR6 = (data[1] + 0x1B) ^ data[1]; |
2012 |
lR4 = (lR4*lR6) ^ data[0]; |
2013 |
data[5] = (lR4 ^ (data[2] << 1)) + data[1]; |
2014 |
lR3 = (data[3] * data[3])| 0x01; |
2015 |
lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2]; |
2016 |
lR6 = data[1] ^ (data[0] + 0x4A); |
2017 |
data[6] = lR6 + lR4; |
2018 |
lR3 = (data[0] * (data[2] << 1)) | data[1]; |
2019 |
lR4 = 0xFE - data[3]; |
2020 |
lR3 = lR4 ^ lR3; |
2021 |
data[7] = lR3 + data[3]; |
2022 |
for (i=0; i<4; i++) { |
2023 |
data[4+i] = T1Key[data[4+i]]; |
2024 |
} |
2025 |
} |
2026 |
break; |
2027 |
default: |
2028 |
break; |
2029 |
} |
2030 |
} |
2031 |
|
2032 |
static void Via3Fct1(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) |
2033 |
{ |
2034 |
uint8_t t; |
2035 |
Via3Core(data, 0, ident, XorKey, T1Key); |
2036 |
|
2037 |
switch (ident) { |
2038 |
case 0x032820: { |
2039 |
t = data[4]; |
2040 |
data[4] = data[7]; |
2041 |
data[7] = t; |
2042 |
} |
2043 |
break; |
2044 |
case 0x030B00: { |
2045 |
t = data[5]; |
2046 |
data[5] = data[7]; |
2047 |
data[7] = t; |
2048 |
} |
2049 |
break; |
2050 |
default: |
2051 |
break; |
2052 |
} |
2053 |
} |
2054 |
|
2055 |
static void Via3Fct2(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) |
2056 |
{ |
2057 |
uint8_t t; |
2058 |
Via3Core(data, 4, ident, XorKey, T1Key); |
2059 |
|
2060 |
switch (ident) { |
2061 |
case 0x032820: { |
2062 |
t = data[4]; |
2063 |
data[4] = data[7]; |
2064 |
data[7] = data[5]; |
2065 |
data[5] = data[6]; |
2066 |
data[6] = t; |
2067 |
} |
2068 |
break; |
2069 |
case 0x030B00: { |
2070 |
t = data[6]; |
2071 |
data[6] = data[7]; |
2072 |
data[7] = t; |
2073 |
} |
2074 |
break; |
2075 |
default: |
2076 |
break; |
2077 |
} |
2078 |
} |
2079 |
|
2080 |
static int8_t Via3ProcessDw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex) |
2081 |
{ |
2082 |
uint8_t i; |
2083 |
uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8]; |
2084 |
uint32_t ks1[32], ks2[32]; |
2085 |
|
2086 |
if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { |
2087 |
return 2; |
2088 |
} |
2089 |
if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { |
2090 |
return 2; |
2091 |
} |
2092 |
if(!GetViaKey(KeyDes, ident, '0', desKeyIndex, 16, 1)) { |
2093 |
return 2; |
2094 |
} |
2095 |
if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { |
2096 |
return 2; |
2097 |
} |
2098 |
|
2099 |
for (i=0; i<4; i++) { |
2100 |
tmp[i] = data[i+4]; |
2101 |
} |
2102 |
Via3Fct1(tmp, ident, XorKey, T1Key); |
2103 |
for (i=0; i<4; i++) { |
2104 |
tmp[i] = data[i]^tmp[i+4]; |
2105 |
} |
2106 |
Via3Fct2(tmp, ident, XorKey, T1Key); |
2107 |
for (i=0; i<4; i++) { |
2108 |
tmp[i]^= XorKey[i+4]; |
2109 |
} |
2110 |
for (i=0; i<4; i++) { |
2111 |
data[i] = data[i+4]^tmp[i+4]; |
2112 |
data[i+4] = tmp[i]; |
2113 |
} |
2114 |
|
2115 |
des_set_key(KeyDes, ks1); |
2116 |
des_set_key(KeyDes+8, ks2); |
2117 |
|
2118 |
des(data, ks1, 0); |
2119 |
des(data, ks2, 1); |
2120 |
des(data, ks1, 0); |
2121 |
|
2122 |
for (i=0; i<4; i++) { |
2123 |
tmp[i] = data[i+4]; |
2124 |
} |
2125 |
Via3Fct2(tmp, ident, XorKey, T1Key); |
2126 |
for (i=0; i<4; i++) { |
2127 |
tmp[i] = data[i]^tmp[i+4]; |
2128 |
} |
2129 |
Via3Fct1(tmp, ident, XorKey, T1Key); |
2130 |
for (i=0; i<4; i++) { |
2131 |
tmp[i]^= XorKey[i]; |
2132 |
} |
2133 |
for (i=0; i<4; i++) { |
2134 |
data[i] = data[i+4]^tmp[i+4]; |
2135 |
data[i+4] = tmp[i]; |
2136 |
} |
2137 |
return 0; |
2138 |
} |
2139 |
|
2140 |
static void Via3FinalMix(uint8_t *dw) |
2141 |
{ |
2142 |
uint8_t tmp[4]; |
2143 |
|
2144 |
memcpy(tmp, dw, 4); |
2145 |
memcpy(dw, dw + 4, 4); |
2146 |
memcpy(dw + 4, tmp, 4); |
2147 |
|
2148 |
memcpy(tmp, dw + 8, 4); |
2149 |
memcpy(dw + 8, dw + 12, 4); |
2150 |
memcpy(dw + 12, tmp, 4); |
2151 |
} |
2152 |
|
2153 |
static int8_t Via3Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex, uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix) |
2154 |
{ |
2155 |
int8_t aesAfterCore = 0; |
2156 |
int8_t needsAES = (aesKeyIndex != 0xFF); |
2157 |
uint8_t tmpData[8], C1[8]; |
2158 |
uint8_t *pXorVector; |
2159 |
char aesKey[16]; |
2160 |
int32_t i, j; |
2161 |
|
2162 |
if(ident == 0) { |
2163 |
return 4; |
2164 |
} |
2165 |
if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { |
2166 |
return 2; |
2167 |
} |
2168 |
if(needsAES && !GetViaKey((uint8_t*)aesKey, ident, 'E', aesKeyIndex, 16, 1)) { |
2169 |
return 2; |
2170 |
} |
2171 |
if(aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15) { |
2172 |
aesAfterCore = 1; |
2173 |
} |
2174 |
|
2175 |
if(needsAES && !aesAfterCore) { |
2176 |
if(aesMode == 0x0F) { |
2177 |
hdSurEncPhase1_D2_0F_11(source); |
2178 |
hdSurEncPhase2_D2_0F_11(source); |
2179 |
} |
2180 |
else if(aesMode == 0x13) { |
2181 |
hdSurEncPhase1_D2_13_15(source); |
2182 |
} |
2183 |
struct aes_keys aes; |
2184 |
aes_set_key(&aes, aesKey); |
2185 |
aes_decrypt(&aes, source, 16); |
2186 |
if(aesMode == 0x0F) { |
2187 |
hdSurEncPhase1_D2_0F_11(source); |
2188 |
} |
2189 |
else if(aesMode == 0x13) { |
2190 |
hdSurEncPhase2_D2_13_15(source); |
2191 |
} |
2192 |
} |
2193 |
|
2194 |
for(i=0; i<2; i++) { |
2195 |
memcpy(tmpData, source+i*8, 8); |
2196 |
Via3ProcessDw(tmpData, ident, desKeyIndex); |
2197 |
if (i!=0) { |
2198 |
pXorVector = source; |
2199 |
} |
2200 |
else { |
2201 |
pXorVector = &C1[0]; |
2202 |
} |
2203 |
for (j=0; j<8; j++) { |
2204 |
dw[i*8+j] = tmpData[j]^pXorVector[j]; |
2205 |
} |
2206 |
} |
2207 |
|
2208 |
if(needsAES && aesAfterCore) { |
2209 |
if(aesMode == 0x11) { |
2210 |
hdSurEncPhase1_D2_0F_11(dw); |
2211 |
hdSurEncPhase2_D2_0F_11(dw); |
2212 |
} |
2213 |
else if(aesMode == 0x15) { |
2214 |
hdSurEncPhase1_D2_13_15(dw); |
2215 |
} |
2216 |
struct aes_keys aes; |
2217 |
aes_set_key(&aes, aesKey); |
2218 |
aes_decrypt(&aes, dw, 16); |
2219 |
if(aesMode == 0x11) { |
2220 |
hdSurEncPhase1_D2_0F_11(dw); |
2221 |
} |
2222 |
if(aesMode == 0x15) { |
2223 |
hdSurEncPhase2_D2_13_15(dw); |
2224 |
} |
2225 |
} |
2226 |
|
2227 |
if(ident == 0x030B00) { |
2228 |
if(doFinalMix) { |
2229 |
Via3FinalMix(dw); |
2230 |
} |
2231 |
if(!isValidDCW(dw)) { |
2232 |
return 6; |
2233 |
} |
2234 |
} |
2235 |
return 0; |
2236 |
} |
2237 |
|
2238 |
static int8_t ViaccessECM(uint8_t *ecm, uint8_t *dw) |
2239 |
{ |
2240 |
uint32_t currentIdent = 0; |
2241 |
uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0, desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF; |
2242 |
int8_t doFinalMix = 0, result = 1; |
2243 |
uint16_t i = 0, keySelectPos = 0, ecmLen = GetEcmLen(ecm); |
2244 |
|
2245 |
for (i=4; i+2<ecmLen; ) { |
2246 |
nanoCmd = ecm[i++]; |
2247 |
nanoLen = ecm[i++]; |
2248 |
if(i+nanoLen > ecmLen) { |
2249 |
return 1; |
2250 |
} |
2251 |
|
2252 |
switch (nanoCmd) { |
2253 |
case 0x40: |
2254 |
if (nanoLen < 0x03) { |
2255 |
break; |
2256 |
} |
2257 |
version = ecm[i]; |
2258 |
if (nanoLen == 3) { |
2259 |
currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); |
2260 |
desKeyIndex = ecm[i+2]&0x0F; |
2261 |
keySelectPos = i+3; |
2262 |
} |
2263 |
else { |
2264 |
currentIdent = (ecm[i]<<16)|(ecm[i+1]<<8)|((ecm[i+2]>>4)&0x0F); |
2265 |
desKeyIndex = ecm[i+3]; |
2266 |
keySelectPos = i+4; |
2267 |
} |
2268 |
providerKeyLen = nanoLen; |
2269 |
break; |
2270 |
case 0x90: |
2271 |
if (nanoLen < 0x03) { |
2272 |
break; |
2273 |
} |
2274 |
version = ecm[i]; |
2275 |
currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); |
2276 |
desKeyIndex = ecm[i+2]&0x0F; |
2277 |
keySelectPos = i+4; |
2278 |
if((version == 3) && (nanoLen > 3)) { |
2279 |
desKeyIndex = ecm[i+(nanoLen-4)]&0x0F; |
2280 |
} |
2281 |
providerKeyLen = nanoLen; |
2282 |
break; |
2283 |
case 0x80: |
2284 |
nanoLen = 0; |
2285 |
break; |
2286 |
case 0xD2: |
2287 |
if (nanoLen < 0x02) { |
2288 |
break; |
2289 |
} |
2290 |
aesMode = ecm[i]; |
2291 |
aesKeyIndex = ecm[i+1]; |
2292 |
break; |
2293 |
case 0xDD: |
2294 |
nanoLen = 0; |
2295 |
break; |
2296 |
case 0xEA: |
2297 |
if (nanoLen < 0x10) { |
2298 |
break; |
2299 |
} |
2300 |
|
2301 |
if (version < 2) { |
2302 |
return Via1Decrypt(ecm, dw, currentIdent, desKeyIndex); |
2303 |
} |
2304 |
else if (version == 2) { |
2305 |
return Via26Decrypt(ecm + i, dw, currentIdent, desKeyIndex); |
2306 |
} |
2307 |
else if (version == 3) { |
2308 |
doFinalMix = 0; |
2309 |
if (currentIdent == 0x030B00 && providerKeyLen>3) { |
2310 |
if(keySelectPos+2 >= ecmLen) { |
2311 |
break; |
2312 |
} |
2313 |
if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos+1] == 0x67 && (ecm[keySelectPos+2] == 0x00 || ecm[keySelectPos+2] == 0x01)) { |
2314 |
if(ecm[keySelectPos+2] == 0x01) { |
2315 |
doFinalMix = 1; |
2316 |
} |
2317 |
} |
2318 |
else { |
2319 |
break; |
2320 |
} |
2321 |
} |
2322 |
return Via3Decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix); |
2323 |
} |
2324 |
break; |
2325 |
default: |
2326 |
break; |
2327 |
} |
2328 |
i += nanoLen; |
2329 |
} |
2330 |
return result; |
2331 |
} |
2332 |
|
2333 |
// Nagra EMU |
2334 |
static int8_t GetNagraKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey) |
2335 |
{ |
2336 |
char keyStr[EMU_MAX_CHAR_KEYNAME]; |
2337 |
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); |
2338 |
if(FindKey('N', ident, 0, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) { |
2339 |
return 1; |
2340 |
} |
2341 |
|
2342 |
return 0; |
2343 |
} |
2344 |
|
2345 |
static int8_t Nagra2Signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len) |
2346 |
{ |
2347 |
uint8_t buff[16]; |
2348 |
uint8_t iv[8]; |
2349 |
int32_t i,j; |
2350 |
|
2351 |
memcpy(buff,vkey,sizeof(buff)); |
2352 |
for(i=0; i+7<len; i+=8) { |
2353 |
IDEA_KEY_SCHEDULE ek; |
2354 |
idea_set_encrypt_key(buff, &ek); |
2355 |
memcpy(buff,buff+8,8); |
2356 |
memset(iv,0,sizeof(iv)); |
2357 |
idea_cbc_encrypt(msg+i,buff+8,8,&ek,iv,IDEA_ENCRYPT); |
2358 |
for(j=7; j>=0; j--) { |
2359 |
buff[j+8]^=msg[i+j]; |
2360 |
} |
2361 |
} |
2362 |
buff[8]&=0x7F; |
2363 |
return (memcmp(sig, buff+8, 8) == 0); |
2364 |
} |
2365 |
|
2366 |
static int8_t DecryptNagra2ECM(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, const uint8_t *vkey, uint8_t *keyM) |
2367 |
{ |
2368 |
BIGNUM *exp, *mod; |
2369 |
uint8_t iv[8]; |
2370 |
int32_t i = 0, sign = in[0] & 0x80; |
2371 |
uint8_t binExp = 3; |
2372 |
int8_t result = 1; |
2373 |
|
2374 |
exp = BN_new(); |
2375 |
mod = BN_new(); |
2376 |
BN_bin2bn(&binExp, 1, exp); |
2377 |
BN_bin2bn(keyM, 64, mod); |
2378 |
|
2379 |
if(EmuRSA(out,in+1,64,exp,mod,1)<=0) { |
2380 |
BN_free(exp); |
2381 |
BN_free(mod); |
2382 |
return 0; |
2383 |
} |
2384 |
out[63]|=sign; |
2385 |
if(len>64) { |
2386 |
memcpy(out+64,in+65,len-64); |
2387 |
} |
2388 |
|
2389 |
memset(iv,0,sizeof(iv)); |
2390 |
if(in[0]&0x04) { |
2391 |
uint8_t key1[8], key2[8]; |
2392 |
ReverseMemInOut(key1,&key[0],8); |
2393 |
ReverseMemInOut(key2,&key[8],8); |
2394 |
|
2395 |
for(i=7; i>=0; i--) { |
2396 |
ReverseMem(out+8*i,8); |
2397 |
} |
2398 |
des_ede2_cbc_decrypt(out, iv, key1, key2, len); |
2399 |
for(i=7; i>=0; i--) { |
2400 |
ReverseMem(out+8*i,8); |
2401 |
} |
2402 |
} |
2403 |
else { |
2404 |
IDEA_KEY_SCHEDULE ek; |
2405 |
idea_set_encrypt_key(key, &ek); |
2406 |
idea_cbc_encrypt(out, out, len&~7, &ek, iv, IDEA_DECRYPT); |
2407 |
} |
2408 |
|
2409 |
ReverseMem(out,64); |
2410 |
if(result && EmuRSA(out,out,64,exp,mod,0)<=0) { |
2411 |
result = 0; |
2412 |
} |
2413 |
if(result && vkey && !Nagra2Signature(vkey,out,out+8,len-8)) { |
2414 |
result = 0; |
2415 |
} |
2416 |
|
2417 |
BN_free(exp); |
2418 |
BN_free(mod); |
2419 |
return result; |
2420 |
} |
2421 |
|
2422 |
static int8_t Nagra2ECM(uint8_t *ecm, uint8_t *dw) |
2423 |
{ |
2424 |
uint32_t ident, identMask, tmp1, tmp2, tmp3; |
2425 |
uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0; |
2426 |
int8_t useVerifyKey = 0; |
2427 |
int32_t l=0, s; |
2428 |
uint16_t i = 0, ecmLen = GetEcmLen(ecm); |
2429 |
|
2430 |
if(ecmLen < 8) { |
2431 |
return 1; |
2432 |
} |
2433 |
cmdLen = ecm[4] - 5; |
2434 |
ident = (ecm[5] << 8) + ecm[6]; |
2435 |
ideaKeyNr = (ecm[7]&0x10)>>4; |
2436 |
if(ideaKeyNr) { |
2437 |
ideaKeyNr = 1; |
2438 |
} |
2439 |
if(ident == 1283 || ident == 1285 || ident == 1297) { |
2440 |
ident = 1281; |
2441 |
} |
2442 |
if(cmdLen <= 63 || ecmLen < cmdLen + 10) { |
2443 |
return 1; |
2444 |
} |
2445 |
|
2446 |
if(!GetNagraKey(ideaKey, ident, '0', ideaKeyNr, 1)) { |
2447 |
return 2; |
2448 |
} |
2449 |
if(GetNagraKey(vKey, ident, 'V', 0, 0)) { |
2450 |
useVerifyKey = 1; |
2451 |
} |
2452 |
if(!GetNagraKey(m1Key, ident, 'M', 1, 1)) { |
2453 |
return 2; |
2454 |
} |
2455 |
ReverseMem(m1Key, 64); |
2456 |
|
2457 |
dec = (uint8_t*)malloc(sizeof(uint8_t)*cmdLen); |
2458 |
if(dec == NULL) { |
2459 |
return 7; |
2460 |
} |
2461 |
if(!DecryptNagra2ECM(ecm+9, dec, ideaKey, cmdLen, useVerifyKey?vKey:0, m1Key)) { |
2462 |
free(dec); |
2463 |
return 1; |
2464 |
} |
2465 |
|
2466 |
for(i=(dec[14]&0x10)?16:20; i<cmdLen && l!=3; ) { |
2467 |
switch(dec[i]) { |
2468 |
case 0x10: |
2469 |
case 0x11: |
2470 |
if(i+10 < cmdLen && dec[i+1] == 0x09) { |
2471 |
s = (~dec[i])&1; |
2472 |
mecmAlgo = dec[i+2]&0x60; |
2473 |
memcpy(dw+(s<<3), &dec[i+3], 8); |
2474 |
i+=11; |
2475 |
l|=(s+1); |
2476 |
} |
2477 |
else { |
2478 |
i++; |
2479 |
} |
2480 |
break; |
2481 |
case 0x00: |
2482 |
i+=2; |
2483 |
break; |
2484 |
case 0x30: |
2485 |
case 0x31: |
2486 |
case 0x32: |
2487 |
case 0x33: |
2488 |
case 0x34: |
2489 |
case 0x35: |
2490 |
case 0x36: |
2491 |
case 0xB0: |
2492 |
if(i+1 < cmdLen) { |
2493 |
i+=dec[i+1]+2; |
2494 |
} |
2495 |
else { |
2496 |
i++; |
2497 |
} |
2498 |
break; |
2499 |
default: |
2500 |
i++; |
2501 |
continue; |
2502 |
} |
2503 |
} |
2504 |
|
2505 |
free(dec); |
2506 |
|
2507 |
if(l!=3) { |
2508 |
return 1; |
2509 |
} |
2510 |
if(mecmAlgo>0) { |
2511 |
return 1; |
2512 |
} |
2513 |
|
2514 |
identMask = ident & 0xFF00; |
2515 |
if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) { |
2516 |
memcpy(&tmp1, dw, 4); |
2517 |
memcpy(&tmp2, dw + 4, 4); |
2518 |
memcpy(&tmp3, dw + 12, 4); |
2519 |
memcpy(dw, dw + 8, 4); |
2520 |
memcpy(dw + 4, &tmp3, 4); |
2521 |
memcpy(dw + 8, &tmp1, 4); |
2522 |
memcpy(dw + 12, &tmp2, 4); |
2523 |
} |
2524 |
return 0; |
2525 |
} |
2526 |
|
2527 |
// Irdeto EMU |
2528 |
static int8_t GetIrdetoKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey, uint32_t *keyRef) |
2529 |
{ |
2530 |
char keyStr[EMU_MAX_CHAR_KEYNAME]; |
2531 |
|
2532 |
if(*keyRef > 0xFF) |
2533 |
{ |
2534 |
return 0; |
2535 |
} |
2536 |
|
2537 |
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); |
2538 |
if(FindKey('I', ident, 0, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) { |
2539 |
(*keyRef)++; |
2540 |
return 1; |
2541 |
} |
2542 |
|
2543 |
return 0; |
2544 |
} |
2545 |
|
2546 |
static void Irdeto2Encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) |
2547 |
{ |
2548 |
const uint8_t *tmp = seed;; |
2549 |
int32_t i; |
2550 |
uint32_t ks1[32], ks2[32]; |
2551 |
|
2552 |
des_set_key(key, ks1); |
2553 |
des_set_key(key+8, ks2); |
2554 |
|
2555 |
len&=~7; |
2556 |
|
2557 |
for(i=0; i+7<len; i+=8) { |
2558 |
xxor(&data[i],8,&data[i],tmp); |
2559 |
tmp=&data[i]; |
2560 |
des(&data[i], ks1, 1); |
2561 |
des(&data[i], ks2, 0); |
2562 |
des(&data[i], ks1, 1); |
2563 |
} |
2564 |
} |
2565 |
|
2566 |
static void Irdeto2Decrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) |
2567 |
{ |
2568 |
uint8_t buf[2][8]; |
2569 |
int32_t i, n=0; |
2570 |
uint32_t ks1[32], ks2[32]; |
2571 |
|
2572 |
des_set_key(key, ks1); |
2573 |
des_set_key(key+8, ks2); |
2574 |
|
2575 |
len&=~7; |
2576 |
|
2577 |
memcpy(buf[n],seed,8); |
2578 |
for(i=0; i+7<len; i+=8,data+=8,n^=1) { |
2579 |
memcpy(buf[1-n],data,8); |
2580 |
des(data, ks1, 0); |
2581 |
des(data, ks2, 1); |
2582 |
des(data, ks1, 0); |
2583 |
xxor(data,8,data,buf[n]); |
2584 |
} |
2585 |
} |
2586 |
|
2587 |
static int8_t Irdeto2CalculateHash(const uint8_t *key, const uint8_t *iv, const uint8_t *data, int32_t len) |
2588 |
{ |
2589 |
uint8_t cbuff[8]; |
2590 |
int32_t l, y; |
2591 |
uint32_t ks1[32], ks2[32]; |
2592 |
|
2593 |
des_set_key(key, ks1); |
2594 |
des_set_key(key+8, ks2); |
2595 |
|
2596 |
memset(cbuff,0,sizeof(cbuff)); |
2597 |
len-=8; |
2598 |
|
2599 |
for(y=0; y<len; y+=8) { |
2600 |
if(y<len-8) { |
2601 |
xxor(cbuff,8,cbuff,&data[y]); |
2602 |
} |
2603 |
else { |
2604 |
l=len-y; |
2605 |
xxor(cbuff,l,cbuff,&data[y]); |
2606 |
xxor(cbuff+l,8-l,cbuff+l,iv+8); |
2607 |
} |
2608 |
|
2609 |
des(cbuff, ks1, 1); |
2610 |
des(cbuff, ks2, 0); |
2611 |
des(cbuff, ks1, 1); |
2612 |
} |
2613 |
|
2614 |
return memcmp(cbuff, &data[len], 8) == 0; |
2615 |
} |
2616 |
|
2617 |
static int8_t Irdeto2ECM(uint16_t caid, uint8_t *oecm, uint8_t *dw) |
2618 |
{ |
2619 |
uint8_t keyNr=0, length, end, key[16], okeySeed[16], keySeed[16], keyIV[16], tmp[16]; |
2620 |
uint32_t i, l, ident; |
2621 |
uint32_t key0Ref, keySeedRef, keyIVRef; |
2622 |
uint8_t ecmCopy[EMU_MAX_ECM_LEN], *ecm = oecm; |
2623 |
uint16_t ecmLen = GetEcmLen(ecm); |
2624 |
|
2625 |
if(ecmLen < 12) { |
2626 |
return 1; |
2627 |
} |
2628 |
|
2629 |
length = ecm[11]; |
2630 |
keyNr = ecm[9]; |
2631 |
ident = ecm[8] | caid << 8; |
2632 |
|
2633 |
if(ecmLen < length+12) { |
2634 |
return 1; |
2635 |
} |
2636 |
|
2637 |
key0Ref = 0; |
2638 |
while(GetIrdetoKey(key, ident, '0', keyNr, 1, &key0Ref)) { |
2639 |
keySeedRef = 0; |
2640 |
while(GetIrdetoKey(okeySeed, ident, 'M', 1, 1, &keySeedRef)) { |
2641 |
keyIVRef = 0; |
2642 |
while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { |
2643 |
|
2644 |
memcpy(keySeed, okeySeed, 16); |
2645 |
memcpy(ecmCopy, oecm, ecmLen); |
2646 |
ecm = ecmCopy; |
2647 |
|
2648 |
memset(tmp, 0, 16); |
2649 |
Irdeto2Encrypt(keySeed, tmp, key, 16); |
2650 |
ecm+=12; |
2651 |
Irdeto2Decrypt(ecm, keyIV, keySeed, length); |
2652 |
i=(ecm[0]&7)+1; |
2653 |
end = length-8 < 0 ? 0 : length-8; |
2654 |
|
2655 |
while(i<end) { |
2656 |
l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1; |
2657 |
switch(ecm[i]) { |
2658 |
case 0x10: |
2659 |
case 0x50: |
2660 |
if(l == 0x13 && i <= length-8-l) { |
2661 |
Irdeto2Decrypt(&ecm[i+3], keyIV, key, 16); |
2662 |
} |
2663 |
break; |
2664 |
case 0x78: |
2665 |
if(l == 0x14 && i <= length-8-l) { |
2666 |
Irdeto2Decrypt(&ecm[i+4], keyIV, key, 16); |
2667 |
} |
2668 |
break; |
2669 |
} |
2670 |
i+=l; |
2671 |
} |
2672 |
|
2673 |
i=(ecm[0]&7)+1; |
2674 |
if(Irdeto2CalculateHash(keySeed, keyIV, ecm-6, length+6)) { |
2675 |
while(i<end) { |
2676 |
l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1; |
2677 |
switch(ecm[i]) { |
2678 |
case 0x78: |
2679 |
if(l == 0x14 && i <= length-8-l) { |
2680 |
memcpy(dw, &ecm[i+4], 16); |
2681 |
return 0; |
2682 |
} |
2683 |
} |
2684 |
i+=l; |
2685 |
} |
2686 |
} |
2687 |
} |
2688 |
if(keyIVRef == 0) { |
2689 |
return 2; |
2690 |
} |
2691 |
} |
2692 |
if(keySeedRef == 0) { |
2693 |
return 2; |
2694 |
} |
2695 |
} |
2696 |
if(key0Ref == 0) { |
2697 |
return 2; |
2698 |
} |
2699 |
|
2700 |
return 1; |
2701 |
} |
2702 |
|
2703 |
// BISS EMU |
2704 |
static void BissUnifyOrbitals(uint32_t *namespace) |
2705 |
{ |
2706 |
// Unify orbitals to produce same namespace among users |
2707 |
// Set positions according to http://satellites-xml.org |
2708 |
|
2709 |
uint16_t pos = (*namespace & 0x0FFF0000) >> 16; |
2710 |
|
2711 |
switch (pos) |
2712 |
{ |
2713 |
case 29: // Rascom QAF 1R |
2714 |
case 31: // Eutelsat 3B |
2715 |
{ |
2716 |
pos = 30; |
2717 |
break; |
2718 |
} |
2719 |
|
2720 |
case 49: |
2721 |
case 50: // SES 5 |
2722 |
{ |
2723 |
pos = 48; // Astra 4A |
2724 |
break; |
2725 |
} |
2726 |
|
2727 |
case 215: |
2728 |
{ |
2729 |
pos = 216; // Eutelsat 21B |
2730 |
break; |
2731 |
} |
2732 |
|
2733 |
case 285: // Astra 2E |
2734 |
{ |
2735 |
pos = 282; // Astra 2F/2G |
2736 |
break; |
2737 |
} |
2738 |
|
2739 |
case 328: // Intelsat 28 |
2740 |
case 329: |
2741 |
case 331: // Eutelsat 33C |
2742 |
{ |
2743 |
pos = 330; |
2744 |
break; |
2745 |
} |
2746 |
|
2747 |
case 359: // Eutelsat 36B |
2748 |
case 361: // Express AMU1 |
2749 |
{ |
2750 |
pos = 360; |
2751 |
break; |
2752 |
} |
2753 |
|
2754 |
case 451: // Intelsat 904 |
2755 |
{ |
2756 |
pos = 450; // Intelsat 12 |
2757 |
break; |
2758 |
} |
2759 |
|
2760 |
case 550: |
2761 |
case 551: // G-Sat 8/16 |
2762 |
{ |
2763 |
pos = 549; // Yamal 402 |
2764 |
break; |
2765 |
} |
2766 |
|
2767 |
case 748: |
2768 |
case 749: // ABS 2A |
2769 |
{ |
2770 |
pos = 750; |
2771 |
break; |
2772 |
} |
2773 |
|
2774 |
case 848: // Horizons 2 |
2775 |
case 852: // Intelsat 15 |
2776 |
{ |
2777 |
pos = 850; |
2778 |
break; |
2779 |
} |
2780 |
|
2781 |
case 914: // Mesasat 3a |
2782 |
{ |
2783 |
pos = 915; // Mesasat 3/3b |
2784 |
break; |
2785 |
} |
2786 |
|
2787 |
case 934: // G-Sat 17 |
2788 |
case 936: // Insat 4B |
2789 |
{ |
2790 |
pos = 935; // G-Sat 15 |
2791 |
break; |
2792 |
} |
2793 |
|
2794 |
case 3600 - 911: // Nimiq 6 |
2795 |
{ |
2796 |
pos = 3600 - 910; // Galaxy 17 |
2797 |
} |
2798 |
|
2799 |
case 3600 - 870: // SES 2 |
2800 |
case 3600 - 872: // TKSat 1 |
2801 |
{ |
2802 |
pos = 3600 - 871; |
2803 |
break; |
2804 |
} |
2805 |
|
2806 |
case 3600 - 432: // Sky Brasil 1 |
2807 |
case 3600 - 430: // Intelsat 11 |
2808 |
{ |
2809 |
pos = 3600 - 431; |
2810 |
break; |
2811 |
} |
2812 |
|
2813 |
case 3600 - 376: // Telstar 11N |
2814 |
case 3600 - 374: // NSS 10 |
2815 |
{ |
2816 |
pos = 3600 - 375; |
2817 |
break; |
2818 |
} |
2819 |
|
2820 |
case 3600 - 359: // Hispasat 36W-1 |
2821 |
{ |
2822 |
pos = 3600 - 360; // Eutelsat 36 West A |
2823 |
break; |
2824 |
} |
2825 |
|
2826 |
case 3600 - 81: // Eutelsat 8 West B |
2827 |
{ |
2828 |
pos = 3600 - 80; |
2829 |
break; |
2830 |
} |
2831 |
|
2832 |
case 3600 - 73: // Eutelsat 7 West A |
2833 |
case 3600 - 72: |
2834 |
case 3600 - 71: |
2835 |
{ |
2836 |
pos = 3600 - 70; // Nilesat 201 |
2837 |
break; |
2838 |
} |
2839 |
|
2840 |
case 3600 - 10: // Intelsat 10-02 |
2841 |
case 3600 - 9: // Thor 6 |
2842 |
case 3600 - 7: // Thor 7 |
2843 |
case 3600 - 6: // Thor 7 |
2844 |
{ |
2845 |
pos = 3600 - 8; // Thor 5 |
2846 |
break; |
2847 |
} |
2848 |
} |
2849 |
|
2850 |
*namespace = (*namespace & 0xF000FFFF) | (pos << 16); |
2851 |
} |
2852 |
|
2853 |
static void BissAnnotate(char *buf, uint8_t len, const uint8_t *ecm, uint16_t ecmLen, uint32_t hash, int8_t isNamespaceHash, int8_t datecoded) |
2854 |
{ |
2855 |
// Extract useful information to append to the "Example key ..." message. |
2856 |
// |
2857 |
// For feeds, the orbital position & frequency are usually embedded in the namespace. |
2858 |
// See https://github.com/openatv/enigma2/blob/master/lib/dvb/frontend.cpp#L496 |
2859 |
// hash = (sat.orbital_position << 16); |
2860 |
// hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15); |
2861 |
// |
2862 |
// If the onid & tsid appear to be a unique DVB identifier, enigma2 strips the frequency |
2863 |
// from our namespace. See https://github.com/openatv/enigma2/blob/master/lib/dvb/scan.cpp#L59 |
2864 |
// In that case, our annotation contains the onid:tsid:sid triplet in lieu of frequency. |
2865 |
// |
2866 |
// For the universal case, we print the number of elementary stream pids & pmtpid. |
2867 |
// The sid and current time are included for all. Examples: |
2868 |
// |
2869 |
// F 1A2B3C4D 00000000 XXXXXXXXXXXXXXXX ; 110.5W 12345H sid:0001 added: 2017-10-17 @ 13:14:15 // namespace |
2870 |
// F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; 33.5E ABCD:9876:1234 added: 2017-10-17 @ 13:14:15 // stripped namespace |
2871 |
// F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; av:5 pmt:0134 sid:0001 added: 2017-10-17 @ 13:14:15 // universal |
2872 |
|
2873 |
uint8_t pidcount; |
2874 |
uint16_t frequency, degrees, pmtpid, srvid, tsid, onid; |
2875 |
uint32_t ens; |
2876 |
char compass, polarisation, timeStr1[9], timeStr2[19]; |
2877 |
|
2878 |
if (datecoded) |
2879 |
{ |
2880 |
Date2Str(timeStr1, sizeof(timeStr1), 4, 3); |
2881 |
} |
2882 |
else |
2883 |
{ |
2884 |
snprintf(timeStr1, sizeof(timeStr1), "00000000"); |
2885 |
} |
2886 |
|
2887 |
Date2Str(timeStr2, sizeof(timeStr2), 0, 2); |
2888 |
|
2889 |
if (isNamespaceHash) // Namespace hash |
2890 |
{ |
2891 |
ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes of the ecm |
2892 |
degrees = (ens >> 16) & 0x0FFF; // Remove not-a-pid flag |
2893 |
|
2894 |
if (degrees > 1800) |
2895 |
{ |
2896 |
degrees = 3600 - degrees; |
2897 |
compass = 'W'; |
2898 |
} |
2899 |
else |
2900 |
{ |
2901 |
compass = 'E'; |
2902 |
} |
2903 |
|
2904 |
if (0 == (ens & 0xFFFF)) // Stripped namespace hash |
2905 |
{ |
2906 |
srvid = b2i(2, ecm + 3); |
2907 |
tsid = b2i(2, ecm + ecmLen - 8); |
2908 |
onid = b2i(2, ecm + ecmLen - 6); |
2909 |
// Printing degree sign "\u00B0" requires c99 standard |
2910 |
snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %04X:%04X:%04X added: %s", |
2911 |
hash, timeStr1, degrees / 10.0, compass, onid, tsid, srvid, timeStr2); |
2912 |
} |
2913 |
else // Full namespace hash |
2914 |
{ |
2915 |
srvid = b2i(2, ecm + 3); |
2916 |
frequency = ens & 0x7FFF; // Remove polarity bit |
2917 |
polarisation = ens & 0x8000 ? 'V' : 'H'; |
2918 |
// Printing degree sign "\u00B0" requires c99 standard |
2919 |
snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %5d%c sid:%04X added: %s", |
2920 |
hash, timeStr1, degrees / 10.0, compass, frequency, polarisation, srvid, timeStr2); |
2921 |
} |
2922 |
} |
2923 |
else // Universal hash |
2924 |
{ |
2925 |
srvid = b2i(2, ecm + 3); |
2926 |
pmtpid = b2i(2, ecm + 5); |
2927 |
pidcount = (ecmLen - 15) / 2; // video + audio pids count |
2928 |
snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; av:%d pmt:%04X sid:%04X added: %s", |
2929 |
hash, timeStr1, pidcount, pmtpid, srvid, timeStr2); |
2930 |
} |
2931 |
} |
2932 |
|
2933 |
static int8_t BissIsCommonHash(uint32_t hash) |
2934 |
{ |
2935 |
// Check universal hash against a number of commnon universal |
2936 |
// hashes in order to warn users about potential key clashes |
2937 |
|
2938 |
switch (hash) |
2939 |
{ |
2940 |
case 0xBAFCD9FD: // 0001 0020 0200 1010 1020 (most common hash) |
2941 |
return 1; |
2942 |
case 0xA6A4FBD4: // 0001 0800 0200 1010 1020 |
2943 |
return 1; |
2944 |
case 0xEFAB7A4D: // 0001 0800 1010 1020 0200 |
2945 |
return 1; |
2946 |
case 0x83FA15D1: // 0001 0020 0134 0100 0101 |
2947 |
return 1; |
2948 |
case 0x58934C38: // 0001 0800 1010 1020 1030 0200 |
2949 |
return 1; |
2950 |
case 0x2C3CEC17: // 0001 0020 0134 0100 |
2951 |
return 1; |
2952 |
case 0x73DF7F7E: // 0001 0020 0200 1010 1020 1030 |
2953 |
return 1; |
2954 |
case 0xAFA85BC8: // 0001 0020 0021 0022 0023 |
2955 |
return 1; |
2956 |
case 0x8C51F31D: // 0001 0800 0200 1010 1020 1030 1040 |
2957 |
return 1; |
2958 |
case 0xE2F9BD29: // 0001 0800 0200 1010 1020 1030 |
2959 |
return 1; |
2960 |
case 0xB9EBE0FF: // 0001 0100 0200 1010 1020 (less common hash) |
2961 |
return 1; |
2962 |
default: |
2963 |
return 0; |
2964 |
} |
2965 |
} |
2966 |
|
2967 |
static int8_t BissIsValidNamespace(uint32_t namespace) |
2968 |
{ |
2969 |
// Note to developers: |
2970 |
// If we ever have a satellite at 0.0E, edit to allow stripped namespace |
2971 |
// '0xA0000000' with an additional test on tsid and onid being != 0 |
2972 |
|
2973 |
uint16_t orbital, frequency; |
2974 |
|
2975 |
orbital = (namespace >> 16) & 0x0FFF; |
2976 |
frequency = namespace & 0x7FFF; |
2977 |
|
2978 |
if ((namespace & 0xA0000000) != 0xA0000000) return 0; // Value isn't flagged as namespace |
2979 |
if (namespace == 0xA0000000) return 0; // Empty namespace |
2980 |
if (orbital > 3599) return 0; // Allow only DVB-S |
2981 |
if (frequency == 0) return 1; // Stripped namespace |
2982 |
if (frequency >= 3400 && frequency <= 4200) return 1; // Super extended C band |
2983 |
if (frequency >= 10700 && frequency <= 12750) return 1; // Ku band Europe |
2984 |
|
2985 |
return 0; |
2986 |
} |
2987 |
|
2988 |
static int8_t BissGetKey(uint32_t provider, uint8_t *key, int8_t dateCoded, int8_t printMsg) |
2989 |
{ |
2990 |
// If date-coded keys are enabled in the webif, this function evaluates the expiration date |
2991 |
// of the keys found. Expired keys are not sent to BissECM(). If date-coded keys are disabled, |
2992 |
// then all keys found are sent without any evaluation. It takes the "provider" as input and |
2993 |
// outputs the "key". Returns 0 (Key not found, or expired) or 1 (Key found). |
2994 |
|
2995 |
// printMsg: 0 => No message |
2996 |
// printMsg: 1 => Print message only if key is found |
2997 |
// printMsg: 2 => Always print message, regardless if key is found or not |
2998 |
|
2999 |
char keyExpDate[9] = "00000000"; |
3000 |
|
3001 |
if (FindKey('F', provider, 0, keyExpDate, key, 8, 0, 0, 0, NULL)) // Key found |
3002 |
{ |
3003 |
if (dateCoded) // Date-coded keys are enabled, evaluate expiration date |
3004 |
{ |
3005 |
char currentDate[9]; |
3006 |
Date2Str(currentDate, sizeof(currentDate), 0, 3); |
3007 |
|
3008 |
if (strncmp("00000000", keyExpDate, 9) == 0 || strncmp(currentDate, keyExpDate, 9) < 0) // Evergreen or not expired |
3009 |
{ |
3010 |
if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); |
3011 |
return 1; |
3012 |
} |
3013 |
else // Key expired |
3014 |
{ |
3015 |
key = NULL; // Make sure we don't send any expired key |
3016 |
if (printMsg == 2) cs_log("Key expired: F %08X %s", provider, keyExpDate); |
3017 |
return 0; |
3018 |
} |
3019 |
} |
3020 |
else // Date-coded keys are disabled, don't evaluate expiration date |
3021 |
{ |
3022 |
if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); |
3023 |
return 1; |
3024 |
} |
3025 |
} |
3026 |
else // Key not found |
3027 |
{ |
3028 |
if (printMsg == 2) cs_log("Key not found: F %08X", provider); |
3029 |
return 0; |
3030 |
} |
3031 |
} |
3032 |
|
3033 |
static int8_t BissECM(struct s_reader *rdr, const uint8_t *ecm, int16_t ecmDataLen, uint8_t *dw, uint16_t srvid, uint16_t ecmpid) |
3034 |
{ |
3035 |
// Oscam's fake ecm consists of [sid] [pmtpid] [pid1] [pid2] ... [pidx] [tsid] [onid] [namespace] |
3036 |
// |
3037 |
// On enigma boxes tsid, onid and namespace should be non zero, while on non-enigma |
3038 |
// boxes they are usually all zero. |
3039 |
// The emulator creates a unique channel hash using srvid and enigma namespace or |
3040 |
// srvid, tsid, onid and namespace (in case of namespace without frequency) and |
3041 |
// another weaker (not unique) hash based on every pid of the channel. This universal |
3042 |
// hash should be available on all types of stbs (enigma and non-enigma). |
3043 |
|
3044 |
// Flags inside [namespace] |
3045 |
// |
3046 |
// emu r748- : no namespace, no flag |
3047 |
// emu r749 : 0x80000000 (full namespase), 0xC0000000 (stripped namespace, injected with tsid^onid^ecmpid^0x1FFF) |
3048 |
// emu r752+ : 0xA0000000 (pure namespace, either full, stripped, or null) |
3049 |
|
3050 |
// Key searches are made in order: |
3051 |
// Highest priority / tightest test first |
3052 |
// Lowest priority / loosest test last |
3053 |
// |
3054 |
// 1st: namespace hash (only on enigma boxes) |
3055 |
// 2nd: universal hash (all box types with emu r752+) |
3056 |
// 3rd: valid tsid, onid combination |
3057 |
// 4th: faulty ecmpid (other than 0x1FFF) |
3058 |
// 5th: reverse order pid (audio, video, pmt pids) |
3059 |
// 6th: standard BISS ecmpid (0x1FFF) |
3060 |
// 7th: default "All Feeds" key |
3061 |
|
3062 |
// If enabled in the webif, a date based key search can be performed. If the expiration |
3063 |
// date has passed, the key is not sent from BissGetKey(). This search method is only |
3064 |
// used in the namespace hash, universal hash and the default "All Feeds" key. |
3065 |
|
3066 |
uint8_t ecmCopy[EMU_MAX_ECM_LEN]; |
3067 |
uint16_t ecmLen = 0, pid = 0; |
3068 |
uint32_t i, ens = 0, hash = 0; |
3069 |
char tmpBuffer1[17], tmpBuffer2[90] = "0", tmpBuffer3[90] = "0"; |
3070 |
|
3071 |
if (ecmDataLen >= 3) |
3072 |
{ |
3073 |
ecmLen = GetEcmLen(ecm); |
3074 |
} |
3075 |
|
3076 |
// First try using the unique namespace hash (enigma only) |
3077 |
if (ecmLen >= 13 && ecmLen <= ecmDataLen) // ecmLen >= 13, allow patching the ecmLen for r749 ecms |
3078 |
{ |
3079 |
memcpy(ecmCopy, ecm, ecmLen); |
3080 |
ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes |
3081 |
|
3082 |
if (BissIsValidNamespace(ens)) // An r752+ extended ecm with valid namespace |
3083 |
{ |
3084 |
BissUnifyOrbitals(&ens); |
3085 |
i2b_buf(4, ens, ecmCopy + ecmLen - 4); |
3086 |
|
3087 |
for (i = 0; i < 5; i++) // Find key matching hash made with frequency modified to: f+0, then f-1, f+1, f-2, lastly f+2 |
3088 |
{ |
3089 |
ecmCopy[ecmLen - 1] = (i & 1) ? ecmCopy[ecmLen - 1] - i : ecmCopy[ecmLen - 1] + i; // frequency +/- 1, 2 MHz |
3090 |
|
3091 |
if (0 != (ens & 0xFFFF)) // Full namespace - Calculate hash with srvid and namespace only |
3092 |
{ |
3093 |
i2b_buf(2, srvid, ecmCopy + ecmLen - 6); // Put [srvid] right before [namespace] |
3094 |
hash = crc32(0x2600, ecmCopy + ecmLen - 6, 6); |
3095 |
} |
3096 |
else // Namespace without frequency - Calculate hash with srvid, tsid, onid and namespace |
3097 |
{ |
3098 |
i2b_buf(2, srvid, ecmCopy + ecmLen - 10); // Put [srvid] right before [tsid] [onid] [namespace] sequence |
3099 |
hash = crc32(0x2600, ecmCopy + ecmLen - 10, 10); |
3100 |
} |
3101 |
|
3102 |
if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, i == 0 ? 2 : 1)) // Do not print "key not found" for frequency off by 1, 2 |
3103 |
{ |
3104 |
memcpy(dw + 8, dw, 8); |
3105 |
return 0; |
3106 |
} |
3107 |
|
3108 |
if (i == 0) // No key found matching our hash: create example SoftCam.Key BISS line for the live log |
3109 |
{ |
3110 |
BissAnnotate(tmpBuffer2, sizeof(tmpBuffer2), ecmCopy, ecmLen, hash, 1, rdr->emu_datecodedenabled); |
3111 |
} |
3112 |
|
3113 |
if (0 == (ens & 0xFFFF)) // Namespace without frequency - Do not iterate |
3114 |
{ |
3115 |
break; |
3116 |
} |
3117 |
} |
3118 |
} |
3119 |
|
3120 |
if ((ens & 0xA0000000) == 0x80000000) // r749 ecms only (exclude r752+ ecms) |
3121 |
{ |
3122 |
cs_log("Hey! Network buddy, you need to upgrade your OSCam-Emu"); |
3123 |
ecmCopy[ecmLen] = 0xA0; // Patch ecm to look like r752+ |
3124 |
ecmLen += 4; |
3125 |
ecmDataLen += 4; |
3126 |
} |
3127 |
} |
3128 |
|
3129 |
// Try using the universal channel hash (namespace not available) |
3130 |
if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms |
3131 |
{ |
3132 |
ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes |
3133 |
|
3134 |
if ((ens & 0xE0000000) == 0xA0000000) // We have an r752+ style ecm which contains pmtpid |
3135 |
{ |
3136 |
memcpy(ecmCopy, ecm, ecmLen - 8); // Make a new ecmCopy from the original ecm as the old ecmCopy may be altered in namespace hash (skip [tsid] [onid] [namespace]) |
3137 |
hash = crc32(0x2600, ecmCopy + 3, ecmLen - 3 - 8); // ecmCopy doesn't have [tsid] [onid] [namespace] part |
3138 |
|
3139 |
if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, 2)) // Key found |
3140 |
{ |
3141 |
memcpy(dw + 8, dw, 8); |
3142 |
return 0; |
3143 |
} |
3144 |
|
3145 |
// No key found matching our hash: create example SoftCam.Key BISS line for the live log |
3146 |
BissAnnotate(tmpBuffer3, sizeof(tmpBuffer3), ecmCopy, ecmLen, hash, 0, rdr->emu_datecodedenabled); |
3147 |
} |
3148 |
} |
3149 |
|
3150 |
// Try using only [tsid][onid] (useful when many channels on a transpoder use the same key) |
3151 |
if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms |
3152 |
{ |
3153 |
ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes |
3154 |
|
3155 |
// We have an r752+ style ecm with stripped namespace, thus a valid [tsid][onid] combo to use as provider |
3156 |
if ((ens & 0xE000FFFF) == 0xA0000000 && BissGetKey(b2i(4, ecm + ecmLen - 8), dw, 0, 2)) |
3157 |
{ |
3158 |
memcpy(dw + 8, dw, 8); |
3159 |
return 0; |
3160 |
} |
3161 |
|
3162 |
if ((ens & 0xE0000000) == 0xA0000000) // Strip [tsid] [onid] [namespace] on r752+ ecms |
3163 |
{ |
3164 |
ecmLen -= 8; |
3165 |
ecmDataLen -= 8; |
3166 |
} |
3167 |
} |
3168 |
|
3169 |
// Try using ecmpid if it seems to be faulty (should be 0x1FFF always for BISS) |
3170 |
if (ecmpid != 0x1FFF && ecmpid != 0) |
3171 |
{ |
3172 |
if (BissGetKey((srvid << 16) | ecmpid, dw, 0, 2)) |
3173 |
{ |
3174 |
memcpy(dw + 8, dw, 8); |
3175 |
return 0; |
3176 |
} |
3177 |
} |
3178 |
|
3179 |
// Try to get the pid from oscam's fake ecm (only search [pid1] [pid2] ... [pidx] to be compatible with emu r748-) |
3180 |
if (ecmLen >= 7 && ecmLen <= ecmDataLen) // Use >= for radio channels with just one (audio) pid |
3181 |
{ |
3182 |
// Reverse search order: last pid in list first |
3183 |
// Better identifies channels where they share identical video pid but have variable counts of audio pids |
3184 |
for (i = ecmLen - 2; i >= 5; i -= 2) |
3185 |
{ |
3186 |
pid = b2i(2, ecm + i); |
3187 |
|
3188 |
if (BissGetKey((srvid << 16) | pid, dw, 0, 2)) |
3189 |
{ |
3190 |
memcpy(dw + 8, dw, 8); |
3191 |
return 0; |
3192 |
} |
3193 |
} |
3194 |
} |
3195 |
|
3196 |
// Try using the standard BISS ecm pid |
3197 |
if (ecmpid == 0x1FFF || ecmpid == 0) |
3198 |
{ |
3199 |
if (BissGetKey((srvid << 16) | 0x1FFF, dw, 0, 2)) |
3200 |
{ |
3201 |
memcpy(dw + 8, dw, 8); |
3202 |
return 0; |
3203 |
} |
3204 |
} |
3205 |
|
3206 |
// Default BISS key for events with many feeds sharing same key |
3207 |
if (ecmpid != 0 && BissGetKey(0xA11FEED5, dw, rdr->emu_datecodedenabled, 2)) // Limit to local ecms, block netwotk ecms |
3208 |
{ |
3209 |
memcpy(dw + 8, dw, 8); |
3210 |
cs_hexdump(0, dw, 8, tmpBuffer1, sizeof(tmpBuffer1)); |
3211 |
cs_log("No specific match found. Using 'All Feeds' key: %s", tmpBuffer1); |
3212 |
return 0; |
3213 |
} |
3214 |
|
3215 |
// Print example key lines for available hash search methods, if no key is found |
3216 |
if (strncmp(tmpBuffer2, "0", 2)) cs_log("Example key based on namespace hash: %s", tmpBuffer2); |
3217 |
if (strncmp(tmpBuffer3, "0", 2)) cs_log("Example key based on universal hash: %s", tmpBuffer3); |
3218 |
|
3219 |
// Check if universal hash is common and warn user |
3220 |
if (BissIsCommonHash(hash)) cs_log("Feed has commonly used pids, universal hash clashes in SoftCam.Key are likely!"); |
3221 |
|
3222 |
return 2; |
3223 |
} |
3224 |
|
3225 |
// PowerVu Emu |
3226 |
static uint8_t PowervuCrc8Calc(uint8_t *data, int len) |
3227 |
{ |
3228 |
int i; |
3229 |
uint8_t crc = 0x00; |
3230 |
uint8_t crcTable[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, |
3231 |
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, |
3232 |
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, |
3233 |
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, |
3234 |
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, |
3235 |
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, |
3236 |
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, |
3237 |
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, |
3238 |
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, |
3239 |
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, |
3240 |
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, |
3241 |
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, |
3242 |
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, |
3243 |
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, |
3244 |
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, |
3245 |
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; |
3246 |
|
3247 |
for(i = 0; i < len; i++) |
3248 |
{ |
3249 |
crc = crcTable[data[i] ^ crc]; |
3250 |
} |
3251 |
|
3252 |
return crc; |
3253 |
} |
3254 |
|
3255 |
static void PowervuPadData(uint8_t *data, int len, uint8_t *dataPadded) |
3256 |
{ |
3257 |
int i; |
3258 |
uint8_t pad[] = {0x01, 0x02, 0x22, 0x04, 0x20, 0x2A, 0x1F, 0x03, 0x04, 0x06, 0x02, 0x0C, 0x2B, 0x2B, 0x01, 0x7B}; |
3259 |
|
3260 |
for(i = 0; i < len; i++) |
3261 |
{ |
3262 |
dataPadded[i] = data[i]; |
3263 |
} |
3264 |
|
3265 |
dataPadded[len] = 0x01; |
3266 |
|
3267 |
for(i = len + 1; i < 0x2F; i++) |
3268 |
{ |
3269 |
dataPadded[i] = 0x00; |
3270 |
} |
3271 |
|
3272 |
dataPadded[0x2F] = len; |
3273 |
|
3274 |
for(i = 0; i < 0x10; i++) |
3275 |
{ |
3276 |
dataPadded[0x30 + i] = pad[i]; |
3277 |
} |
3278 |
} |
3279 |
|
3280 |
static void PowervuHashMode01CustomMD5(uint8_t *data, uint8_t *hash) |
3281 |
{ |
3282 |
int i, j, s; |
3283 |
uint32_t a, b, c, d, f, g; |
3284 |
|
3285 |
uint32_t T[] = {0x783E16F6, 0xC267AC13, 0xA2B17F12, 0x6B8A31A4, 0xF910654D, 0xB702DBCB, 0x266CEF60, 0x5145E47C, |
3286 |
0xB92E00D6, 0xE80A4A64, 0x8A07FA77, 0xBA7D89A9, 0xEBED8022, 0x653AAF2B, 0xF118B03B, 0x6CC16544, |
3287 |
0x96EB6583, 0xF4E27E35, 0x1ABB119E, 0x068D3EF2, 0xDAEAA8A5, 0x3C312A3D, 0x59538388, 0xA100772F, |
3288 |
0xAB0165CE, 0x979959E7, 0x5DD8F53D, 0x189662BA, 0xFD021A9C, 0x6BC2D338, 0x1EFF667E, 0x40C66888, |
3289 |
0x6E9F07FF, 0x0CEF442F, 0x82D20190, 0x4E8CAEAC, 0x0F7CB305, 0x2E73FBE7, 0x1CE884A2, 0x7A60BD52, |
3290 |
0xC348B30D, 0x081CE3AA, 0xA12220E7, 0x38C7EC79, 0xCBD8DD3A, 0x62B4FBA5, 0xAD2A63DB, 0xE4D0852E, |
3291 |
0x53DE980F, 0x9C8DDA59, 0xA6B4CEDE, 0xB48A7692, 0x0E2C46A4, 0xEB9367CB, 0x165D72EE, 0x75532B45, |
3292 |
0xB9CA8E97, 0x08C8837B, 0x966F917B, 0x527515B4, 0xF27A5E5D, 0xB71E6267, 0x7603D7E6, 0x9837DD69}; // CUSTOM T |
3293 |
|
3294 |
uint8_t r[] = {0x06, 0x0A, 0x0F, 0x15, 0x05, 0x09, 0x0E, 0x14, 0x04, 0x0B, 0x10, 0x17, 0x07, 0x0C, 0x11, 0x16}; // STANDARD REORDERED |
3295 |
|
3296 |
uint8_t tIdxInit[] = {0, 1, 5, 0}; // STANDARD |
3297 |
uint8_t tIdxIncr[] = {1, 5, 3, 7}; // STANDARD |
3298 |
|
3299 |
uint32_t h[] = {0xEAD81D2E, 0xCE4DC6E9, 0xF9B5C301, 0x10325476}; // CUSTOM h0, h1, h2 STANDARD h3 |
3300 |
uint32_t dataLongs[0x10]; |
3301 |
|
3302 |
for(i = 0; i < 0x10; i++) |
3303 |
{ |
3304 |
dataLongs[i] = (data[4 * i + 0] << 0) + (data[4 * i + 1] << 8) + (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24); |
3305 |
} |
3306 |
|
3307 |
a = h[0]; |
3308 |
b = h[1]; |
3309 |
c = h[2]; |
3310 |
d = h[3]; |
3311 |
|
3312 |
for(i = 0; i < 4; i++) |
3313 |
{ |
3314 |
g = tIdxInit[i]; |
3315 |
|
3316 |
for(j = 0; j < 16; j++) |
3317 |
{ |
3318 |
if(i == 0) |
3319 |
{ |
3320 |
f = (b & c) | (~b & d); |
3321 |
} |
3322 |
else if(i == 1) |
3323 |
{ |
3324 |
f = (b & d) | (~d & c); |
3325 |
} |
3326 |
else if(i == 2) |
3327 |
{ |
3328 |
f = (b ^ c ^ d); |
3329 |
} |
3330 |
else if (i == 3) |
3331 |
{ |
3332 |
f = (~d | b) ^ c; |
3333 |
} |
3334 |
|
3335 |
f = dataLongs[g] + a + T[16 * i + j] + f; |
3336 |
|
3337 |
s = r[4 * i + (j & 3)]; |
3338 |
f = (f << s) | (f >> (32 - s)); |
3339 |
|
3340 |
a = d; |
3341 |
d = c; |
3342 |
c = b; |
3343 |
b += f; |
3344 |
|
3345 |
g = (g + tIdxIncr[i]) & 0xF; |
3346 |
} |
3347 |
} |
3348 |
|
3349 |
h[0] += a; |
3350 |
h[1] += b; |
3351 |
h[2] += c; |
3352 |
h[3] += d; |
3353 |
|
3354 |
for(i = 0; i < 4; i++) |
3355 |
{ |
3356 |
hash[4 * i + 0] = h[i] >> 0; |
3357 |
hash[4 * i + 1] = h[i] >> 8; |
3358 |
hash[4 * i + 2] = h[i] >> 16; |
3359 |
hash[4 * i + 3] = h[i] >> 24; |
3360 |
} |
3361 |
} |
3362 |
|
3363 |
static void PowervuHashMode02(uint8_t *data, uint8_t *hash) |
3364 |
{ |
3365 |
int i; |
3366 |
uint32_t a, b, c, d, e, f, tmp; |
3367 |
uint32_t h[] = {0x81887F3A, 0x36CCA480, 0x99056FB1, 0x79705BAE}; |
3368 |
uint32_t dataLongs[0x50]; |
3369 |
|
3370 |
for (i = 0; i < 0x10; i++) |
3371 |
{ |
3372 |
dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); |
3373 |
} |
3374 |
|
3375 |
for (i = 0; i < 0x40; i++) |
3376 |
{ |
3377 |
dataLongs[0x10 + i] = dataLongs[0x10 + i - 2]; |
3378 |
dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 7]; |
3379 |
dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 13]; |
3380 |
dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 16]; |
3381 |
} |
3382 |
|
3383 |
a = dataLongs[0]; |
3384 |
b = dataLongs[1]; |
3385 |
c = dataLongs[2]; |
3386 |
d = dataLongs[3]; |
3387 |
e = dataLongs[4]; |
3388 |
|
3389 |
for (i = 0; i < 0x50; i++) |
3390 |
{ |
3391 |
if (i < 0x15) f = (b & c) | (~b & d); |
3392 |
else if (i < 0x28) f = (b ^ c ^ d); |
3393 |
else if (i < 0x3D) f = (b & c) | (c & d) | (b & d); |
3394 |
else if (i < 0x50) f = (b ^ c ^ d); |
3395 |
|
3396 |
tmp = a; |
3397 |
a = e + f + (a << 5) + (a >> 27) + h[i / 0x14] + dataLongs[i]; |
3398 |
e = d; |
3399 |
d = c; |
3400 |
c = (b << 30) + (b >> 2); |
3401 |
b = tmp; |
3402 |
} |
3403 |
|
3404 |
dataLongs[0] += a; |
3405 |
dataLongs[1] += b; |
3406 |
dataLongs[2] += c; |
3407 |
dataLongs[3] += d; |
3408 |
|
3409 |
for (i = 0; i < 4; i++) |
3410 |
{ |
3411 |
hash[4 * i + 0] = dataLongs[i] >> 24; |
3412 |
hash[4 * i + 1] = dataLongs[i] >> 16; |
3413 |
hash[4 * i + 2] = dataLongs[i] >> 8; |
3414 |
hash[4 * i + 3] = dataLongs[i] >> 0; |
3415 |
} |
3416 |
} |
3417 |
|
3418 |
static void PowervuHashMode03(uint8_t *data, uint8_t *hash) |
3419 |
{ |
3420 |
int i, j, k, s, s2, tmp; |
3421 |
uint32_t a, b, c, d, f, g; |
3422 |
uint32_t a2, b2, c2, d2, f2, g2; |
3423 |
|
3424 |
uint32_t T[] = { 0xC88F3F2E, 0x967506BA, 0xDA877A7B, 0x0DECCDFE }; |
3425 |
uint32_t T2[] = { 0x01F42668, 0x39C7CDA5, 0xD490E2FE, 0x9965235D }; |
3426 |
|
3427 |
uint8_t r[] = { 0x0B, 0x0E, 0x0F, 0x0C, 0x05, 0x08, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0F, 0x06, 0x07, 0x09, 0x08, |
3428 |
0x07, 0x06, 0x08, 0x0D, 0x0B, 0x09, 0x07, 0x0F, 0x07, 0x0C, 0x0F, 0x09, 0x0B, 0x07, 0x0D, 0x0C }; |
3429 |
|
3430 |
uint8_t tIdxIncr[] = { 0x07, 0x04, 0x0D, 0x01, 0x0A, 0x06, 0x0F, 0x03, 0x0C, 0x00, 0x09, 0x05, 0x02, 0x0E, 0x0B, 0x08, |
3431 |
0x05, 0x0D, 0x02, 0x00, 0x04, 0x09, 0x03, 0x08, 0x01, 0x0A, 0x07, 0x0B, 0x06, 0x0F, 0x0C, 0x0E }; |
3432 |
|
3433 |
uint32_t h[] = { 0xC8616857, 0x9D3F5B8E, 0x4D7B8F76, 0x97BC8D80 }; |
3434 |
|
3435 |
uint32_t dataLongs[0x50]; |
3436 |
uint32_t result[4]; |
3437 |
|
3438 |
for (i = 0; i < 0x10; i++) |
3439 |
{ |
3440 |
dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); |
3441 |
} |
3442 |
|
3443 |
a = h[0]; |
3444 |
b = h[1]; |
3445 |
c = h[2]; |
3446 |
d = h[3]; |
3447 |
|
3448 |
a2 = h[3]; |
3449 |
b2 = h[2]; |
3450 |
c2 = h[1]; |
3451 |
d2 = h[0]; |
3452 |
|
3453 |
for (i = 0; i < 4; i++) |
3454 |
{ |
3455 |
for (j = 0; j < 16; j++) |
3456 |
{ |
3457 |
tmp = j; |
3458 |
|
3459 |
for (k = 0; k < i; k++) |
3460 |
{ |
3461 |
tmp = tIdxIncr[tmp]; |
3462 |
} |
3463 |
|
3464 |
g = 0x0F - tmp; |
3465 |
g2 = tmp; |
3466 |
|
3467 |
if (i == 0) f = (b & d) | (~d & c); |
3468 |
else if (i == 1) f = (~c | b) ^ d; |
3469 |
else if (i == 2) f = (~b & d) | (b & c); |
3470 |
else if (i == 3) f = (b ^ c ^ d); |
3471 |
|
3472 |
if (i == 0) f2 = (b2 ^ c2 ^ d2); |
3473 |
else if (i == 1) f2 = (~b2 & d2) | (b2 & c2); |
3474 |
else if (i == 2) f2 = (~c2 | b2) ^ d2; |
3475 |
else if (i == 3) f2 = (b2 & d2) | (~d2 & c2); |
3476 |
|
3477 |
f = dataLongs[g] + a + T[i] + f; |
3478 |
s = r[0x0F + (((i & 1) ^ 1) << 4) - j]; |
3479 |
f = (f << s) | (f >> (32 - s)); |
3480 |
|
3481 |
f2 = dataLongs[g2] + a2 + T2[i] + f2; |
3482 |
s2 = r[((i & 1) << 4) + j]; |
3483 |
f2 = (f2 << s2) | (f2 >> (32 - s2)); |
3484 |
|
3485 |
a = d; |
3486 |
d = (c << 10) | (c >> 22); |
3487 |
c = b; |
3488 |
b = f; |
3489 |
|
3490 |
a2 = d2; |
3491 |
d2 = (c2 << 10) | (c2 >> 22); |
3492 |
c2 = b2; |
3493 |
b2 = f2; |
3494 |
} |
3495 |
} |
3496 |
|
3497 |
result[0] = h[3] + b + a2; |
3498 |
result[1] = h[2] + c + b2; |
3499 |
result[2] = h[1] + d + c2; |
3500 |
result[3] = h[0] + a + d2; |
3501 |
|
3502 |
for (i = 0; i < 4; i++) |
3503 |
{ |
3504 |
hash[4 * i + 0] = result[i] >> 0; |
3505 |
hash[4 * i + 1] = result[i] >> 8; |
3506 |
hash[4 * i + 2] = result[i] >> 16; |
3507 |
hash[4 * i + 3] = result[i] >> 24; |
3508 |
} |
3509 |
} |
3510 |
|
3511 |
uint8_t table04[] = { 0x02, 0x03, 0x07, 0x0B, 0x0D, 0x08, 0x00, 0x01, 0x2B, 0x2D, 0x28, 0x20, 0x21, 0x0A, 0x0C, 0x0E, |
3512 |
0x22, 0x36, 0x23, 0x27, 0x29, 0x24, 0x25, 0x26, 0x2A, 0x3C, 0x3E, 0x3F, 0x0F, 0x2C, 0x2E, 0x2F, |
3513 |
0x12, 0x13, 0x17, 0x1B, 0x1C, 0x18, 0x10, 0x11, 0x19, 0x14, 0x15, 0x16, 0x1A, 0x09, 0x04, 0x05, |
3514 |
0x32, 0x33, 0x37, 0x3B, 0x06, 0x1C, 0x1E, 0x1F, 0x3D, 0x38, 0x30, 0x31, 0x39, 0x34, 0x35, 0x3A }; |
3515 |
|
3516 |
uint8_t table05[] = { 0x08, 0x09, 0x0A, 0x03, 0x04, 0x3F, 0x27, 0x28, 0x29, 0x2A, 0x05, 0x0B, 0x1B, 0x1C, 0x1C, 0x1E, |
3517 |
0x20, 0x0C, 0x0D, 0x22, 0x23, 0x24, 0x00, 0x01, 0x02, 0x06, 0x07, 0x25, 0x26, 0x0E, 0x0F, 0x21, |
3518 |
0x10, 0x11, 0x12, 0x2E, 0x2F, 0x13, 0x14, 0x15, 0x2B, 0x2C, 0x2D, 0x16, 0x17, 0x18, 0x19, 0x1A, |
3519 |
0x30, 0x31, 0x37, 0x3B, 0x3C, 0x3D, 0x3E, 0x1F, 0x38, 0x39, 0x32, 0x33, 0x34, 0x35, 0x36, 0x3A }; |
3520 |
|
3521 |
uint8_t table06[] = { 0x00, 0x01, 0x02, 0x06, 0x07, 0x08, 0x03, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x04, 0x05, 0x09, 0x0D, |
3522 |
0x20, 0x21, 0x22, 0x26, 0x27, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x10, 0x11, 0x12, 0x16, 0x17, 0x28, |
3523 |
0x18, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x29, 0x2D, |
3524 |
0x30, 0x31, 0x32, 0x36, 0x37, 0x38, 0x33, 0x34, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x35, 0x39, 0x3D }; |
3525 |
|
3526 |
uint8_t table09[] = { 0x20, 0x21, 0x24, 0x22, 0x23, 0x2A, 0x2B, 0x33, 0x35, 0x38, 0x39, 0x36, 0x2D, 0x2C, 0x2E, 0x2F, |
3527 |
0x00, 0x01, 0x04, 0x02, 0x25, 0x28, 0x08, 0x09, 0x06, 0x07, 0x0A, 0x0B, 0x0D, 0x0C, 0x0E, 0x0F, |
3528 |
0x10, 0x11, 0x14, 0x12, 0x13, 0x15, 0x19, 0x16, 0x29, 0x26, 0x03, 0x17, 0x1A, 0x1C, 0x1C, 0x1E, |
3529 |
0x30, 0x31, 0x34, 0x32, 0x37, 0x3A, 0x3B, 0x3D, 0x3C, 0x3E, 0x3F, 0x1B, 0x05, 0x18, 0x27, 0x1F }; |
3530 |
|
3531 |
static void PowervuHashModes04to0ATables(uint8_t *data, uint8_t *hash, uint8_t *table) |
3532 |
{ |
3533 |
int i; |
3534 |
|
3535 |
for (i = 0; i < 0x10; i++) |
3536 |
{ |
3537 |
hash[i] = table[i]; |
3538 |
hash[i] ^= data[table[i]]; |
3539 |
hash[i] ^= table[0x10 + i]; |
3540 |
hash[i] ^= data[table[0x10 + i]]; |
3541 |
hash[i] ^= table[0x20 + i]; |
3542 |
hash[i] ^= data[table[0x20 + i]]; |
3543 |
hash[i] ^= table[0x30 + i]; |
3544 |
hash[i] ^= data[table[0x30 + i]]; |
3545 |
} |
3546 |
} |
3547 |
|
3548 |
static void PowervuCreateHash(uint8_t *data, int len, uint8_t *hash, int mode) |
3549 |
{ |
3550 |
uint8_t dataPadded[0x40]; |
3551 |
|
3552 |
PowervuPadData(data, len, dataPadded); |
3553 |
|
3554 |
switch(mode) |
3555 |
{ |
3556 |
case 1: |
3557 |
PowervuHashMode01CustomMD5(dataPadded, hash); |
3558 |
break; |
3559 |
|
3560 |
case 2: |
3561 |
PowervuHashMode02(dataPadded, hash); |
3562 |
break; |
3563 |
|
3564 |
case 3: |
3565 |
PowervuHashMode03(dataPadded, hash); |
3566 |
break; |
3567 |
|
3568 |
case 4: |
3569 |
PowervuHashModes04to0ATables(dataPadded, hash, table04); |
3570 |
break; |
3571 |
|
3572 |
case 5: |
3573 |
PowervuHashModes04to0ATables(dataPadded, hash, table05); |
3574 |
break; |
3575 |
|
3576 |
case 6: |
3577 |
PowervuHashModes04to0ATables(dataPadded, hash, table06); |
3578 |
break; |
3579 |
|
3580 |
case 9: |
3581 |
PowervuHashModes04to0ATables(dataPadded, hash, table09); |
3582 |
break; |
3583 |
|
3584 |
default: |
3585 |
cs_log("A new hash mode [%d] is in use.", mode); |
3586 |
break; |
3587 |
} |
3588 |
} |
3589 |
|
3590 |
static void PowervuCreateDataEcmEmm(uint8_t *emmEcm, uint8_t *pos, int lenHeader, int len, uint8_t *data) |
3591 |
{ |
3592 |
int i; |
3593 |
|
3594 |
for(i = 0; i < len; i++) |
3595 |
{ |
3596 |
data[i] = emmEcm[lenHeader + pos[i]]; |
3597 |
} |
3598 |
} |
3599 |
|
3600 |
static uint8_t PowervuCreateDataCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, uint8_t *seedEcmCw, uint8_t *data) |
3601 |
{ |
3602 |
int i; |
3603 |
|
3604 |
for(i = 0; i < lenSeed; i++) |
3605 |
{ |
3606 |
data[i] = seed[i]; |
3607 |
} |
3608 |
|
3609 |
for(i = 0; i < 7; i++) |
3610 |
{ |
3611 |
data[lenSeed + i] = baseCw[i]; |
3612 |
} |
3613 |
|
3614 |
data[lenSeed + 7] = val; |
3615 |
|
3616 |
for(i = 0; i < 16; i++) |
3617 |
{ |
3618 |
data[lenSeed + 7 + 1 + i] = seedEcmCw[i]; |
3619 |
} |
3620 |
|
3621 |
return lenSeed + 7 + 1 + 0x10; |
3622 |
} |
3623 |
|
3624 |
static uint8_t PowervuUnmaskEcm(uint8_t *ecm, uint8_t *seedEcmCw) |
3625 |
{ |
3626 |
int i, l; |
3627 |
|
3628 |
uint8_t sourcePos[] = {0x04, 0x05, 0x06, 0x07, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x17, 0x1C, 0x1D, 0x1F, 0x23, |
3629 |
0x24, 0x25, 0x26, 0x27, 0x29, 0x2C, 0x2D, 0x2E}; |
3630 |
uint8_t destPos[] = {0x08, 0x09, 0x11, 0x18, 0x19, 0x1A, 0x1B, 0x1E, 0x20, 0x21, 0x22, 0x28, 0x2A, 0x2B, 0x2F, 0x30}; |
3631 |
uint8_t seedCwPos[] = {0x07, 0x0A, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0B, 0x10, 0x0C, 0x0F}; |
3632 |
|
3633 |
uint8_t data[0x18]; |
3634 |
uint8_t mask[0x10]; |
3635 |
uint8_t hashModeEcm; |
3636 |
uint8_t hashModeCw; |
3637 |
uint32_t crc; |
3638 |
|
3639 |
// Create seed for CW decryption |
3640 |
memset(seedEcmCw, 0, 0x10); |
3641 |
|
3642 |
int extraBytesLen = ecm[9]; |
3643 |
int startOffset = extraBytesLen + 0x0A; |
3644 |
|
3645 |
for (i = 0; i < 0x0B; i++) |
3646 |
{ |
3647 |
seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; |
3648 |
} |
3649 |
|
3650 |
// Read hash mode CW |
3651 |
hashModeCw = ecm[28 + extraBytesLen] ^ PowervuCrc8Calc(seedEcmCw, 0x10); |
3652 |
|
3653 |
// Create mask for ECM decryption |
3654 |
PowervuCreateDataEcmEmm(ecm, sourcePos, startOffset, 0x18, data); |
3655 |
|
3656 |
hashModeEcm = ecm[8] ^ PowervuCrc8Calc(data, 0x18); |
3657 |
|
3658 |
PowervuCreateHash(data, 0x18, mask, hashModeEcm); |
3659 |
|
3660 |
// Fix header |
3661 |
ecm[3] &= 0x0F; |
3662 |
ecm[3] |= 0x30; |
3663 |
ecm[8] = 0x00; |
3664 |
ecm[28 + extraBytesLen] = 0x00; |
3665 |
|
3666 |
// Unmask body |
3667 |
for (i = 0; i < 0x10; i++) |
3668 |
{ |
3669 |
ecm[startOffset + destPos[i]] ^= mask[i & 0x0F]; |
3670 |
} |
3671 |
|
3672 |
// Fix CRC (optional) |
3673 |
l = (((ecm[1] << 8) + ecm[2]) & 0xFFF) + 3 - 4; |
3674 |
|
3675 |
crc = fletcher_crc32(ecm, l); |
3676 |
|
3677 |
ecm[l + 0] = crc >> 24; |
3678 |
ecm[l + 1] = crc >> 16; |
3679 |
ecm[l + 2] = crc >> 8; |
3680 |
ecm[l + 3] = crc >> 0; |
3681 |
|
3682 |
return hashModeCw; |
3683 |
} |
3684 |
|
3685 |
static void PowervuCreateCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, |
3686 |
uint8_t *seedEcmCw, uint8_t *cw, int modeDesCsa, int hashMode) |
3687 |
{ |
3688 |
uint8_t tableFixParity[] = {0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, |
3689 |
0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, |
3690 |
0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, |
3691 |
0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, |
3692 |
0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, |
3693 |
0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, |
3694 |
0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, |
3695 |
0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, |
3696 |
0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, |
3697 |
0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, |
3698 |
0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, |
3699 |
0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, |
3700 |
0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, |
3701 |
0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, |
3702 |
0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, |
3703 |
0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}; |
3704 |
|
3705 |
uint8_t data[0x1C]; |
3706 |
uint8_t hash[0x10]; |
3707 |
uint8_t lenData; |
3708 |
int i; |
3709 |
|
3710 |
lenData = PowervuCreateDataCw(seed, lenSeed, baseCw, val, seedEcmCw, data); |
3711 |
PowervuCreateHash(data, lenData, hash, hashMode); |
3712 |
|
3713 |
for(i = 0; i < 8; i++) |
3714 |
{ |
3715 |
cw[i] = hash[i]; |
3716 |
} |
3717 |
|
3718 |
if(modeDesCsa == 0) // DES - Fix Parity Bits |
3719 |
{ |
3720 |
for(i = 0; i < 8; i++) |
3721 |
{ |
3722 |
cw[i] = tableFixParity[cw[i]]; |
3723 |
} |
3724 |
} |
3725 |
else if(modeDesCsa == 1) // CSA - Fix Checksums |
3726 |
{ |
3727 |
cw[3] = cw[0] + cw[1] + cw[2]; |
3728 |
cw[7] = cw[4] + cw[5] + cw[6]; |
3729 |
} |
3730 |
} |
3731 |
|
3732 |
static int8_t GetPowervuKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef) |
3733 |
{ |
3734 |
char keyStr[EMU_MAX_CHAR_KEYNAME]; |
3735 |
|
3736 |
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); |
3737 |
if(FindKey('P', ident, 0xFFFF0000, keyStr, buf, keyLength, isCriticalKey, keyRef, 0, NULL)) { |
3738 |
return 1; |
3739 |
} |
3740 |
|
3741 |
return 0; |
3742 |
} |
3743 |
|
3744 |
static int8_t GetPowervuEmmKey(uint8_t *buf, uint32_t ident, char *keyName, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef, uint32_t *getProvider) |
3745 |
{ |
3746 |
if(FindKey('P', ident, 0xFFFFFFFF, keyName, buf, keyLength, isCriticalKey, keyRef, 0, getProvider)) { |
3747 |
return 1; |
3748 |
} |
3749 |
|
3750 |
return 0; |
3751 |
} |
3752 |
|
3753 |
static const uint8_t PowerVu_A0_S_1[16] = {0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2}; |
3754 |
static const uint8_t PowerVu_A0_S_2[16] = {0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB}; |
3755 |
static const uint8_t PowerVu_A0_S_3[16] = {0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA}; |
3756 |
static const uint8_t PowerVu_A0_S_4[16] = {0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56}; |
3757 |
static const uint8_t PowerVu_A0_S_5[16] = {0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47}; |
3758 |
static const uint8_t PowerVu_A0_S_6[16] = {0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4}; |
3759 |
static const uint8_t PowerVu_A0_S_7[16] = {0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A}; |
3760 |
static const uint8_t PowerVu_A0_S_8[16] = {0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0}; |
3761 |
static const uint8_t PowerVu_A0_S_9[32] = {0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15, |
3762 |
0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C |
3763 |
}; |
3764 |
|
3765 |
static const uint8_t PowerVu_00_S_1[16] = {0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C}; |
3766 |
static const uint8_t PowerVu_00_S_2[16] = {0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73}; |
3767 |
static const uint8_t PowerVu_00_S_3[16] = {0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41}; |
3768 |
static const uint8_t PowerVu_00_S_4[16] = {0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F}; |
3769 |
static const uint8_t PowerVu_00_S_5[16] = {0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29}; |
3770 |
static const uint8_t PowerVu_00_S_6[16] = {0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D}; |
3771 |
static const uint8_t PowerVu_00_S_7[16] = {0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B}; |
3772 |
static const uint8_t PowerVu_00_S_8[16] = {0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9}; |
3773 |
static const uint8_t PowerVu_00_S_9[32] = {0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2, |
3774 |
0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59, |
3775 |
}; |
3776 |
|
3777 |
static uint8_t PowervuSbox(uint8_t *input, uint8_t mode) |
3778 |
{ |
3779 |
uint8_t s_index, bit, last_index, last_bit; |
3780 |
uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9; |
3781 |
|
3782 |
if(mode) |
3783 |
{ |
3784 |
Sbox1 = PowerVu_A0_S_1; |
3785 |
Sbox2 = PowerVu_A0_S_2; |
3786 |
Sbox3 = PowerVu_A0_S_3; |
3787 |
Sbox4 = PowerVu_A0_S_4; |
3788 |
Sbox5 = PowerVu_A0_S_5; |
3789 |
Sbox6 = PowerVu_A0_S_6; |
3790 |
Sbox7 = PowerVu_A0_S_7; |
3791 |
Sbox8 = PowerVu_A0_S_8; |
3792 |
Sbox9 = PowerVu_A0_S_9; |
3793 |
} |
3794 |
else |
3795 |
{ |
3796 |
Sbox1 = PowerVu_00_S_1; |
3797 |
Sbox2 = PowerVu_00_S_2; |
3798 |
Sbox3 = PowerVu_00_S_3; |
3799 |
Sbox4 = PowerVu_00_S_4; |
3800 |
Sbox5 = PowerVu_00_S_5; |
3801 |
Sbox6 = PowerVu_00_S_6; |
3802 |
Sbox7 = PowerVu_00_S_7; |
3803 |
Sbox8 = PowerVu_00_S_8; |
3804 |
Sbox9 = PowerVu_00_S_9; |
3805 |
} |
3806 |
|
3807 |
bit = (GetBit(input[2],0)<<2) | (GetBit(input[3],4)<<1) | (GetBit(input[5],3)); |
3808 |
s_index = (GetBit(input[0],0)<<3) | (GetBit(input[2],6)<<2) | (GetBit(input[2],4)<<1) | (GetBit(input[5],7)); |
3809 |
last_bit = GetBit(Sbox1[s_index],7-bit); |
3810 |
|
3811 |
bit = (GetBit(input[5],0)<<2) | (GetBit(input[4],0)<<1) | (GetBit(input[6],2)); |
3812 |
s_index = (GetBit(input[2],1)<<3) | (GetBit(input[2],2)<<2) | (GetBit(input[5],5)<<1) | (GetBit(input[5],1)); |
3813 |
last_bit = last_bit | (GetBit(Sbox2[s_index],7-bit)<<1); |
3814 |
|
3815 |
bit = (GetBit(input[6],0)<<2) | (GetBit(input[1],7)<<1) | (GetBit(input[6],7)); |
3816 |
s_index = (GetBit(input[1],3)<<3) | (GetBit(input[3],7)<<2) | (GetBit(input[1],5)<<1) | (GetBit(input[5],2)); |
3817 |
last_bit = last_bit | (GetBit(Sbox3[s_index], 7-bit)<<2); |
3818 |
|
3819 |
bit = (GetBit(input[1],0)<<2) | (GetBit(input[2],7)<<1) | (GetBit(input[2],5)); |
3820 |
s_index = (GetBit(input[6],3)<<3) | (GetBit(input[6],4)<<2) | (GetBit(input[6],6)<<1) | (GetBit(input[3],5)); |
3821 |
last_index = GetBit(Sbox4[s_index], 7-bit); |
3822 |
|
3823 |
bit = (GetBit(input[3],3)<<2) | (GetBit(input[4],6)<<1) | (GetBit(input[3],2)); |
3824 |
s_index = (GetBit(input[3],1)<<3) | (GetBit(input[4],5)<<2) | (GetBit(input[3],0)<<1) | (GetBit(input[4],7)); |
3825 |
last_index = last_index | (GetBit(Sbox5[s_index], 7-bit)<<1); |
3826 |
|
3827 |
bit = (GetBit(input[5],4)<<2) | (GetBit(input[4],4)<<1) | (GetBit(input[1],2)); |
3828 |
s_index = (GetBit(input[2],3)<<3) | (GetBit(input[6],5)<<2) | (GetBit(input[1],4)<<1) | (GetBit(input[4],1)); |
3829 |
last_index = last_index | (GetBit(Sbox6[s_index], 7-bit)<<2); |
3830 |
|
3831 |
bit = (GetBit(input[0],6)<<2) | (GetBit(input[0],7)<<1) | (GetBit(input[0],4)); |
3832 |
s_index = (GetBit(input[0],5)<<3) | (GetBit(input[0],3)<<2) | (GetBit(input[0],1)<<1) | (GetBit(input[0],2)); |
3833 |
last_index = last_index | (GetBit(Sbox7[s_index], 7-bit)<<3); |
3834 |
|
3835 |
bit = (GetBit(input[4],2)<<2) | (GetBit(input[4],3)<<1) | (GetBit(input[1],1)); |
3836 |
s_index = (GetBit(input[1],6)<<3) | (GetBit(input[6],1)<<2) | (GetBit(input[5],6)<<1) | (GetBit(input[3],6)); |
3837 |
last_index = last_index | (GetBit(Sbox8[s_index], 7-bit)<<4); |
3838 |
|
3839 |
return (GetBit(Sbox9[last_index&0x1f],7-last_bit)&1) ? 1: 0; |
3840 |
} |
3841 |
|
3842 |
static void PowervuDecrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox) |
3843 |
{ |
3844 |
uint32_t i; |
3845 |
int32_t j, k; |
3846 |
uint8_t curByte, tmpBit; |
3847 |
|
3848 |
for(i = 0; i < length; i++) |
3849 |
{ |
3850 |
curByte = data[i]; |
3851 |
|
3852 |
for(j = 7; j >= 0; j--) |
3853 |
{ |
3854 |
data[i] = SetBit(data[i], j, (GetBit(curByte, j)^PowervuSbox(key, sbox))^GetBit(key[0], 7)); |
3855 |
|
3856 |
tmpBit = GetBit(data[i], j)^(GetBit(key[6], 0)); |
3857 |
if (tmpBit) |
3858 |
{ |
3859 |
key[3] ^= 0x10; |
3860 |
} |
3861 |
|
3862 |
for (k = 6; k > 0; k--) |
3863 |
{ |
3864 |
key[k] = (key[k]>>1) | (key[k-1]<<7); |
3865 |
} |
3866 |
key[0] = (key[0]>>1); |
3867 |
|
3868 |
key[0] = SetBit(key[0], 7, tmpBit); |
3869 |
} |
3870 |
} |
3871 |
} |
3872 |
|
3873 |
#define PVU_CW_VID 0 // VIDeo |
3874 |
#define PVU_CW_HSD 1 // High Speed Data |
3875 |
#define PVU_CW_A1 2 // Audio 1 |
3876 |
#define PVU_CW_A2 3 // Audio 2 |
3877 |
#define PVU_CW_A3 4 // Audio 3 |
3878 |
#define PVU_CW_A4 5 // Audio 4 |
3879 |
#define PVU_CW_UTL 6 // UTiLity |
3880 |
#define PVU_CW_VBI 7 // Vertical Blanking Interval |
3881 |
|
3882 |
#define PVU_CONVCW_VID_ECM 0x80 // VIDeo |
3883 |
#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data |
3884 |
#define PVU_CONVCW_A1_ECM 0x20 // Audio 1 |
3885 |
#define PVU_CONVCW_A2_ECM 0x10 // Audio 2 |
3886 |
#define PVU_CONVCW_A3_ECM 0x08 // Audio 3 |
3887 |
#define PVU_CONVCW_A4_ECM 0x04 // Audio 4 |
3888 |
#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity |
3889 |
#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval |
3890 |
|
3891 |
static uint8_t PowervuGetConvcwIndex(uint8_t ecmTag) |
3892 |
{ |
3893 |
switch(ecmTag) |
3894 |
{ |
3895 |
case PVU_CONVCW_VID_ECM: |
3896 |
return PVU_CW_VID; |
3897 |
|
3898 |
case PVU_CONVCW_HSD_ECM: |
3899 |
return PVU_CW_HSD; |
3900 |
|
3901 |
case PVU_CONVCW_A1_ECM: |
3902 |
return PVU_CW_A1; |
3903 |
|
3904 |
case PVU_CONVCW_A2_ECM: |
3905 |
return PVU_CW_A2; |
3906 |
|
3907 |
case PVU_CONVCW_A3_ECM: |
3908 |
return PVU_CW_A3; |
3909 |
|
3910 |
case PVU_CONVCW_A4_ECM: |
3911 |
return PVU_CW_A4; |
3912 |
|
3913 |
case PVU_CONVCW_UTL_ECM: |
3914 |
return PVU_CW_UTL; |
3915 |
|
3916 |
case PVU_CONVCW_VBI_ECM: |
3917 |
return PVU_CW_VBI; |
3918 |
|
3919 |
default: |
3920 |
return PVU_CW_VBI; |
3921 |
} |
3922 |
} |
3923 |
|
3924 |
static uint16_t PowervuGetSeedIV(uint8_t seedType, uint8_t *ecm) |
3925 |
{ |
3926 |
switch(seedType) |
3927 |
{ |
3928 |
case PVU_CW_VID: |
3929 |
return ((ecm[0x10] & 0x1F) <<3) | 0; |
3930 |
case PVU_CW_HSD: |
3931 |
return ((ecm[0x12] & 0x1F) <<3) | 2; |
3932 |
case PVU_CW_A1: |
3933 |
return ((ecm[0x11] & 0x3F) <<3) | 1; |
3934 |
case PVU_CW_A2: |
3935 |
return ((ecm[0x13] & 0x3F) <<3) | 1; |
3936 |
case PVU_CW_A3: |
3937 |
return ((ecm[0x19] & 0x3F) <<3) | 1; |
3938 |
case PVU_CW_A4: |
3939 |
return ((ecm[0x1A] & 0x3F) <<3) | 1;; |
3940 |
case PVU_CW_UTL: |
3941 |
return ((ecm[0x14] & 0x0F) <<3) | 4; |
3942 |
case PVU_CW_VBI: |
3943 |
return (((ecm[0x15] & 0xF8)>>3)<<3) | 5; |
3944 |
default: |
3945 |
return 0; |
3946 |
} |
3947 |
} |
3948 |
|
3949 |
static uint8_t PowervuExpandSeed(uint8_t seedType, uint8_t *seed) |
3950 |
{ |
3951 |
uint8_t seedLength = 0, i; |
3952 |
|
3953 |
switch(seedType) |
3954 |
{ |
3955 |
case PVU_CW_VID: |
3956 |
case PVU_CW_HSD: |
3957 |
seedLength = 4; |
3958 |
break; |
3959 |
case PVU_CW_A1: |
3960 |
case PVU_CW_A2: |
3961 |
case PVU_CW_A3: |
3962 |
case PVU_CW_A4: |
3963 |
seedLength = 3; |
3964 |
break; |
3965 |
case PVU_CW_UTL: |
3966 |
case PVU_CW_VBI: |
3967 |
seedLength = 2; |
3968 |
break; |
3969 |
default: |
3970 |
return seedLength; |
3971 |
} |
3972 |
|
3973 |
for(i=seedLength; i<7; i++) |
3974 |
{ |
3975 |
seed[i] = seed[i%seedLength]; |
3976 |
} |
3977 |
|
3978 |
return seedLength; |
3979 |
} |
3980 |
|
3981 |
static void PowervuCalculateSeed(uint8_t seedType, uint8_t *ecm, uint8_t *seedBase, uint8_t *key, uint8_t *seed, uint8_t sbox) |
3982 |
{ |
3983 |
uint16_t tmpSeed; |
3984 |
|
3985 |
tmpSeed = PowervuGetSeedIV(seedType, ecm+23); |
3986 |
seed[0] = (tmpSeed >> 2) & 0xFF; |
3987 |
seed[1] = ((tmpSeed & 0x3) << 6) | (seedBase[0] >> 2); |
3988 |
seed[2] = ( seedBase[0] << 6) | (seedBase[1] >> 2); |
3989 |
seed[3] = ( seedBase[1] << 6) | (seedBase[2] >> 2); |
3990 |
seed[4] = ( seedBase[2] << 6) | (seedBase[3] >> 2); |
3991 |
seed[5] = ( seedBase[3] << 6); |
3992 |
|
3993 |
PowervuDecrypt(seed, 6, key, sbox); |
3994 |
|
3995 |
seed[0] = (seed[1] << 2) | (seed[2] >> 6); |
3996 |
seed[1] = (seed[2] << 2) | (seed[3] >> 6); |
3997 |
seed[2] = (seed[3] << 2) | (seed[4] >> 6); |
3998 |
seed[3] = (seed[4] << 2) | (seed[5] >> 6); |
3999 |
} |
4000 |
|
4001 |
static void PowervuCalculateCw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8_t *convolvedCw, |
4002 |
uint8_t *cw, uint8_t *baseCw, uint8_t *seedEcmCw, uint8_t hashModeCw, |
4003 |
uint8_t needsUnmasking, uint8_t xorMode) |
4004 |
{ |
4005 |
int32_t k; |
4006 |
uint8_t seedLength, val = 0; |
4007 |
|
4008 |
seedLength = PowervuExpandSeed(seedType, seed); |
4009 |
|
4010 |
if(csaUsed) |
4011 |
{ |
4012 |
if(!needsUnmasking || (hashModeCw == 0)) |
4013 |
{ |
4014 |
for(k = 0; k < 7; k++) |
4015 |
{ |
4016 |
seed[k] ^= baseCw[k]; |
4017 |
} |
4018 |
|
4019 |
cw[0] = seed[0] ^ convolvedCw[0]; |
4020 |
cw[1] = seed[1] ^ convolvedCw[1]; |
4021 |
cw[2] = seed[2] ^ convolvedCw[2]; |
4022 |
cw[3] = seed[3] ^ convolvedCw[3]; |
4023 |
cw[4] = seed[3] ^ convolvedCw[4]; |
4024 |
cw[5] = seed[4] ^ convolvedCw[5]; |
4025 |
cw[6] = seed[5] ^ convolvedCw[6]; |
4026 |
cw[7] = seed[6] ^ convolvedCw[7]; |
4027 |
} |
4028 |
} |
4029 |
else |
4030 |
{ |
4031 |
if(xorMode == 0) |
4032 |
{ |
4033 |
for(k = 0; k < 7; k++) |
4034 |
{ |
4035 |
cw[k] = seed[k] ^ baseCw[k]; |
4036 |
} |
4037 |
} |
4038 |
|
4039 |
if(xorMode == 1) |
4040 |
{ |
4041 |
for(k = 0; k < 3; k++) |
4042 |
{ |
4043 |
cw[k] = seed[k] ^ baseCw[k]; |
4044 |
} |
4045 |
|
4046 |
for(k = 3; k < 7; k++) |
4047 |
{ |
4048 |
cw[k] = baseCw[k]; |
4049 |
} |
4050 |
} |
4051 |
|
4052 |
ExpandDesKey(cw); |
4053 |
} |
4054 |
|
4055 |
if(needsUnmasking && (hashModeCw > 0)) |
4056 |
{ |
4057 |
switch(seedType) |
4058 |
{ |
4059 |
case PVU_CW_VID: |
4060 |
val = 0; |
4061 |
break; |
4062 |
|
4063 |
case PVU_CW_A1: |
4064 |
case PVU_CW_A2: |
4065 |
case PVU_CW_A3: |
4066 |
case PVU_CW_A4: |
4067 |
val = 1; |
4068 |
break; |
4069 |
|
4070 |
case PVU_CW_HSD: |
4071 |
val = 2; |
4072 |
break; |
4073 |
|
4074 |
case PVU_CW_UTL: |
4075 |
val = 4; |
4076 |
break; |
4077 |
|
4078 |
case PVU_CW_VBI: |
4079 |
val = 5; |
4080 |
break; |
4081 |
} |
4082 |
PowervuCreateCw(seed, seedLength, baseCw, val, seedEcmCw, cw, csaUsed, hashModeCw); |
4083 |
} |
4084 |
} |
4085 |
|
4086 |
#ifdef WITH_EMU |
4087 |
int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex) |
4088 |
#else |
4089 |
int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata) |
4090 |
#endif |
4091 |
{ |
4092 |
int8_t ret = 1; |
4093 |
uint16_t ecmLen = GetEcmLen(ecm); |
4094 |
uint32_t ecmCrc32; |
4095 |
uint8_t nanoCmd, nanoChecksum, keyType, fixedKey, oddKey, bid, csaUsed; |
4096 |
uint16_t nanoLen; |
4097 |
uint32_t channelId, ecmSrvid, keyIndex; |
4098 |
uint32_t i, j, k; |
4099 |
uint8_t convolvedCw[8][8]; |
4100 |
uint8_t ecmKey[7], tmpEcmKey[7], seedBase[4], baseCw[7], seed[8][8], cw[8][8]; |
4101 |
uint8_t decrypt_ok; |
4102 |
uint8_t ecmPart1[14], ecmPart2[27]; |
4103 |
uint8_t sbox; |
4104 |
uint32_t keyRef1, keyRef2; |
4105 |
uint8_t calculateAllCws; |
4106 |
uint8_t seedEcmCw[0x10]; |
4107 |
uint8_t hashModeCw = 0, needsUnmasking, xorMode; |
4108 |
#ifdef WITH_EMU |
4109 |
uint8_t *dwp; |
4110 |
emu_stream_cw_item *cw_item; |
4111 |
int8_t update_global_key = 0; |
4112 |
int8_t update_global_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; |
4113 |
|
4114 |
memset(update_global_keys, 0, sizeof(update_global_keys)); |
4115 |
#endif |
4116 |
|
4117 |
if(ecmLen < 7) |
4118 |
{ |
4119 |
return 1; |
4120 |
} |
4121 |
|
4122 |
needsUnmasking = (ecm[3] & 0xF0) == 0x50; |
4123 |
|
4124 |
if(needsUnmasking) |
4125 |
{ |
4126 |
hashModeCw = PowervuUnmaskEcm(ecm, seedEcmCw); |
4127 |
} |
4128 |
|
4129 |
ecmCrc32 = b2i(4, ecm+ecmLen-4); |
4130 |
|
4131 |
if(fletcher_crc32(ecm, ecmLen-4) != ecmCrc32) |
4132 |
{ |
4133 |
return 8; |
4134 |
} |
4135 |
ecmLen -= 4; |
4136 |
|
4137 |
for(i = 0; i < 8; i++) { |
4138 |
memset(convolvedCw[i], 0, 8); |
4139 |
} |
4140 |
|
4141 |
for(i = 3; i+3 < ecmLen; ) { |
4142 |
nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); |
4143 |
i += 2; |
4144 |
if(nanoLen > 0) |
4145 |
{ |
4146 |
nanoLen--; |
4147 |
} |
4148 |
nanoCmd = ecm[i++]; |
4149 |
if(i+nanoLen > ecmLen) { |
4150 |
return 1; |
4151 |
} |
4152 |
|
4153 |
switch (nanoCmd) { |
4154 |
case 0x27: |
4155 |
if(nanoLen < 15) |
4156 |
{ |
4157 |
break; |
4158 |
} |
4159 |
|
4160 |
nanoChecksum = 0; |
4161 |
for(j = 4; j < 15; j++) |
4162 |
{ |
4163 |
nanoChecksum += ecm[i+j]; |
4164 |
} |
4165 |
|
4166 |
if(nanoChecksum != 0) |
4167 |
{ |
4168 |
break; |
4169 |
} |
4170 |
|
4171 |
keyType = PowervuGetConvcwIndex(ecm[i+4]); |
4172 |
memcpy(convolvedCw[keyType], &ecm[i+6], 8); |
4173 |
break; |
4174 |
|
4175 |
default: |
4176 |
break; |
4177 |
} |
4178 |
i += nanoLen; |
4179 |
} |
4180 |
|
4181 |
for(i = 3; i+3 < ecmLen; ) { |
4182 |
nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); |
4183 |
i += 2; |
4184 |
if(nanoLen > 0) |
4185 |
{ |
4186 |
nanoLen--; |
4187 |
} |
4188 |
nanoCmd = ecm[i++]; |
4189 |
if(i+nanoLen > ecmLen) { |
4190 |
return 1; |
4191 |
} |
4192 |
|
4193 |
switch (nanoCmd) { |
4194 |
case 0x20: |
4195 |
if(nanoLen < 54) |
4196 |
{ |
4197 |
break; |
4198 |
} |
4199 |
|
4200 |
i += ecm[i + 3]; // Extra Data Length |
4201 |
|
4202 |
csaUsed = GetBit(ecm[i+7], 7); |
4203 |
fixedKey = !GetBit(ecm[i+6], 5); |
4204 |
oddKey = GetBit(ecm[i+6], 4); |
4205 |
xorMode = GetBit(ecm[i+6], 0); |
4206 |
bid = (GetBit(ecm[i+7], 1) << 1) | GetBit(ecm[i+7], 0); |
4207 |
sbox = GetBit(ecm[i+6], 3); |
4208 |
|
4209 |
keyIndex = (fixedKey << 3) | (bid << 2) | oddKey; |
4210 |
channelId = b2i(2, ecm+i+23); |
4211 |
ecmSrvid = (channelId >> 4) | ((channelId & 0xF) << 12); |
4212 |
|
4213 |
decrypt_ok = 0; |
4214 |
|
4215 |
memcpy(ecmPart1, ecm+i+8, 14); |
4216 |
memcpy(ecmPart2, ecm+i+27, 27); |
4217 |
|
4218 |
keyRef1 = 0; |
4219 |
keyRef2 = 0; |
4220 |
|
4221 |
do |
4222 |
{ |
4223 |
if(!GetPowervuKey(ecmKey, ecmSrvid, '0', keyIndex, 7, 0, keyRef1++)) |
4224 |
{ |
4225 |
if(!GetPowervuKey(ecmKey, channelId, '0', keyIndex, 7, 0, keyRef2++)) |
4226 |
{ |
4227 |
cs_log("Key not found: P %04X 0%X", ecmSrvid, keyIndex); |
4228 |
return 2; |
4229 |
} |
4230 |
} |
4231 |
|
4232 |
PowervuDecrypt(ecm+i+8, 14, ecmKey, sbox); |
4233 |
if((ecm[i+6] != ecm[i+6+7]) || (ecm[i+6+8] != ecm[i+6+15])) |
4234 |
{ |
4235 |
memcpy(ecm+i+8, ecmPart1, 14); |
4236 |
continue; |
4237 |
} |
4238 |
|
4239 |
memcpy(tmpEcmKey, ecmKey, 7); |
4240 |
|
4241 |
PowervuDecrypt(ecm+i+27, 27, ecmKey, sbox); |
4242 |
if((ecm[i+23] != ecm[i+23+29]) || (ecm[i+23+1] != ecm[i+23+30])) |
4243 |
{ |
4244 |
memcpy(ecm+i+8, ecmPart1, 14); |
4245 |
memcpy(ecm+i+27, ecmPart2, 27); |
4246 |
continue; |
4247 |
} |
4248 |
|
4249 |
decrypt_ok = 1; |
4250 |
} |
4251 |
while(!decrypt_ok); |
4252 |
|
4253 |
memcpy(seedBase, ecm+i+6+2, 4); |
4254 |
|
4255 |
#ifdef WITH_EMU |
4256 |
if(cdata == NULL) |
4257 |
{ |
4258 |
SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); |
4259 |
for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) |
4260 |
{ |
4261 |
if(!stream_server_has_ecm[j] && emu_stream_cur_srvid[j] == srvid) |
4262 |
{ |
4263 |
update_global_key = 1; |
4264 |
update_global_keys[j] = 1; |
4265 |
} |
4266 |
} |
4267 |
SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); |
4268 |
} |
4269 |
|
4270 |
if(cdata != NULL || update_global_key || cw_ex != NULL) |
4271 |
#else |
4272 |
if(cdata != NULL) |
4273 |
#endif |
4274 |
{ |
4275 |
// Calculate all seeds |
4276 |
for(j = 0; j < 8; j++) |
4277 |
{ |
4278 |
memcpy(ecmKey, tmpEcmKey, 7); |
4279 |
PowervuCalculateSeed(j, ecm+i, seedBase, ecmKey, seed[j], sbox); |
4280 |
} |
4281 |
} |
4282 |
else |
4283 |
{ |
4284 |
// Calculate only video seed |
4285 |
memcpy(ecmKey, tmpEcmKey, 7); |
4286 |
PowervuCalculateSeed(PVU_CW_VID, ecm+i, seedBase, ecmKey, seed[PVU_CW_VID], sbox); |
4287 |
} |
4288 |
|
4289 |
memcpy(baseCw, ecm+i+6+8, 7); |
4290 |
|
4291 |
#ifdef WITH_EMU |
4292 |
calculateAllCws = cdata != NULL || update_global_key || cw_ex != NULL; |
4293 |
#else |
4294 |
calculateAllCws = cdata != NULL; |
4295 |
#endif |
4296 |
if(calculateAllCws) |
4297 |
{ |
4298 |
// Calculate all cws |
4299 |
for(j = 0; j < 8; j++) |
4300 |
{ |
4301 |
PowervuCalculateCw(j, seed[j], csaUsed, convolvedCw[j], cw[j], baseCw, |
4302 |
seedEcmCw, hashModeCw, needsUnmasking, xorMode); |
4303 |
|
4304 |
if(csaUsed) |
4305 |
{ |
4306 |
for(k = 0; k < 8; k += 4) { |
4307 |
cw[j][k + 3] = ((cw[j][k] + cw[j][k + 1] + cw[j][k + 2]) & 0xff); |
4308 |
} |
4309 |
} |
4310 |
} |
4311 |
|
4312 |
#ifdef WITH_EMU |
4313 |
if(update_global_key) |
4314 |
{ |
4315 |
for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) |
4316 |
{ |
4317 |
if(update_global_keys[j]) |
4318 |
{ |
4319 |
cw_item = (emu_stream_cw_item*)malloc(sizeof(emu_stream_cw_item)); |
4320 |
if(cw_item != NULL) |
4321 |
{ |
4322 |
cw_item->csa_used = csaUsed; |
4323 |
cw_item->is_even = ecm[0] == 0x80 ? 1 : 0; |
4324 |
cs_ftime(&cw_item->write_time); |
4325 |
add_ms_to_timeb(&cw_item->write_time, cfg.emu_stream_ecm_delay); |
4326 |
memcpy(cw_item->cw, cw, sizeof(cw)); |
4327 |
ll_append(ll_emu_stream_delayed_keys[j], cw_item); |
4328 |
} |
4329 |
} |
4330 |
} |
4331 |
} |
4332 |
|
4333 |
if(cdata != NULL) |
4334 |
{ |
4335 |
#endif |
4336 |
for(j = 0; j < 8; j++) |
4337 |
{ |
4338 |
if(csaUsed) |
4339 |
{ |
4340 |
if(cdata->pvu_csa_ks[j] == NULL) |
4341 |
{ cdata->pvu_csa_ks[j] = get_key_struct(); } |
4342 |
|
4343 |
if(ecm[0] == 0x80) |
4344 |
{ set_even_control_word(cdata->pvu_csa_ks[j], cw[j]); } |
4345 |
else |
4346 |
{ set_odd_control_word(cdata->pvu_csa_ks[j], cw[j]); } |
4347 |
|
4348 |
cdata->pvu_csa_used = 1; |
4349 |
} |
4350 |
else |
4351 |
{ |
4352 |
if(ecm[0] == 0x80) |
4353 |
{ des_set_key(cw[j], cdata->pvu_des_ks[j][0]); } |
4354 |
else |
4355 |
{ des_set_key(cw[j], cdata->pvu_des_ks[j][1]); } |
4356 |
|
4357 |
cdata->pvu_csa_used = 0; |
4358 |
} |
4359 |
} |
4360 |
#ifdef WITH_EMU |
4361 |
} |
4362 |
|
4363 |
if(cw_ex != NULL) |
4364 |
{ |
4365 |
cw_ex->mode = CW_MODE_MULTIPLE_CW; |
4366 |
|
4367 |
if(csaUsed) |
4368 |
{ |
4369 |
cw_ex->algo = CW_ALGO_CSA; |
4370 |
cw_ex->algo_mode = CW_ALGO_MODE_ECB; |
4371 |
} |
4372 |
else |
4373 |
{ |
4374 |
cw_ex->algo = CW_ALGO_DES; |
4375 |
cw_ex->algo_mode = CW_ALGO_MODE_ECB; |
4376 |
} |
4377 |
|
4378 |
for(j = 0; j < 4; j++) |
4379 |
{ |
4380 |
dwp = cw_ex->audio[j]; |
4381 |
|
4382 |
memset(dwp, 0, 16); |
4383 |
|
4384 |
if(ecm[0] == 0x80) |
4385 |
{ |
4386 |
memcpy(dwp, cw[PVU_CW_A1+j], 8); |
4387 |
|
4388 |
if(csaUsed) |
4389 |
{ |
4390 |
for(k = 0; k < 8; k += 4) |
4391 |
{ |
4392 |
dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); |
4393 |
} |
4394 |
} |
4395 |
} |
4396 |
else |
4397 |
{ |
4398 |
memcpy(&dwp[8], cw[PVU_CW_A1+j], 8); |
4399 |
|
4400 |
if(csaUsed) |
4401 |
{ |
4402 |
for(k = 8; k < 16; k += 4) |
4403 |
{ |
4404 |
dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); |
4405 |
} |
4406 |
} |
4407 |
} |
4408 |
} |
4409 |
|
4410 |
dwp = cw_ex->data; |
4411 |
|
4412 |
memset(dwp, 0, 16); |
4413 |
|
4414 |
if(ecm[0] == 0x80) |
4415 |
{ |
4416 |
memcpy(dwp, cw[PVU_CW_HSD], 8); |
4417 |
|
4418 |
if(csaUsed) |
4419 |
{ |
4420 |
for(k = 0; k < 8; k += 4) |
4421 |
{ |
4422 |
dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); |
4423 |
} |
4424 |
} |
4425 |
} |
4426 |
else |
4427 |
{ |
4428 |
memcpy(&dwp[8], cw[PVU_CW_HSD], 8); |
4429 |
|
4430 |
if(csaUsed) |
4431 |
{ |
4432 |
for(k = 8; k < 16; k += 4) |
4433 |
{ |
4434 |
dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); |
4435 |
} |
4436 |
} |
4437 |
} |
4438 |
} |
4439 |
#endif |
4440 |
} |
4441 |
else |
4442 |
{ |
4443 |
// Calculate only video cw |
4444 |
PowervuCalculateCw(PVU_CW_VID, seed[PVU_CW_VID], csaUsed, convolvedCw[PVU_CW_VID], cw[PVU_CW_VID], baseCw, |
4445 |
seedEcmCw, hashModeCw, needsUnmasking, xorMode); |
4446 |
} |
4447 |
|
4448 |
memset(dw, 0, 16); |
4449 |
|
4450 |
if(ecm[0] == 0x80) |
4451 |
{ |
4452 |
memcpy(dw, cw[PVU_CW_VID], 8); |
4453 |
|
4454 |
if(csaUsed) |
4455 |
{ |
4456 |
for(k = 0; k < 8; k += 4) |
4457 |
{ |
4458 |
dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); |
4459 |
} |
4460 |
} |
4461 |
} |
4462 |
else |
4463 |
{ |
4464 |
memcpy(&dw[8], cw[PVU_CW_VID], 8); |
4465 |
|
4466 |
if(csaUsed) |
4467 |
{ |
4468 |
for(k = 8; k < 16; k += 4) |
4469 |
{ |
4470 |
dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); |
4471 |
} |
4472 |
} |
4473 |
} |
4474 |
|
4475 |
return 0; |
4476 |
|
4477 |
default: |
4478 |
break; |
4479 |
} |
4480 |
i += nanoLen; |
4481 |
} |
4482 |
|
4483 |
return ret; |
4484 |
} |
4485 |
|
4486 |
|
4487 |
// Drecrypt EMU |
4488 |
static void DREover(const uint8_t *ECMdata, uint8_t *dw) |
4489 |
{ |
4490 |
uint8_t key[8]; |
4491 |
uint32_t key_schedule[32]; |
4492 |
|
4493 |
if (ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) |
4494 |
{ |
4495 |
if (!FindKey('D', ECMdata[42] & 0x0F, 0, "OVER", key, 8, 1, 0, 0, NULL)) |
4496 |
{ |
4497 |
return; |
4498 |
} |
4499 |
|
4500 |
des_set_key(key, key_schedule); |
4501 |
|
4502 |
des(dw, key_schedule, 0); // even dw post-process |
4503 |
des(dw + 8, key_schedule, 0); // odd dw post-process |
4504 |
} |
4505 |
} |
4506 |
|
4507 |
static uint32_t DreGostDec(uint32_t inData) |
4508 |
{ |
4509 |
static uint8_t Sbox[128] = |
4510 |
{ |
4511 |
0x0E,0x04,0x0D,0x01,0x02,0x0F,0x0B,0x08,0x03,0x0A,0x06,0x0C,0x05,0x09,0x00,0x07, |
4512 |
0x0F,0x01,0x08,0x0E,0x06,0x0B,0x03,0x04,0x09,0x07,0x02,0x0D,0x0C,0x00,0x05,0x0A, |
4513 |
0x0A,0x00,0x09,0x0E,0x06,0x03,0x0F,0x05,0x01,0x0D,0x0C,0x07,0x0B,0x04,0x02,0x08, |
4514 |
0x07,0x0D,0x0E,0x03,0x00,0x06,0x09,0x0A,0x01,0x02,0x08,0x05,0x0B,0x0C,0x04,0x0F, |
4515 |
0x02,0x0C,0x04,0x01,0x07,0x0A,0x0B,0x06,0x08,0x05,0x03,0x0F,0x0D,0x00,0x0E,0x09, |
4516 |
0x0C,0x01,0x0A,0x0F,0x09,0x02,0x06,0x08,0x00,0x0D,0x03,0x04,0x0E,0x07,0x05,0x0B, |
4517 |
0x04,0x0B,0x02,0x0E,0x0F,0x00,0x08,0x0D,0x03,0x0C,0x09,0x07,0x05,0x0A,0x06,0x01, |
4518 |
0x0D,0x02,0x08,0x04,0x06,0x0F,0x0B,0x01,0x0A,0x09,0x03,0x0E,0x05,0x00,0x0C,0x07 |
4519 |
}; |
4520 |
uint8_t i, j; |
4521 |
|
4522 |
for(i = 0; i < 8; i++) |
4523 |
{ |
4524 |
j = (inData >> 28) & 0x0F; |
4525 |
inData = (inData << 4) | (Sbox[i * 16 + j] & 0x0F); |
4526 |
} |
4527 |
|
4528 |
inData = (inData << 11) | (inData >> 21); |
4529 |
|
4530 |
return (inData); |
4531 |
} |
4532 |
|
4533 |
static void DrecryptDecrypt(uint8_t *Data, uint8_t *Key) // DRE GOST 28147-89 CORE |
4534 |
{ |
4535 |
int i, j; |
4536 |
uint32_t L_part = 0, R_part = 0, temp = 0; |
4537 |
|
4538 |
for(i = 0; i < 4; i++) L_part = (L_part << 8) | (Data[i] & 0xFF), R_part = (R_part << 8) | (Data[i + 4] & 0xFF); |
4539 |
|
4540 |
for(i = 0; i < 4; i++) |
4541 |
{ |
4542 |
temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); |
4543 |
R_part ^= DreGostDec(temp + L_part); |
4544 |
temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); |
4545 |
L_part ^= DreGostDec(temp + R_part); |
4546 |
} |
4547 |
|
4548 |
for(j = 0; j < 3; j++) |
4549 |
{ |
4550 |
for(i = 3; i >= 0; i--) |
4551 |
{ |
4552 |
temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); |
4553 |
R_part ^= DreGostDec(temp + L_part); |
4554 |
temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); |
4555 |
L_part ^= DreGostDec(temp + R_part); |
4556 |
} |
4557 |
} |
4558 |
|
4559 |
for(i = 0; i < 4; i++) Data[i] = (R_part >> i*8) & 0xFF, Data[i+4] = (L_part >> i*8) & 0xFF; |
4560 |
} |
4561 |
|
4562 |
static void DrecryptPostCw(uint8_t* ccw) |
4563 |
{ |
4564 |
uint32_t i, j; |
4565 |
uint8_t tmp[4]; |
4566 |
|
4567 |
for(i = 0; i < 4; i++) |
4568 |
{ |
4569 |
for(j = 0; j < 4; j++) |
4570 |
{ |
4571 |
tmp[j] = ccw[3 - j]; |
4572 |
} |
4573 |
|
4574 |
for(j = 0; j < 4; j++) |
4575 |
{ |
4576 |
ccw[j] = tmp[j]; |
4577 |
} |
4578 |
|
4579 |
ccw += 4; |
4580 |
} |
4581 |
} |
4582 |
|
4583 |
static void DrecryptSwap(uint8_t* ccw) |
4584 |
{ |
4585 |
uint32_t tmp1, tmp2; |
4586 |
|
4587 |
memcpy(&tmp1, ccw, 4); |
4588 |
memcpy(&tmp2, ccw + 4, 4); |
4589 |
|
4590 |
memcpy(ccw, ccw + 8, 8); |
4591 |
|
4592 |
memcpy(ccw + 8 , &tmp1, 4); |
4593 |
memcpy(ccw + 8 + 4, &tmp2, 4); |
4594 |
} |
4595 |
|
4596 |
static int8_t Drecrypt2ECM(uint32_t provId, uint8_t *ecm, uint8_t *dw) |
4597 |
{ |
4598 |
uint8_t ecmDataLen, ccw[16], key[32]; |
4599 |
uint16_t ecmLen, overcryptId; |
4600 |
char keyName[EMU_MAX_CHAR_KEYNAME]; |
4601 |
|
4602 |
ecmLen = GetEcmLen(ecm); |
4603 |
|
4604 |
if (ecmLen < 3) |
4605 |
{ |
4606 |
return 1; // Not supported |
4607 |
} |
4608 |
|
4609 |
ecmDataLen = ecm[2]; |
4610 |
|
4611 |
if (ecmLen < ecmDataLen + 3) |
4612 |
{ |
4613 |
return 4; // Corrupt data |
4614 |
} |
4615 |
|
4616 |
switch (provId & 0xFF) |
4617 |
{ |
4618 |
case 0x11: |
4619 |
{ |
4620 |
if (ecm[3] == 0x56) |
4621 |
{ |
4622 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); |
4623 |
|
4624 |
if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) |
4625 |
{ |
4626 |
return 2; |
4627 |
} |
4628 |
} |
4629 |
else |
4630 |
{ |
4631 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[3]); |
4632 |
|
4633 |
if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) |
4634 |
{ |
4635 |
return 2; |
4636 |
} |
4637 |
} |
4638 |
|
4639 |
break; |
4640 |
} |
4641 |
|
4642 |
case 0x14: |
4643 |
{ |
4644 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); |
4645 |
|
4646 |
if (!FindKey('D', 0x4AE114, 0, keyName, key, 32, 1, 0, 0, NULL)) |
4647 |
{ |
4648 |
return 2; |
4649 |
} |
4650 |
|
4651 |
break; |
4652 |
} |
4653 |
|
4654 |
default: |
4655 |
return 1; |
4656 |
} |
4657 |
|
4658 |
memcpy(ccw, ecm + 13, 16); |
4659 |
|
4660 |
DrecryptPostCw(key); |
4661 |
DrecryptPostCw(key + 16); |
4662 |
|
4663 |
DrecryptDecrypt(ccw, key); |
4664 |
DrecryptDecrypt(ccw + 8, key); |
4665 |
|
4666 |
if (ecm[2] >= 46 && ecm[43] == 1 && provId == 0x11) |
4667 |
{ |
4668 |
DrecryptSwap(ccw); |
4669 |
overcryptId = b2i(2, &ecm[44]); |
4670 |
|
4671 |
Drecrypt2OverCW(overcryptId, ccw); |
4672 |
|
4673 |
if (isValidDCW(ccw)) |
4674 |
{ |
4675 |
memcpy(dw, ccw, 16); |
4676 |
return 0; |
4677 |
} |
4678 |
|
4679 |
return 9; // ICG error |
4680 |
} |
4681 |
|
4682 |
DREover(ecm, ccw); |
4683 |
|
4684 |
if (isValidDCW(ccw)) |
4685 |
{ |
4686 |
DrecryptSwap(ccw); |
4687 |
memcpy(dw, ccw, 16); |
4688 |
return 0; |
4689 |
} |
4690 |
|
4691 |
return 1; |
4692 |
} |
4693 |
|
4694 |
// Tandberg EMU |
4695 |
static uint16_t TandbergChecksum(uint8_t *data, uint8_t length) |
4696 |
{ |
4697 |
// ECM and EMM checksum calculation |
4698 |
// 1. Combine data in 2 byte groups |
4699 |
// 2. Add them together |
4700 |
// 3. Multiply result by itself (power of 7) |
4701 |
// 4. XOR with fixed value 0x17E3 |
4702 |
|
4703 |
uint8_t i; |
4704 |
uint16_t checksum = 0; |
4705 |
|
4706 |
for(i = 0; i < length; i += 2) |
4707 |
{ |
4708 |
checksum += (data[i] << 8) | data[i + 1]; |
4709 |
} |
4710 |
|
4711 |
checksum = checksum * checksum * checksum * checksum * checksum * checksum * checksum; |
4712 |
checksum ^= 0x17E3; |
4713 |
|
4714 |
return checksum; |
4715 |
} |
4716 |
|
4717 |
static int8_t GetTandbergKey(uint32_t keyIndex, char *keyName, uint8_t *key, uint32_t keyLength) |
4718 |
{ |
4719 |
// keyIndex: ecm keys --> entitlementId |
4720 |
// emm keys --> aeskeyIndex |
4721 |
// aes keys --> keyIndex |
4722 |
|
4723 |
// keyName: ecm keys --> "01" |
4724 |
// emm keys --> "MK" or "MK01" |
4725 |
// aes keys --> "AES" |
4726 |
|
4727 |
return FindKey('T', keyIndex, 0, keyName, key, keyLength, 1, 0, 0, NULL); |
4728 |
} |
4729 |
|
4730 |
static int8_t TandbergECM(uint8_t *ecm, uint8_t *dw) |
4731 |
{ |
4732 |
uint8_t nanoType, nanoLength; |
4733 |
uint8_t* nanoData; |
4734 |
uint32_t pos = 3; |
4735 |
uint32_t entitlementId; |
4736 |
uint32_t ks[32]; |
4737 |
uint8_t ecmKey[8]; |
4738 |
uint16_t ecmLen = GetEcmLen(ecm); |
4739 |
|
4740 |
if(ecmLen < 5) |
4741 |
{ |
4742 |
return 1; |
4743 |
} |
4744 |
|
4745 |
do |
4746 |
{ |
4747 |
nanoType = ecm[pos]; |
4748 |
nanoLength = ecm[pos+1]; |
4749 |
|
4750 |
if(pos + 2 + nanoLength > ecmLen) |
4751 |
{ |
4752 |
break; |
4753 |
} |
4754 |
|
4755 |
nanoData = ecm + pos + 2; |
4756 |
|
4757 |
// ECM validation |
4758 |
uint16_t payloadChecksum = (nanoData[nanoLength - 2] << 8) | nanoData[nanoLength - 1]; |
4759 |
uint16_t calculatedChecksum = TandbergChecksum(nanoData, nanoLength - 2); |
4760 |
|
4761 |
if(calculatedChecksum != payloadChecksum) |
4762 |
{ |
4763 |
cs_log("ECM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); |
4764 |
return 8; |
4765 |
} |
4766 |
// End of ECM validation |
4767 |
|
4768 |
switch(nanoType) |
4769 |
{ |
4770 |
case 0xEC: // Director v6 (September 2017) |
4771 |
{ |
4772 |
if(nanoLength != 0x28) |
4773 |
{ |
4774 |
cs_log("WARNING: nanoType EC length (%d) != %d", nanoLength, 0x28); |
4775 |
break; |
4776 |
} |
4777 |
|
4778 |
entitlementId = b2i(4, nanoData); |
4779 |
|
4780 |
if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) |
4781 |
{ |
4782 |
return 2; |
4783 |
} |
4784 |
|
4785 |
cs_log("Active entitlement %.4X", entitlementId); |
4786 |
|
4787 |
// Step 1 - Decrypt DES CBC with ecmKey and iv = { 0 } (equal to nanoED) |
4788 |
uint8_t encryptedData[32] = { 0 }; |
4789 |
memcpy(encryptedData, nanoData + 6, 32); |
4790 |
|
4791 |
uint8_t iv[8] = { 0 }; |
4792 |
des_cbc_decrypt(encryptedData, iv, ecmKey, 32); |
4793 |
|
4794 |
uint8_t nanoMode = nanoData[5]; |
4795 |
|
4796 |
if ((nanoMode & 0x20) == 0) // Old algo |
4797 |
{ |
4798 |
// Step 2 - Create CW (equal to nano ED) |
4799 |
dw[0] = encryptedData[0x05]; |
4800 |
dw[1] = encryptedData[0x19]; |
4801 |
dw[2] = encryptedData[0x1D]; |
4802 |
|
4803 |
dw[4] = encryptedData[0x0B]; |
4804 |
dw[5] = encryptedData[0x12]; |
4805 |
dw[6] = encryptedData[0x1A]; |
4806 |
|
4807 |
dw[8] = encryptedData[0x16]; |
4808 |
dw[9] = encryptedData[0x03]; |
4809 |
dw[10] = encryptedData[0x11]; |
4810 |
|
4811 |
dw[12] = encryptedData[0x18]; |
4812 |
dw[13] = encryptedData[0x10]; |
4813 |
dw[14] = encryptedData[0x0E]; |
4814 |
|
4815 |
return 0; |
4816 |
} |
4817 |
else // New algo (overencryption with AES) |
4818 |
{ |
4819 |
// Step 2 - Prepare data for AES (it is like the creation of CW in nanoED but swapped each 8 bytes) |
4820 |
uint8_t dataEC[16] = { 0 }; |
4821 |
|
4822 |
dataEC[0] = encryptedData[0x02]; |
4823 |
dataEC[1] = encryptedData[0x0E]; |
4824 |
dataEC[2] = encryptedData[0x10]; |
4825 |
dataEC[3] = encryptedData[0x18]; |
4826 |
dataEC[4] = encryptedData[0x09]; |
4827 |
dataEC[5] = encryptedData[0x11]; |
4828 |
dataEC[6] = encryptedData[0x03]; |
4829 |
dataEC[7] = encryptedData[0x16]; |
4830 |
|
4831 |
dataEC[8] = encryptedData[0x13]; |
4832 |
dataEC[9] = encryptedData[0x1A]; |
4833 |
dataEC[10] = encryptedData[0x12]; |
4834 |
dataEC[11] = encryptedData[0x0B]; |
4835 |
dataEC[12] = encryptedData[0x04]; |
4836 |
dataEC[13] = encryptedData[0x1D]; |
4837 |
dataEC[14] = encryptedData[0x19]; |
4838 |
dataEC[15] = encryptedData[0x05]; |
4839 |
|
4840 |
// Step 3 - Decrypt AES CBC with new aesKey and iv 2EBD816A5E749A708AE45ADDD84333DE |
4841 |
uint8_t aesKeyIndex = nanoMode & 0x1F; // 32 possible AES keys |
4842 |
uint8_t aesKey[16] = { 0 }; |
4843 |
|
4844 |
if(!GetTandbergKey(aesKeyIndex, "AES", aesKey, 16)) |
4845 |
{ |
4846 |
return 2; |
4847 |
} |
4848 |
|
4849 |
struct aes_keys aes; |
4850 |
aes_set_key(&aes, (char *)aesKey); |
4851 |
|
4852 |
uint8_t ivAes[16] = { 0x2E, 0xBD, 0x81, 0x6A, 0x5E, 0x74, 0x9A, 0x70, 0x8A, 0xE4, 0x5A, 0xDD, 0xD8, 0x43, 0x33, 0xDE }; |
4853 |
aes_cbc_decrypt(&aes, dataEC, 16, ivAes); |
4854 |
|
4855 |
// Step 4 - Create CW (a simple swap) |
4856 |
uint8_t offset; |
4857 |
for (offset = 0; offset < 16; offset++) |
4858 |
{ |
4859 |
dw[offset] = dataEC[15 - offset]; |
4860 |
} |
4861 |
|
4862 |
return 0; |
4863 |
} |
4864 |
} |
4865 |
|
4866 |
case 0xED: // ECM_TAG_CW_DESCRIPTOR |
4867 |
{ |
4868 |
if(nanoLength != 0x26) |
4869 |
{ |
4870 |
cs_log("WARNING: nanoType ED length (%d) != %d", nanoLength, 0x26); |
4871 |
break; |
4872 |
} |
4873 |
|
4874 |
entitlementId = b2i(4, nanoData); |
4875 |
|
4876 |
if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) |
4877 |
{ |
4878 |
return 2; |
4879 |
} |
4880 |
|
4881 |
cs_log("Active entitlement %.4X", entitlementId); |
4882 |
|
4883 |
uint8_t encryptedData[32] = { 0 }; |
4884 |
memcpy(encryptedData, nanoData + 4, 32); |
4885 |
|
4886 |
uint8_t iv[8] = { 0 }; |
4887 |
des_cbc_decrypt(encryptedData, iv, ecmKey, 32); |
4888 |
|
4889 |
dw[0] = encryptedData[0x05]; |
4890 |
dw[1] = encryptedData[0x19]; |
4891 |
dw[2] = encryptedData[0x1D]; |
4892 |
dw[4] = encryptedData[0x0B]; |
4893 |
dw[5] = encryptedData[0x12]; |
4894 |
dw[6] = encryptedData[0x1A]; |
4895 |
dw[8] = encryptedData[0x16]; |
4896 |
dw[9] = encryptedData[0x03]; |
4897 |
dw[10] = encryptedData[0x11]; |
4898 |
dw[12] = encryptedData[0x18]; |
4899 |
dw[13] = encryptedData[0x10]; |
4900 |
dw[14] = encryptedData[0x0E]; |
4901 |
|
4902 |
return 0; |
4903 |
} |
4904 |
|
4905 |
case 0xEE: // ECM_TAG_CW_DESCRIPTOR |
4906 |
{ |
4907 |
if(nanoLength != 0x16) |
4908 |
{ |
4909 |
cs_log("WARNING: nanoType EE length (%d) != %d", nanoLength, 0x16); |
4910 |
break; |
4911 |
} |
4912 |
|
4913 |
entitlementId = b2i(4, nanoData); |
4914 |
|
4915 |
if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) |
4916 |
{ |
4917 |
return 2; |
4918 |
} |
4919 |
|
4920 |
cs_log("Active entitlement %.4X", entitlementId); |
4921 |
|
4922 |
memcpy(dw, nanoData + 4 + 8, 8); // even |
4923 |
memcpy(dw + 8, nanoData + 4, 8); // odd |
4924 |
|
4925 |
des_set_key(ecmKey, ks); |
4926 |
|
4927 |
des(dw, ks, 0); |
4928 |
des(dw + 8, ks, 0); |
4929 |
|
4930 |
return 0; |
4931 |
} |
4932 |
|
4933 |
default: |
4934 |
cs_log("WARNING: nanoType %.2X not supported", nanoType); |
4935 |
break; |
4936 |
} |
4937 |
|
4938 |
pos += 2 + nanoLength; |
4939 |
|
4940 |
} while (pos < ecmLen); |
4941 |
|
4942 |
return 1; |
4943 |
} |
4944 |
|
4945 |
const char* GetProcessECMErrorReason(int8_t result) |
4946 |
{ |
4947 |
switch(result) { |
4948 |
case 0: |
4949 |
return "No error"; |
4950 |
case 1: |
4951 |
return "ECM not supported"; |
4952 |
case 2: |
4953 |
return "Key not found"; |
4954 |
case 3: |
4955 |
return "Nano80 problem"; |
4956 |
case 4: |
4957 |
return "Corrupt data"; |
4958 |
case 5: |
4959 |
return "CW not found"; |
4960 |
case 6: |
4961 |
return "CW checksum error"; |
4962 |
case 7: |
4963 |
return "Out of memory"; |
4964 |
case 8: |
4965 |
return "ECM checksum error"; |
4966 |
case 9: |
4967 |
return "ICG error"; |
4968 |
default: |
4969 |
return "Unknown"; |
4970 |
} |
4971 |
} |
4972 |
|
4973 |
/* Error codes |
4974 |
0 OK |
4975 |
1 ECM not supported |
4976 |
2 Key not found |
4977 |
3 Nano80 problem |
4978 |
4 Corrupt data |
4979 |
5 CW not found |
4980 |
6 CW checksum error |
4981 |
7 Out of memory |
4982 |
8 ECM checksum error |
4983 |
9 ICG error |
4984 |
*/ |
4985 |
#ifdef WITH_EMU |
4986 |
int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, |
4987 |
uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex) |
4988 |
#else |
4989 |
int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, |
4990 |
uint8_t *dw, uint16_t srvid, uint16_t ecmpid) |
4991 |
#endif |
4992 |
{ |
4993 |
int8_t result = 1, i; |
4994 |
uint8_t ecmCopy[EMU_MAX_ECM_LEN]; |
4995 |
uint16_t ecmLen = 0; |
4996 |
|
4997 |
if(ecmDataLen < 3) { |
4998 |
// accept requests without ecm only for biss |
4999 |
if((caid>>8) != 0x26 && caid != 0xFFFF) { |
5000 |
return 1; |
5001 |
} |
5002 |
} |
5003 |
else { |
5004 |
ecmLen = GetEcmLen(ecm); |
5005 |
} |
5006 |
|
5007 |
if(ecmLen > ecmDataLen) { |
5008 |
return 1; |
5009 |
} |
5010 |
|
5011 |
if(ecmLen > EMU_MAX_ECM_LEN) { |
5012 |
return 1; |
5013 |
} |
5014 |
memcpy(ecmCopy, ecm, ecmLen); |
5015 |
|
5016 |
if((caid >> 8) == 0x0D) { |
5017 |
result = CryptoworksECM(caid, ecmCopy, dw); |
5018 |
} |
5019 |
else if((caid >> 8) == 0x09) { |
5020 |
result = SoftNDSECM(caid, ecmCopy, dw); |
5021 |
} |
5022 |
else if(caid == 0x0500) { |
5023 |
result = ViaccessECM(ecmCopy, dw); |
5024 |
} |
5025 |
else if((caid >> 8) == 0x18) { |
5026 |
result = Nagra2ECM(ecmCopy, dw); |
5027 |
} |
5028 |
else if((caid >> 8) == 0x06) { |
5029 |
result = Irdeto2ECM(caid, ecmCopy, dw); |
5030 |
} |
5031 |
else if((caid >> 8) == 0x26 || caid == 0xFFFF) { |
5032 |
result = BissECM(rdr, ecm, ecmDataLen, dw, srvid, ecmpid); |
5033 |
} |
5034 |
else if((caid >> 8) == 0x0E) { |
5035 |
#ifdef WITH_EMU |
5036 |
result = PowervuECM(ecmCopy, dw, srvid, NULL, cw_ex); |
5037 |
#else |
5038 |
result = PowervuECM(ecmCopy, dw, NULL); |
5039 |
#endif |
5040 |
} |
5041 |
else if(caid == 0x4AE1) { |
5042 |
result = Drecrypt2ECM(provider, ecmCopy, dw); |
5043 |
} |
5044 |
else if((caid >> 8) == 0x10) { |
5045 |
result = TandbergECM(ecmCopy, dw); |
5046 |
} |
5047 |
|
5048 |
// fix dcw checksum |
5049 |
if(result == 0 && !((caid >> 8) == 0x0E)) { |
5050 |
for(i = 0; i < 16; i += 4) { |
5051 |
dw[i + 3] = ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xff); |
5052 |
} |
5053 |
} |
5054 |
|
5055 |
if(result != 0) { |
5056 |
cs_log("ECM failed: %s", GetProcessECMErrorReason(result)); |
5057 |
} |
5058 |
|
5059 |
return result; |
5060 |
} |
5061 |
|
5062 |
// Viaccess EMM EMU |
5063 |
static int8_t ViaccessEMM(uint8_t *emm, uint32_t *keysAdded) |
5064 |
{ |
5065 |
uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp; |
5066 |
uint16_t i = 0, j = 0, k = 0, emmLen = GetEcmLen(emm); |
5067 |
uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17]; |
5068 |
uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D; |
5069 |
uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0; |
5070 |
uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0; |
5071 |
char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; |
5072 |
struct aes_keys aes; |
5073 |
|
5074 |
memset(keyD0, 0, 2); |
5075 |
memset(ecmKeyIndex, 0, sizeof(uint32_t)*6); |
5076 |
|
5077 |
for(i=3; i+2<emmLen; ) { |
5078 |
nanoCmd = emm[i++]; |
5079 |
nanoLen = emm[i++]; |
5080 |
if(i+nanoLen > emmLen) { |
5081 |
return 1; |
5082 |
} |
5083 |
|
5084 |
switch(nanoCmd) { |
5085 |
case 0x90: { |
5086 |
if(nanoLen < 3) { |
5087 |
break; |
5088 |
} |
5089 |
ui1 = emm[i+2]; |
5090 |
ui2 = emm[i+1]; |
5091 |
ui3 = emm[i]; |
5092 |
provider = (ui1 | (ui2 << 8) | (ui3 << 16)); |
5093 |
if(provider == 0x00D00040) { |
5094 |
ecmProvider = 0x030B00; |
5095 |
} |
5096 |
else { |
5097 |
return 1; |
5098 |
} |
5099 |
break; |
5100 |
} |
5101 |
case 0xD2: { |
5102 |
if(nanoLen < 2) { |
5103 |
break; |
5104 |
} |
5105 |
emmKeyIndex = emm[i+1]; |
5106 |
break; |
5107 |
} |
5108 |
case 0x41: { |
5109 |
if(nanoLen < 1) { |
5110 |
break; |
5111 |
} |
5112 |
if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { |
5113 |
return 2; |
5114 |
} |
5115 |
memset(provName, 0, 17); |
5116 |
memset(emmXorKey, 0, 16); |
5117 |
k = nanoLen < 16 ? nanoLen : 16; |
5118 |
memcpy(provName, &emm[i], k); |
5119 |
aes_set_key(&aes, (char*)emmKey); |
5120 |
aes_decrypt(&aes, emmXorKey, 16); |
5121 |
for(j=0; j<16; j++) { |
5122 |
provName[j] ^= emmXorKey[j]; |
5123 |
} |
5124 |
provName[k] = 0; |
5125 |
|
5126 |
if(strcmp((char*)provName, "TNTSAT") != 0 && strcmp((char*)provName, "TNTSATPRO") != 0 |
5127 |
&&strcmp((char*)provName, "CSAT V") != 0) { |
5128 |
return 1; |
5129 |
} |
5130 |
break; |
5131 |
} |
5132 |
case 0xBA: { |
5133 |
if(nanoLen < 2) { |
5134 |
break; |
5135 |
} |
5136 |
GetViaKey(keyD0, ecmProvider, 'D', 0, 2, 0); |
5137 |
ui1 = (emm[i] << 8) | emm[i+1]; |
5138 |
if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) { |
5139 |
keyD0[0] = emm[i]; |
5140 |
keyD0[1] = emm[i+1]; |
5141 |
haveNewD0 = 1; |
5142 |
break; |
5143 |
} |
5144 |
return 0; |
5145 |
} |
5146 |
case 0xBC: { |
5147 |
break; |
5148 |
} |
5149 |
case 0x43: { |
5150 |
if(nanoLen < 16) { |
5151 |
break; |
5152 |
} |
5153 |
memcpy(emmXorKey, &emm[i], 16); |
5154 |
haveEmmXorKey = 1; |
5155 |
break; |
5156 |
} |
5157 |
case 0x44: { |
5158 |
if(nanoLen < 3) { |
5159 |
break; |
5160 |
} |
5161 |
if (!haveEmmXorKey) { |
5162 |
memset(emmXorKey, 0, 16); |
5163 |
} |
5164 |
tmp = (uint8_t*)malloc(((nanoLen/16)+1)*16*sizeof(uint8_t)); |
5165 |
if(tmp == NULL) { |
5166 |
return 7; |
5167 |
} |
5168 |
memcpy(tmp, &emm[i], nanoLen); |
5169 |
aes_set_key(&aes, (char*)emmKey); |
5170 |
for(j=0; j<nanoLen; j+=16) { |
5171 |
aes_decrypt(&aes, emmXorKey, 16); |
5172 |
for(k=0; k<16; k++) { |
5173 |
tmp[j+k] ^= emmXorKey[k]; |
5174 |
} |
5175 |
} |
5176 |
memcpy(&emm[i-2], tmp, nanoLen); |
5177 |
free(tmp); |
5178 |
nanoLen = 0; |
5179 |
i -= 2; |
5180 |
break; |
5181 |
} |
5182 |
case 0x68: { |
5183 |
if(ecmKeyCount > 5) { |
5184 |
break; |
5185 |
} |
5186 |
for(j=i; j+2<i+nanoLen; ) { |
5187 |
subNanoCmd = emm[j++]; |
5188 |
subNanoLen = emm[j++]; |
5189 |
if(j+subNanoLen > i+nanoLen) { |
5190 |
break; |
5191 |
} |
5192 |
switch(subNanoCmd) { |
5193 |
case 0xD2: { |
5194 |
if(nanoLen < 2) { |
5195 |
break; |
5196 |
} |
5197 |
aesMode = emm[j]; |
5198 |
emmKeyIndex = emm[j+1]; |
5199 |
break; |
5200 |
} |
5201 |
case 0x01: { |
5202 |
if(nanoLen < 17) { |
5203 |
break; |
5204 |
} |
5205 |
ecmKeyIndex[ecmKeyCount] = emm[j]; |
5206 |
memcpy(&ecmKeys[ecmKeyCount], &emm[j+1], 16); |
5207 |
if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { |
5208 |
break; |
5209 |
} |
5210 |
|
5211 |
if(aesMode == 0x0F || aesMode == 0x11) { |
5212 |
hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); |
5213 |
hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]); |
5214 |
} |
5215 |
else if(aesMode == 0x13 || aesMode == 0x15) { |
5216 |
hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]); |
5217 |
} |
5218 |
aes_set_key(&aes, (char*)emmKey); |
5219 |
aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16); |
5220 |
if(aesMode == 0x0F || aesMode == 0x11) { |
5221 |
hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); |
5222 |
} |
5223 |
else if(aesMode == 0x13 || aesMode == 0x15) { |
5224 |
hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]); |
5225 |
} |
5226 |
|
5227 |
ecmKeyCount++; |
5228 |
break; |
5229 |
} |
5230 |
default: |
5231 |
break; |
5232 |
} |
5233 |
j += subNanoLen; |
5234 |
} |
5235 |
break; |
5236 |
} |
5237 |
case 0xF0: { |
5238 |
if(nanoLen != 4) { |
5239 |
break; |
5240 |
} |
5241 |
ui1 = ((emm[i+2] << 8) | (emm[i+1] << 16) | (emm[i] << 24) | emm[i+3]); |
5242 |
if(fletcher_crc32(emm + 3, emmLen - 11) != ui1) { |
5243 |
return 4; |
5244 |
} |
5245 |
|
5246 |
if(haveNewD0) { |
5247 |
|
5248 |
SetKey('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL); |
5249 |
|
5250 |
for(j=0; j<ecmKeyCount; j++) { |
5251 |
|
5252 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "E%X", ecmKeyIndex[j]); |
5253 |
SetKey('V', ecmProvider, keyName, ecmKeys[j], 16, 1, NULL, NULL); |
5254 |
|
5255 |
(*keysAdded)++; |
5256 |
cs_hexdump(0, ecmKeys[j], 16, keyValue, sizeof(keyValue)); |
5257 |
cs_log("Key found in EMM: V %06X %s %s", ecmProvider, keyName, keyValue); |
5258 |
} |
5259 |
} |
5260 |
break; |
5261 |
} |
5262 |
default: |
5263 |
break; |
5264 |
} |
5265 |
i += nanoLen; |
5266 |
} |
5267 |
return 0; |
5268 |
} |
5269 |
|
5270 |
// Irdeto2 EMM EMU |
5271 |
static int8_t Irdeto2DoEMMTypeOP(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, |
5272 |
uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) |
5273 |
{ |
5274 |
uint32_t end, i, l; |
5275 |
uint8_t tmp[16]; |
5276 |
char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; |
5277 |
|
5278 |
memset(tmp, 0, 16); |
5279 |
Irdeto2Encrypt(keySeed, tmp, keyPMK, 16); |
5280 |
Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); |
5281 |
|
5282 |
i = 16; |
5283 |
end = startOffset + (length-8 < 0 ? 0 : length-8); |
5284 |
|
5285 |
while(i<end) { |
5286 |
l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; |
5287 |
switch(emm[i]) { |
5288 |
case 0x10: |
5289 |
case 0x50: |
5290 |
if(l==0x13 && i<=startOffset+length-8-l) { |
5291 |
Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16); |
5292 |
} |
5293 |
break; |
5294 |
case 0x78: |
5295 |
if(l==0x14 && i<=startOffset+length-8-l) { |
5296 |
Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16); |
5297 |
} |
5298 |
break; |
5299 |
} |
5300 |
i+=l; |
5301 |
} |
5302 |
|
5303 |
memmove(emm+6, emm+7, emmLen-7); |
5304 |
|
5305 |
i = 15; |
5306 |
end = startOffset + (length-9 < 0 ? 0 : length-9); |
5307 |
|
5308 |
if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-4)) { |
5309 |
while(i<end) { |
5310 |
l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; |
5311 |
switch(emm[i]) { |
5312 |
case 0x10: |
5313 |
case 0x50: |
5314 |
if(l==0x13 && i<=startOffset+length-9-l) { |
5315 |
|
5316 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X", emm[i+2]>>2); |
5317 |
SetKey('I', ident, keyName, &emm[i+3], 16, 1, NULL, NULL); |
5318 |
|
5319 |
(*keysAdded)++; |
5320 |
cs_hexdump(0, &emm[i+3], 16, keyValue, sizeof(keyValue)); |
5321 |
cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); |
5322 |
} |
5323 |
} |
5324 |
i+=l; |
5325 |
} |
5326 |
|
5327 |
if(*keysAdded > 0) { |
5328 |
return 0; |
5329 |
} |
5330 |
} |
5331 |
|
5332 |
return 1; |
5333 |
} |
5334 |
|
5335 |
static int8_t Irdeto2DoEMMTypePMK(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, |
5336 |
uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) |
5337 |
{ |
5338 |
uint32_t end, i, l, j; |
5339 |
char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; |
5340 |
|
5341 |
Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); |
5342 |
|
5343 |
i = 13; |
5344 |
end = startOffset + (length-8 < 0 ? 0 : length-8); |
5345 |
|
5346 |
while(i<end) { |
5347 |
l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; |
5348 |
switch(emm[i]) { |
5349 |
case 0x10: |
5350 |
case 0x50: |
5351 |
if(l==0x13 && i<=startOffset+length-8-l) { |
5352 |
Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16); |
5353 |
} |
5354 |
break; |
5355 |
case 0x78: |
5356 |
if(l==0x14 && i<=startOffset+length-8-l) { |
5357 |
Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16); |
5358 |
} |
5359 |
break; |
5360 |
case 0x68: |
5361 |
if(l==0x26 && i<=startOffset+length-8-l) { |
5362 |
Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16*2); |
5363 |
} |
5364 |
break; |
5365 |
} |
5366 |
i+=l; |
5367 |
} |
5368 |
|
5369 |
memmove(emm+7, emm+9, emmLen-9); |
5370 |
|
5371 |
i = 11; |
5372 |
end = startOffset + (length-10 < 0 ? 0 : length-10); |
5373 |
|
5374 |
if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-5)) { |
5375 |
while(i<end) { |
5376 |
l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; |
5377 |
switch(emm[i]) { |
5378 |
case 0x68: |
5379 |
if(l==0x26 && i<=startOffset+length-10-l) { |
5380 |
for(j=0; j<2; j++) { |
5381 |
|
5382 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "M%01X", 3+j); |
5383 |
SetKey('I', ident, keyName, &emm[i+3+j*16], 16, 1, NULL, NULL); |
5384 |
|
5385 |
(*keysAdded)++; |
5386 |
cs_hexdump(0, &emm[i+3+j*16], 16, keyValue, sizeof(keyValue)); |
5387 |
cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); |
5388 |
} |
5389 |
} |
5390 |
} |
5391 |
i+=l; |
5392 |
} |
5393 |
|
5394 |
if(*keysAdded > 0) { |
5395 |
return 0; |
5396 |
} |
5397 |
} |
5398 |
|
5399 |
return 1; |
5400 |
} |
5401 |
|
5402 |
static const uint8_t fausto_xor[16] = { 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D }; |
5403 |
|
5404 |
static int8_t Irdeto2EMM(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded) |
5405 |
{ |
5406 |
uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType; |
5407 |
uint32_t ident; |
5408 |
uint32_t keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef; |
5409 |
uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm; |
5410 |
uint16_t emmLen = GetEcmLen(emm); |
5411 |
|
5412 |
if(emmLen < 11) { |
5413 |
return 1; |
5414 |
} |
5415 |
|
5416 |
if(emm[3] == 0xC3 || emm[3] == 0xCB) { |
5417 |
emmType = 2; |
5418 |
startOffset = 11; |
5419 |
} |
5420 |
else { |
5421 |
emmType = 1; |
5422 |
startOffset = 10; |
5423 |
} |
5424 |
|
5425 |
ident = emm[startOffset-2] | caid << 8; |
5426 |
length = emm[startOffset-1]; |
5427 |
|
5428 |
|
5429 |
if(emmLen < length+startOffset) { |
5430 |
return 1; |
5431 |
} |
5432 |
|
5433 |
keySeedRef = 0; |
5434 |
while(GetIrdetoKey(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) { |
5435 |
keyIVRef = 0; |
5436 |
while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { |
5437 |
|
5438 |
keyPMK0Ref = 0; |
5439 |
keyPMK1Ref = 0; |
5440 |
keyPMK0ERef = 0; |
5441 |
keyPMK1ERef = 0; |
5442 |
|
5443 |
while(GetIrdetoKey(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) { |
5444 |
memcpy(keySeed, okeySeed, 16); |
5445 |
memcpy(emmCopy, oemm, emmLen); |
5446 |
emm = emmCopy; |
5447 |
if(emmType == 1) { |
5448 |
if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { |
5449 |
return 0; |
5450 |
} |
5451 |
} |
5452 |
else { |
5453 |
if(Irdeto2DoEMMTypePMK(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { |
5454 |
return 0; |
5455 |
} |
5456 |
} |
5457 |
} |
5458 |
|
5459 |
if(emmType == 1) { |
5460 |
while(GetIrdetoKey(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) { |
5461 |
memcpy(keySeed, okeySeed, 16); |
5462 |
memcpy(emmCopy, oemm, emmLen); |
5463 |
emm = emmCopy; |
5464 |
if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { |
5465 |
return 0; |
5466 |
} |
5467 |
} |
5468 |
|
5469 |
while(GetIrdetoKey(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) { |
5470 |
xxor(keyPMK, 16, keyPMK, fausto_xor); |
5471 |
memcpy(keySeed, okeySeed, 16); |
5472 |
memcpy(emmCopy, oemm, emmLen); |
5473 |
emm = emmCopy; |
5474 |
if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { |
5475 |
return 0; |
5476 |
} |
5477 |
} |
5478 |
|
5479 |
while(GetIrdetoKey(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) { |
5480 |
xxor(keyPMK, 16, keyPMK, fausto_xor); |
5481 |
memcpy(keySeed, okeySeed, 16); |
5482 |
memcpy(emmCopy, oemm, emmLen); |
5483 |
emm = emmCopy; |
5484 |
if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { |
5485 |
return 0; |
5486 |
} |
5487 |
} |
5488 |
} |
5489 |
|
5490 |
if(keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) { |
5491 |
return 2; |
5492 |
} |
5493 |
} |
5494 |
if(keyIVRef == 0) { |
5495 |
return 2; |
5496 |
} |
5497 |
} |
5498 |
if(keySeedRef == 0) { |
5499 |
return 2; |
5500 |
} |
5501 |
|
5502 |
return 1; |
5503 |
} |
5504 |
|
5505 |
int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t *hexserial) |
5506 |
{ |
5507 |
uint32_t i, len; |
5508 |
KeyDataContainer *KeyDB; |
5509 |
KeyData *tmpKeyData; |
5510 |
|
5511 |
KeyDB = GetKeyContainer('I'); |
5512 |
if(KeyDB == NULL) { |
5513 |
return 0; |
5514 |
} |
5515 |
|
5516 |
for(i=0; i<KeyDB->keyCount; i++) { |
5517 |
|
5518 |
if(KeyDB->EmuKeys[i].provider>>8 != caid) { |
5519 |
continue; |
5520 |
} |
5521 |
if(strcmp(KeyDB->EmuKeys[i].keyName, "MC")) { |
5522 |
continue; |
5523 |
} |
5524 |
|
5525 |
tmpKeyData = &KeyDB->EmuKeys[i]; |
5526 |
|
5527 |
len = tmpKeyData->keyLength; |
5528 |
if(len > 3) |
5529 |
{ len = 3; } |
5530 |
|
5531 |
memcpy(hexserial+(3-len), tmpKeyData->key, len); |
5532 |
return 1; |
5533 |
} |
5534 |
|
5535 |
return 0; |
5536 |
} |
5537 |
|
5538 |
|
5539 |
// PowerVu EMM EMU |
5540 |
static void PowervuUnmaskEmm(uint8_t *emm) |
5541 |
{ |
5542 |
int i, l; |
5543 |
|
5544 |
uint8_t sourcePos[] = {0x03, 0x0C, 0x0D, 0x11, 0x15, 0x18, 0x1D, 0x1F, 0x25, 0x2A, 0x32, 0x35, 0x3A, 0x3B, 0x3E, |
5545 |
0x42, 0x47, 0x48, 0x53, 0x58, 0x5C, 0x61, 0x66, 0x69, 0x71, 0x72, 0x78, 0x7B, 0x81, 0x84}; |
5546 |
|
5547 |
uint8_t destPos[] = {0x02, 0x08, 0x0B, 0x0E, 0x13, 0x16, 0x1E, 0x23, 0x28, 0x2B, 0x2F, 0x33, 0x38, 0x3C, 0x40, |
5548 |
0x44, 0x4A, 0x4D, 0x54, 0x57, 0x5A, 0x63, 0x68, 0x6A, 0x70, 0x75, 0x76, 0x7D, 0x82, 0x85}; |
5549 |
|
5550 |
uint8_t data[0x1E]; |
5551 |
uint8_t hashModeEmm; |
5552 |
uint8_t mask[0x10]; |
5553 |
uint32_t crc; |
5554 |
|
5555 |
// Create Mask for ECM decryption |
5556 |
PowervuCreateDataEcmEmm(emm, sourcePos, 0x13, 0x1E, data); |
5557 |
|
5558 |
hashModeEmm = emm[8] ^ PowervuCrc8Calc(data, 0x1E); |
5559 |
|
5560 |
PowervuCreateHash(data, 0x1E, mask, hashModeEmm); |
5561 |
|
5562 |
// Fix Header |
5563 |
emm[3] &= 0x0F; |
5564 |
emm[3] |= 0x10; |
5565 |
emm[8] = 0x00; |
5566 |
|
5567 |
// Unmask Body |
5568 |
for(i = 0; i < 0x1E; i++) |
5569 |
{ |
5570 |
emm[0x13 + destPos[i]] ^= mask[i & 0x0F]; |
5571 |
} |
5572 |
|
5573 |
// Fix CRC (optional) |
5574 |
l = (((emm[1] << 8) + emm[2]) & 0xFFF) + 3 - 4; |
5575 |
crc = fletcher_crc32(emm, l); |
5576 |
|
5577 |
emm[l + 0] = crc >> 24; |
5578 |
emm[l + 1] = crc >> 16; |
5579 |
emm[l + 2] = crc >> 8; |
5580 |
emm[l + 3] = crc >> 0; |
5581 |
} |
5582 |
|
5583 |
static int8_t PowervuEMM(uint8_t *emm, uint32_t *keysAdded) |
5584 |
{ |
5585 |
uint8_t emmInfo, emmType, decryptOk = 0; |
5586 |
uint16_t emmLen = GetEcmLen(emm); |
5587 |
uint32_t i, uniqueAddress, groupId, keyRef = 0; |
5588 |
//uint32_t emmCrc32; |
5589 |
uint8_t emmKey[7], tmpEmmKey[7], tmp[26]; |
5590 |
char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[16]; |
5591 |
char uaInfo[4+8+1]; |
5592 |
|
5593 |
if(emmLen < 50) |
5594 |
{ |
5595 |
return 1; |
5596 |
} |
5597 |
|
5598 |
// Check if unmasking is needed |
5599 |
if((emm[3] & 0xF0) == 0x50) |
5600 |
{ |
5601 |
PowervuUnmaskEmm(emm); |
5602 |
} |
5603 |
|
5604 |
// looks like checksum does not work for all EMMs |
5605 |
//emmCrc32 = b2i(4, emm+emmLen-4); |
5606 |
// |
5607 |
//if(fletcher_crc32(emm, emmLen-4) != emmCrc32) |
5608 |
//{ |
5609 |
// return 8; |
5610 |
//} |
5611 |
emmLen -= 4; |
5612 |
|
5613 |
uniqueAddress = b2i(4, emm+12); |
5614 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.8X", uniqueAddress); |
5615 |
|
5616 |
do |
5617 |
{ |
5618 |
if(!GetPowervuEmmKey(emmKey, 0, keyName, 7, 0, keyRef++, &groupId)) |
5619 |
{ |
5620 |
cs_log_dbg(D_EMM, "EMM error: AU key for UA %s is missing", keyName); |
5621 |
return 2; |
5622 |
} |
5623 |
|
5624 |
for(i=19; i+27<=emmLen; i+=27) { |
5625 |
emmInfo = emm[i]; |
5626 |
|
5627 |
if(!GetBit(emmInfo, 7)) |
5628 |
{ |
5629 |
continue; |
5630 |
} |
5631 |
|
5632 |
//keyNb = emm[i] & 0x0F; |
5633 |
|
5634 |
memcpy(tmp, emm+i+1, 26); |
5635 |
memcpy(tmpEmmKey, emmKey, 7); |
5636 |
PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 0); |
5637 |
|
5638 |
if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) |
5639 |
{ |
5640 |
memcpy(emm+i+1, tmp, 26); |
5641 |
memcpy(tmpEmmKey, emmKey, 7); |
5642 |
PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 1); |
5643 |
|
5644 |
if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) |
5645 |
{ |
5646 |
memcpy(emm+i+1, tmp, 26); |
5647 |
memcpy(tmpEmmKey, emmKey, 7); |
5648 |
continue; |
5649 |
} |
5650 |
} |
5651 |
|
5652 |
decryptOk = 1; |
5653 |
|
5654 |
emmType = emm[i+2] & 0x7F; |
5655 |
if(emmType > 1) |
5656 |
{ |
5657 |
continue; |
5658 |
} |
5659 |
|
5660 |
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType); |
5661 |
snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress); |
5662 |
|
5663 |
if(emm[i+3] == 0 && emm[i+4] == 0) |
5664 |
{ |
5665 |
cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); |
5666 |
cs_log("Key found in EMM: P %.4X**** %s %s -> REJECTED (looks invalid) UA: %.8X", groupId, keyName, keyValue, uniqueAddress); |
5667 |
continue; |
5668 |
} |
5669 |
|
5670 |
UpdateKeysByProviderMask('P', groupId<<16, 0x0000FFFF, keyName, &emm[i+3], 7, uaInfo); |
5671 |
|
5672 |
(*keysAdded)++; |
5673 |
cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); |
5674 |
cs_log("Key found in EMM: P %.4X**** %s %s ; UA: %.8X", groupId, keyName, keyValue, uniqueAddress); |
5675 |
} |
5676 |
|
5677 |
} while(!decryptOk); |
5678 |
|
5679 |
return 0; |
5680 |
} |
5681 |
|
5682 |
int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count) |
5683 |
{ |
5684 |
//srvid == 0xFFFF -> get all |
5685 |
|
5686 |
uint32_t i, j; |
5687 |
uint32_t groupid; |
5688 |
int32_t len, k; |
5689 |
KeyDataContainer *KeyDB; |
5690 |
uint8_t tmp[4]; |
5691 |
int8_t alreadyAdded; |
5692 |
|
5693 |
KeyDB = GetKeyContainer('P'); |
5694 |
if(KeyDB == NULL) |
5695 |
{ return 0; } |
5696 |
|
5697 |
(*count) = 0; |
5698 |
|
5699 |
for(i=0; i<KeyDB->keyCount && (*count)<length ; i++) { |
5700 |
|
5701 |
if(KeyDB->EmuKeys[i].provider <= 0x0000FFFF) // skip au keys |
5702 |
{ continue; } |
5703 |
|
5704 |
if(srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid) |
5705 |
{ continue; } |
5706 |
|
5707 |
groupid = KeyDB->EmuKeys[i].provider>>16; |
5708 |
|
5709 |
for(j=0; j<KeyDB->keyCount && (*count)<length ; j++) { |
5710 |
|
5711 |
if(KeyDB->EmuKeys[j].provider != groupid) // search au key with groupip |
5712 |
{ continue; } |
5713 |
|
5714 |
len = strlen(KeyDB->EmuKeys[j].keyName); |
5715 |
|
5716 |
if(len < 3) |
5717 |
{ continue;} |
5718 |
|
5719 |
if(len > 8) |
5720 |
{ len = 8; } |
5721 |
|
5722 |
memset(tmp, 0, 4); |
5723 |
CharToBin(tmp+(4-(len/2)), KeyDB->EmuKeys[j].keyName, len); |
5724 |
|
5725 |
for(k=0, alreadyAdded=0; k<*count; k++) |
5726 |
{ |
5727 |
if(!memcmp(hexserials[k], tmp, 4)) |
5728 |
{ |
5729 |
alreadyAdded = 1; |
5730 |
break; |
5731 |
} |
5732 |
} |
5733 |
|
5734 |
if(!alreadyAdded) |
5735 |
{ |
5736 |
memcpy(hexserials[*count], tmp, 4); |
5737 |
(*count)++; |
5738 |
} |
5739 |
} |
5740 |
|
5741 |
} |
5742 |
|
5743 |
return 1; |
5744 |
} |
5745 |
|
5746 |
// Drecrypt EMM EMU |
5747 |
static int8_t DrecryptGetEmmKey(uint8_t *buf, uint32_t keyIdent, uint16_t keyName, uint8_t isCriticalKey) |
5748 |
{ |
5749 |
char keyStr[EMU_MAX_CHAR_KEYNAME]; |
5750 |
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "MK%04X", keyName); |
5751 |
return FindKey('D', keyIdent, 0, keyStr, buf, 32, isCriticalKey, 0, 0, NULL); |
5752 |
} |
5753 |
|
5754 |
static void DrecryptWriteEebin(const char *path, const char *name) |
5755 |
{ |
5756 |
char tmp[256]; |
5757 |
FILE *file = NULL; |
5758 |
uint8_t i, buffer[64][32]; |
5759 |
uint32_t prvid; |
5760 |
|
5761 |
// Set path |
5762 |
if (path != NULL) |
5763 |
{ |
5764 |
snprintf(tmp, 256, "%s%s", path, name); |
5765 |
} |
5766 |
else // No path set, use SoftCam.Keys's path |
5767 |
{ |
5768 |
snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); |
5769 |
} |
5770 |
|
5771 |
if ((file = fopen(tmp, "wb")) != NULL) |
5772 |
{ |
5773 |
cs_log("Writing key file: %s", tmp); |
5774 |
} |
5775 |
else |
5776 |
{ |
5777 |
cs_log("Error writing key file: %s", tmp); |
5778 |
return; |
5779 |
} |
5780 |
|
5781 |
// Load keys from db to buffer |
5782 |
prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; |
5783 |
|
5784 |
for (i = 0; i < 32; i++) // Load "3B" type keys |
5785 |
{ |
5786 |
snprintf(tmp, 5, "3B%02X", i); |
5787 |
if (!FindKey('D', prvid, 0, tmp, buffer[i], 32, 0, 0, 0, NULL)) |
5788 |
{ |
5789 |
memset(buffer[i], 0xFF, 32); |
5790 |
} |
5791 |
} |
5792 |
|
5793 |
for (i = 0; i < 32; i++) // Load "56" type keys |
5794 |
{ |
5795 |
snprintf(tmp, 5, "56%02X", i); |
5796 |
if (!FindKey('D', prvid, 0, tmp, buffer[32 + i], 32, 0, 0, 0, NULL)) |
5797 |
{ |
5798 |
memset(buffer[32 + i], 0xFF, 32); |
5799 |
} |
5800 |
} |
5801 |
|
5802 |
// Write buffer to ee.bin file |
5803 |
fwrite(buffer, 1, sizeof(buffer), file); |
5804 |
fclose(file); |
5805 |
} |
5806 |
|
5807 |
static int8_t DrecryptProcessEMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) |
5808 |
{ |
5809 |
uint16_t emmLen, emmDataLen; |
5810 |
uint32_t i, keyIdent; |
5811 |
uint16_t keyName; |
5812 |
uint8_t emmKey[32]; |
5813 |
uint8_t *curECMkey3B = NULL, *curECMkey56 = NULL; |
5814 |
uint8_t keynum =0, keyidx = 0, keyclass = 0, key1offset, key2offset; |
5815 |
char newKeyName[EMU_MAX_CHAR_KEYNAME], curKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100]; |
5816 |
|
5817 |
emmDataLen = GetEcmLen(emm); |
5818 |
emmLen = ((emm[1] & 0xF) << 8) | emm[2]; |
5819 |
|
5820 |
if (emmDataLen < emmLen + 3) |
5821 |
{ |
5822 |
return 4; // Corrupt data |
5823 |
} |
5824 |
|
5825 |
if (emm[0] == 0x91) |
5826 |
{ |
5827 |
Drecrypt2OverEMM(emm); |
5828 |
return 0; |
5829 |
} |
5830 |
else if (emm[0] == 0x82) |
5831 |
{ |
5832 |
ReasmEMM82(emm); |
5833 |
return 0; |
5834 |
} |
5835 |
else if (emm[0] != 0x86) |
5836 |
{ |
5837 |
return 1; // Not supported |
5838 |
} |
5839 |
|
5840 |
// Emm type 0x86 only |
5841 |
switch (emm[4]) |
5842 |
{ |
5843 |
case 0x02: |
5844 |
keynum = 0x2C; |
5845 |
keyidx = 0x30; |
5846 |
keyclass = 0x26; |
5847 |
key1offset = 0x35; |
5848 |
key2offset = 0x6D; |
5849 |
break; |
5850 |
|
5851 |
case 0x4D: |
5852 |
keynum = 0x61; |
5853 |
keyidx = 0x60; |
5854 |
keyclass = 0x05; |
5855 |
key1offset = 0x62; |
5856 |
key2offset = 0x8B; |
5857 |
break; |
5858 |
|
5859 |
default: |
5860 |
return 1; // Not supported |
5861 |
} |
5862 |
|
5863 |
switch (provId & 0xFF) |
5864 |
{ |
5865 |
case 0x11: |
5866 |
{ |
5867 |
snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); |
5868 |
FindKey('D', 0x4AE111, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); |
5869 |
|
5870 |
snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); |
5871 |
FindKey('D', 0x4AE111, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); |
5872 |
|
5873 |
break; |
5874 |
} |
5875 |
|
5876 |
case 0x14: |
5877 |
{ |
5878 |
snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); |
5879 |
FindKey('D', 0x4AE114, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); |
5880 |
|
5881 |
snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); |
5882 |
FindKey('D', 0x4AE114, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); |
5883 |
|
5884 |
break; |
5885 |
} |
5886 |
|
5887 |
default: |
5888 |
return 9; // Wrong provider |
5889 |
} |
5890 |
|
5891 |
keyIdent = (0x4AE1 << 8) | provId; |
5892 |
keyName = (emm[3] << 8) | emm[keynum]; |
5893 |
|
5894 |
if (!DrecryptGetEmmKey(emmKey, keyIdent, keyName, 1)) |
5895 |
{ |
5896 |
return 2; |
5897 |
} |
5898 |
|
5899 |
// Key #1 |
5900 |
for (i = 0; i < 4; i++) |
5901 |
{ |
5902 |
DrecryptDecrypt(&emm[key1offset + (i * 8)], emmKey); |
5903 |
} |
5904 |
|
5905 |
// Key #2 |
5906 |
for (i = 0; i < 4; i++) |
5907 |
{ |
5908 |
DrecryptDecrypt(&emm[key2offset + (i * 8)], emmKey); |
5909 |
} |
5910 |
|
5911 |
// Key #1 |
5912 |
keyName = emm[keyidx] << 8 | emm[keyclass]; |
5913 |
snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); |
5914 |
|
5915 |
if (memcmp(&emm[key1offset], emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, 32) != 0) |
5916 |
{ |
5917 |
memcpy(emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, &emm[key1offset], 32); |
5918 |
SetKey('D', keyIdent, newKeyName, &emm[key1offset], 32, 0, NULL, NULL); |
5919 |
(*keysAdded)++; |
5920 |
|
5921 |
cs_hexdump(0, &emm[key1offset], 32, keyValue, sizeof(keyValue)); |
5922 |
cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); |
5923 |
} |
5924 |
else |
5925 |
{ |
5926 |
cs_log("Key %.6X %s already exists", keyIdent, newKeyName); |
5927 |
} |
5928 |
|
5929 |
// Key #2 |
5930 |
keyName = (emm[keyidx] == 0x56 ? 0x3B00 : 0x5600) | emm[keyclass]; |
5931 |
snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); |
5932 |
|
5933 |
if (memcmp(&emm[key2offset], emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, 32) != 0) |
5934 |
{ |
5935 |
memcpy(emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, &emm[key2offset], 32); |
5936 |
SetKey('D', keyIdent, newKeyName, &emm[key2offset], 32, 0, NULL, NULL); |
5937 |
(*keysAdded)++; |
5938 |
|
5939 |
cs_hexdump(0, &emm[key2offset], 32, keyValue, sizeof(keyValue)); |
5940 |
cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); |
5941 |
} |
5942 |
else |
5943 |
{ |
5944 |
cs_log("Key %.6X %s already exists", keyIdent, newKeyName); |
5945 |
} |
5946 |
|
5947 |
if (*keysAdded > 0) // Write new ecm keys to ee.bin file |
5948 |
{ |
5949 |
switch (provId & 0xFF) |
5950 |
{ |
5951 |
case 0x11: |
5952 |
DrecryptWriteEebin(rdr->extee36, "ee36.bin"); |
5953 |
break; |
5954 |
|
5955 |
case 0x14: |
5956 |
DrecryptWriteEebin(rdr->extee56, "ee56.bin"); |
5957 |
break; |
5958 |
|
5959 |
default: |
5960 |
cs_log("Provider %02X doesn't have a matching ee.bin file", provId & 0xFF); |
5961 |
break; |
5962 |
} |
5963 |
} |
5964 |
|
5965 |
return 0; |
5966 |
} |
5967 |
|
5968 |
static int8_t Drecrypt2EMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) |
5969 |
{ |
5970 |
int8_t result = DrecryptProcessEMM(rdr, provId, emm, keysAdded); |
5971 |
|
5972 |
if (result == 2) |
5973 |
{ |
5974 |
uint8_t keynum = 0, emmkey; |
5975 |
uint32_t i; |
5976 |
KeyDataContainer *KeyDB = GetKeyContainer('D'); |
5977 |
|
5978 |
if (KeyDB == NULL) |
5979 |
{ |
5980 |
return result; |
5981 |
} |
5982 |
|
5983 |
for (i = 0; i < KeyDB->keyCount; i++) |
5984 |
{ |
5985 |
if (KeyDB->EmuKeys[i].provider != ((0x4AE1 << 8) | provId)) |
5986 |
{ |
5987 |
continue; |
5988 |
} |
5989 |
|
5990 |
if (strlen(KeyDB->EmuKeys[i].keyName) < 6) |
5991 |
{ |
5992 |
continue; |
5993 |
} |
5994 |
|
5995 |
if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) |
5996 |
{ |
5997 |
continue; |
5998 |
} |
5999 |
|
6000 |
CharToBin(&keynum, KeyDB->EmuKeys[i].keyName + 4, 2); |
6001 |
emmkey = (emm[4] == 0x4D) ? emm[0x61] : emm[0x2C]; |
6002 |
|
6003 |
if (keynum == emmkey) |
6004 |
{ |
6005 |
if (provId == 0x11) |
6006 |
{ |
6007 |
CharToBin(&rdr->dre36_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); |
6008 |
} |
6009 |
else |
6010 |
{ |
6011 |
CharToBin(&rdr->dre56_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); |
6012 |
} |
6013 |
|
6014 |
break; |
6015 |
} |
6016 |
} |
6017 |
} |
6018 |
|
6019 |
return result; |
6020 |
} |
6021 |
|
6022 |
int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t *count) |
6023 |
{ |
6024 |
uint32_t i; |
6025 |
KeyDataContainer *KeyDB = GetKeyContainer('D'); |
6026 |
|
6027 |
if (KeyDB == NULL) |
6028 |
{ |
6029 |
return 0; |
6030 |
} |
6031 |
|
6032 |
(*count) = 0; |
6033 |
|
6034 |
for (i = 0; i < KeyDB->keyCount && (*count) < length; i++) |
6035 |
{ |
6036 |
|
6037 |
if (KeyDB->EmuKeys[i].provider != ((caid << 8) | provid)) |
6038 |
{ |
6039 |
continue; |
6040 |
} |
6041 |
|
6042 |
if (strlen(KeyDB->EmuKeys[i].keyName) < 6) |
6043 |
{ |
6044 |
continue; |
6045 |
} |
6046 |
|
6047 |
if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) |
6048 |
{ |
6049 |
continue; |
6050 |
} |
6051 |
|
6052 |
CharToBin(&hexserials[(*count)], KeyDB->EmuKeys[i].keyName + 2, 2); |
6053 |
|
6054 |
(*count)++; |
6055 |
} |
6056 |
|
6057 |
return 1; |
6058 |
} |
6059 |
|
6060 |
// Tandberg EMM EMU |
6061 |
static uint8_t MixTable[] = |
6062 |
{ |
6063 |
0x12,0x78,0x4B,0x19,0x13,0x80,0x2F,0x84, |
6064 |
0x86,0x4C,0x09,0x53,0x15,0x79,0x6B,0x49, |
6065 |
0x10,0x4D,0x33,0x43,0x18,0x37,0x83,0x38, |
6066 |
0x82,0x1B,0x6E,0x24,0x2A,0x85,0x3C,0x3D, |
6067 |
0x5A,0x58,0x55,0x5D,0x20,0x41,0x65,0x51, |
6068 |
0x0C,0x45,0x63,0x7F,0x0F,0x46,0x21,0x7C, |
6069 |
0x2C,0x61,0x7E,0x0A,0x42,0x57,0x35,0x16, |
6070 |
0x87,0x3B,0x4F,0x40,0x34,0x22,0x26,0x74, |
6071 |
0x32,0x69,0x44,0x7A,0x6A,0x6D,0x0D,0x56, |
6072 |
0x23,0x2B,0x5C,0x72,0x76,0x36,0x28,0x25, |
6073 |
0x2E,0x52,0x5B,0x6C,0x7D,0x30,0x0B,0x5E, |
6074 |
0x47,0x1F,0x7B,0x31,0x3E,0x11,0x77,0x1E, |
6075 |
0x60,0x75,0x54,0x27,0x50,0x17,0x70,0x59, |
6076 |
0x1A,0x2D,0x4A,0x67,0x3A,0x5F,0x68,0x08, |
6077 |
0x4E,0x3F,0x29,0x6F,0x81,0x71,0x39,0x64, |
6078 |
0x48,0x66,0x73,0x14,0x0E,0x1D,0x62,0x1C |
6079 |
}; |
6080 |
|
6081 |
void TandbergRotateBytes(unsigned char *in, int n) |
6082 |
{ |
6083 |
if(n > 1) |
6084 |
{ |
6085 |
unsigned char *e = in + n - 1; |
6086 |
do |
6087 |
{ |
6088 |
unsigned char temp = *in; |
6089 |
*in++ = *e; |
6090 |
*e-- = temp; |
6091 |
} |
6092 |
while (in < e); |
6093 |
} |
6094 |
} |
6095 |
|
6096 |
static void TandbergECMKeyDecrypt(uint8_t* emmKey, uint8_t* tagData, uint8_t* ecmKey) |
6097 |
{ |
6098 |
TandbergRotateBytes(emmKey, 8); |
6099 |
uint8_t iv[8] = { 0 }; |
6100 |
uint8_t* payLoad = tagData + 4 + 5; |
6101 |
des_cbc_decrypt(payLoad, iv, emmKey, 16); |
6102 |
|
6103 |
ecmKey[0] = payLoad[0x0F]; |
6104 |
ecmKey[1] = payLoad[0x01]; |
6105 |
ecmKey[2] = payLoad[0x0B]; |
6106 |
ecmKey[3] = payLoad[0x03]; |
6107 |
ecmKey[4] = payLoad[0x0E]; |
6108 |
ecmKey[5] = payLoad[0x04]; |
6109 |
ecmKey[6] = payLoad[0x0A]; |
6110 |
ecmKey[7] = payLoad[0x08]; |
6111 |
} |
6112 |
|
6113 |
static int8_t TandbergParseEMMNanoTags(uint8_t* data, uint32_t length, uint8_t keyIndex, uint32_t *keysAdded) |
6114 |
{ |
6115 |
uint8_t tagType, tagLength, blockIndex; |
6116 |
uint32_t pos = 0, entitlementId; |
6117 |
int32_t i, k; |
6118 |
uint32_t ks[32]; |
6119 |
uint8_t* tagData; |
6120 |
uint8_t emmKey[8]; |
6121 |
char keyValue[17]; |
6122 |
uint8_t tagDataDecrypted[0x10][8]; |
6123 |
|
6124 |
if(length < 2) |
6125 |
{ |
6126 |
return 1; |
6127 |
} |
6128 |
|
6129 |
while(pos < length) |
6130 |
{ |
6131 |
tagType = data[pos]; |
6132 |
tagLength = data[pos+1]; |
6133 |
|
6134 |
if(pos + 2 + tagLength > length) |
6135 |
{ |
6136 |
return 1; |
6137 |
} |
6138 |
|
6139 |
tagData = data + pos + 2; |
6140 |
|
6141 |
switch(tagType) |
6142 |
{ |
6143 |
case 0xE4: // EMM_TAG_SECURITY_TABLE_DESCRIPTOR (ram emm keys) |
6144 |
{ |
6145 |
uint8_t tagMode = data[pos + 2]; |
6146 |
|
6147 |
switch(tagMode) |
6148 |
{ |
6149 |
case 0x01: // keySet 01 (MK01) |
6150 |
{ |
6151 |
if(tagLength != 0x8A) |
6152 |
{ |
6153 |
cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x8A); |
6154 |
break; |
6155 |
} |
6156 |
|
6157 |
if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) |
6158 |
{ |
6159 |
break; |
6160 |
} |
6161 |
|
6162 |
uint8_t iv[8] = { 0 }; |
6163 |
uint8_t* tagPayload = tagData + 2; |
6164 |
des_cbc_decrypt(tagPayload, iv, emmKey, 136); |
6165 |
|
6166 |
for (k = 0; k < 0x10; k++) // loop 0x10 keys |
6167 |
{ |
6168 |
for (i = 0; i < 8; i++) // loop 8 bytes of key |
6169 |
{ |
6170 |
tagDataDecrypted[k][i] = tagPayload[MixTable[8*k + i]]; |
6171 |
} |
6172 |
} |
6173 |
|
6174 |
blockIndex = tagData[1] & 0x03; |
6175 |
|
6176 |
for(i = 0; i < 0x10; i++) |
6177 |
{ |
6178 |
SetKey('T', (blockIndex << 4) + i, "MK01", tagDataDecrypted[i], 8, 0, NULL, NULL); |
6179 |
} |
6180 |
} |
6181 |
break; |
6182 |
|
6183 |
case 0xFF: // keySet FF (MK) |
6184 |
{ |
6185 |
if(tagLength != 0x82) |
6186 |
{ |
6187 |
cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x82); |
6188 |
break; |
6189 |
} |
6190 |
|
6191 |
blockIndex = tagData[1] & 0x03; |
6192 |
|
6193 |
if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) |
6194 |
{ |
6195 |
break; |
6196 |
} |
6197 |
|
6198 |
des_set_key(emmKey, ks); |
6199 |
|
6200 |
for(i = 0; i < 0x10; i++) |
6201 |
{ |
6202 |
des(tagData + 2 + (i*8), ks, 0); |
6203 |
} |
6204 |
|
6205 |
for(i = 0; i < 0x10; i++) |
6206 |
{ |
6207 |
SetKey('T', (blockIndex << 4) + i, "MK", tagData + 2 + (i*8), 8, 0, NULL, NULL); |
6208 |
} |
6209 |
} |
6210 |
break; |
6211 |
|
6212 |
default: |
6213 |
cs_log("WARNING: nanoTag E4 mode %.2X not supported", tagMode); |
6214 |
break; |
6215 |
} |
6216 |
break; |
6217 |
} |
6218 |
|
6219 |
case 0xE1: // EMM_TAG_EVENT_ENTITLEMENT_DESCRIPTOR (ecm keys) |
6220 |
{ |
6221 |
uint8_t tagMode = data[pos + 2 + 4]; |
6222 |
|
6223 |
switch(tagMode) |
6224 |
{ |
6225 |
case 0x00: // ecm keys from mode FF |
6226 |
{ |
6227 |
if(tagLength != 0x12) |
6228 |
{ |
6229 |
cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x12); |
6230 |
break; |
6231 |
} |
6232 |
|
6233 |
entitlementId = b2i(4, tagData); |
6234 |
|
6235 |
if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) |
6236 |
{ |
6237 |
break; |
6238 |
} |
6239 |
|
6240 |
des_set_key(emmKey, ks); |
6241 |
des(tagData + 4 + 5, ks, 0); |
6242 |
|
6243 |
if((tagData + 4 + 5 + 7) != 0x00) // check if key looks valid (last byte 0x00) |
6244 |
{ |
6245 |
break; |
6246 |
} |
6247 |
|
6248 |
if(UpdateKey('T', entitlementId, "01", tagData + 4 + 5, 8, 1, NULL)) |
6249 |
{ |
6250 |
(*keysAdded)++; |
6251 |
cs_hexdump(0, tagData + 4 + 5, 8, keyValue, sizeof(keyValue)); |
6252 |
cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); |
6253 |
} |
6254 |
} |
6255 |
break; |
6256 |
|
6257 |
case 0x01: // ecm keys from mode 01 |
6258 |
{ |
6259 |
if(tagLength != 0x1A) |
6260 |
{ |
6261 |
cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x1A); |
6262 |
break; |
6263 |
} |
6264 |
|
6265 |
entitlementId = b2i(4, tagData); |
6266 |
|
6267 |
if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) |
6268 |
{ |
6269 |
break; |
6270 |
} |
6271 |
|
6272 |
uint8_t ecmKey[8] = { 0 }; |
6273 |
TandbergECMKeyDecrypt(emmKey, tagData, ecmKey); |
6274 |
|
6275 |
if(ecmKey[7] != 0x00) // check if key looks valid (last byte 0x00) |
6276 |
{ |
6277 |
break; |
6278 |
} |
6279 |
|
6280 |
if(UpdateKey('T', entitlementId, "01", ecmKey, 8, 1, NULL)) |
6281 |
{ |
6282 |
(*keysAdded)++; |
6283 |
cs_hexdump(0, ecmKey, 8, keyValue, sizeof(keyValue)); |
6284 |
cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); |
6285 |
} |
6286 |
} |
6287 |
break; |
6288 |
|
6289 |
default: |
6290 |
cs_log("WARNING: nanoTag E1 mode %.2X not supported", tagMode); |
6291 |
break; |
6292 |
} |
6293 |
break; |
6294 |
} |
6295 |
|
6296 |
default: |
6297 |
cs_log("WARNING: nanoTag %.2X not supported", tagType); |
6298 |
break; |
6299 |
} |
6300 |
|
6301 |
pos += 2 + tagLength; |
6302 |
} |
6303 |
|
6304 |
return 0; |
6305 |
} |
6306 |
|
6307 |
static int8_t TandbergParseEMMNanoData(uint8_t* data, uint32_t* nanoLength, uint32_t maxLength, uint8_t keyIndex, uint32_t *keysAdded) |
6308 |
{ |
6309 |
uint32_t pos = 0; |
6310 |
uint16_t sectionLength; |
6311 |
int8_t ret = 0; |
6312 |
|
6313 |
if(maxLength < 2) |
6314 |
{ |
6315 |
(*nanoLength) = 0; |
6316 |
return 1; |
6317 |
} |
6318 |
|
6319 |
sectionLength = ((data[pos]<<8) | data[pos+1]) & 0x0FFF; |
6320 |
|
6321 |
if(pos + 2 + sectionLength > maxLength) |
6322 |
{ |
6323 |
(*nanoLength) = pos; |
6324 |
return 1; |
6325 |
} |
6326 |
|
6327 |
ret = TandbergParseEMMNanoTags(data + pos + 2, sectionLength, keyIndex, keysAdded); |
6328 |
|
6329 |
pos += 2 + sectionLength; |
6330 |
|
6331 |
(*nanoLength) = pos; |
6332 |
return ret; |
6333 |
} |
6334 |
|
6335 |
static int8_t TandbergEMM(uint8_t *emm, uint32_t *keysAdded) |
6336 |
{ |
6337 |
uint8_t keyIndex, ret = 0; |
6338 |
uint16_t emmLen = GetEcmLen(emm); |
6339 |
uint32_t pos = 3; |
6340 |
uint32_t permissionDataType; |
6341 |
uint32_t nanoLength = 0; |
6342 |
|
6343 |
while (pos < emmLen && !ret) |
6344 |
{ |
6345 |
permissionDataType = emm[pos]; |
6346 |
|
6347 |
switch(permissionDataType) |
6348 |
{ |
6349 |
case 0x00: |
6350 |
{ |
6351 |
break; |
6352 |
} |
6353 |
|
6354 |
case 0x01: |
6355 |
{ |
6356 |
pos += 0x0A; |
6357 |
break; |
6358 |
} |
6359 |
|
6360 |
case 0x02: |
6361 |
{ |
6362 |
pos += 0x26; |
6363 |
break; |
6364 |
} |
6365 |
|
6366 |
default: |
6367 |
cs_log("ERROR: unknown permissionDataType %.2X (pos: %d)", permissionDataType, pos); |
6368 |
return 1; |
6369 |
} |
6370 |
|
6371 |
if(pos+6 >= emmLen) |
6372 |
{ |
6373 |
break; |
6374 |
} |
6375 |
|
6376 |
keyIndex = emm[pos+1]; |
6377 |
|
6378 |
// EMM validation |
6379 |
// Copy payload checksum bytes and then set them to zero, |
6380 |
// so they do not affect the calculated checksum. |
6381 |
uint16_t payloadChecksum = (emm[pos + 2] << 8) | emm[pos + 3]; |
6382 |
memset(emm + pos + 2, 0, 2); |
6383 |
uint16_t calculatedChecksum = TandbergChecksum(emm + 3, emmLen - 3); |
6384 |
|
6385 |
if(calculatedChecksum != payloadChecksum) |
6386 |
{ |
6387 |
cs_log("EMM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); |
6388 |
return 8; |
6389 |
} |
6390 |
// End of EMM validation |
6391 |
|
6392 |
pos += 0x04; |
6393 |
ret = TandbergParseEMMNanoData(emm + pos, &nanoLength, emmLen - pos, keyIndex, keysAdded); |
6394 |
pos += nanoLength; |
6395 |
} |
6396 |
|
6397 |
return ret; |
6398 |
} |
6399 |
|
6400 |
const char* GetProcessEMMErrorReason(int8_t result) |
6401 |
{ |
6402 |
switch(result) { |
6403 |
case 0: |
6404 |
return "No error"; |
6405 |
case 1: |
6406 |
return "EMM not supported"; |
6407 |
case 2: |
6408 |
return "Key not found"; |
6409 |
case 3: |
6410 |
return "Nano80 problem"; |
6411 |
case 4: |
6412 |
return "Corrupt data"; |
6413 |
case 5: |
6414 |
return "Unknown"; |
6415 |
case 6: |
6416 |
return "Checksum error"; |
6417 |
case 7: |
6418 |
return "Out of memory"; |
6419 |
case 8: |
6420 |
return "EMM checksum error"; |
6421 |
case 9: |
6422 |
return "Wrong provider"; |
6423 |
default: |
6424 |
return "Unknown"; |
6425 |
} |
6426 |
} |
6427 |
|
6428 |
int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded) |
6429 |
{ |
6430 |
int8_t result = 1; |
6431 |
uint8_t emmCopy[EMU_MAX_EMM_LEN]; |
6432 |
uint16_t emmLen = GetEcmLen(emm); |
6433 |
|
6434 |
if(emmLen > EMU_MAX_EMM_LEN) { |
6435 |
return 1; |
6436 |
} |
6437 |
memcpy(emmCopy, emm, emmLen); |
6438 |
*keysAdded = 0; |
6439 |
|
6440 |
if(caid==0x0500) { |
6441 |
result = ViaccessEMM(emmCopy, keysAdded); |
6442 |
} |
6443 |
else if((caid>>8)==0x06) { |
6444 |
result = Irdeto2EMM(caid, emmCopy, keysAdded); |
6445 |
} |
6446 |
else if((caid>>8)==0x0E) { |
6447 |
result = PowervuEMM(emmCopy, keysAdded); |
6448 |
} |
6449 |
else if(caid==0x4AE1) { |
6450 |
result = Drecrypt2EMM(rdr, provider, emmCopy, keysAdded); |
6451 |
} |
6452 |
else if((caid>>8)==0x10) { |
6453 |
result = TandbergEMM(emmCopy, keysAdded); |
6454 |
} |
6455 |
|
6456 |
if(result != 0) { |
6457 |
cs_log_dbg(D_EMM,"EMM failed: %s", GetProcessEMMErrorReason(result)); |
6458 |
} |
6459 |
|
6460 |
return result; |
6461 |
} |