|
@@ -23,6 +23,14 @@
|
23
|
23
|
|
24
|
24
|
#include "util.h"
|
25
|
25
|
|
|
26
|
+uint8_t cur_cw[16];
|
|
27
|
+uint8_t invalid_cw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
28
|
+
|
|
29
|
+static inline int valid_cw(uint8_t *cw) {
|
|
30
|
+ return memcmp(cw, invalid_cw, 16) != 0;
|
|
31
|
+}
|
|
32
|
+
|
|
33
|
+
|
26
|
34
|
struct ts {
|
27
|
35
|
struct ts_pat *pat, *curpat;
|
28
|
36
|
struct ts_cat *cat, *curcat;
|
|
@@ -79,11 +87,6 @@ uint32_t camd35_auth = 0;
|
79
|
87
|
AES_KEY camd35_aes_encrypt_key;
|
80
|
88
|
AES_KEY camd35_aes_decrypt_key;
|
81
|
89
|
|
82
|
|
-enum e_flag {
|
83
|
|
- TYPE_EMM,
|
84
|
|
- TYPE_ECM
|
85
|
|
-};
|
86
|
|
-
|
87
|
90
|
static int connect_to(struct in_addr ip, int port) {
|
88
|
91
|
ts_LOGf("Connecting to %s:%d\n", inet_ntoa(ip), port);
|
89
|
92
|
|
|
@@ -106,20 +109,6 @@ static int connect_to(struct in_addr ip, int port) {
|
106
|
109
|
return fd;
|
107
|
110
|
}
|
108
|
111
|
|
109
|
|
-void savefile(uint8_t *data, int datasize, enum e_flag flag) {
|
110
|
|
- static int cnt = 0;
|
111
|
|
- char *fname;
|
112
|
|
- asprintf(&fname, "%03d-%s.dump", ++cnt, flag == TYPE_EMM ? "emm" : "ecm");
|
113
|
|
- int fd = open(fname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
114
|
|
- if (fd < 0) {
|
115
|
|
- perror("open");
|
116
|
|
- exit(1);
|
117
|
|
- }
|
118
|
|
- write(fd, data, datasize);
|
119
|
|
- close(fd);
|
120
|
|
- free(fname);
|
121
|
|
-}
|
122
|
|
-
|
123
|
112
|
// 4 auth header, 20 header size, 256 max data size, 16 potential padding
|
124
|
113
|
#define HDR_LEN (20)
|
125
|
114
|
#define BUF_SIZE (4 + HDR_LEN + 256 + 16)
|
|
@@ -142,20 +131,61 @@ static void camd35_connect() {
|
142
|
131
|
static int camd35_recv(uint8_t *data, int *data_len) {
|
143
|
132
|
int i;
|
144
|
133
|
|
|
134
|
+ // Read AUTH token
|
|
135
|
+ ssize_t r = fdread(server_fd, (char *)data, 4);
|
|
136
|
+ if (r < 4)
|
|
137
|
+ return -1;
|
145
|
138
|
uint32_t auth_token = (((data[0] << 24) | (data[1] << 16) | (data[2]<<8) | data[3]) & 0xffffffffL);
|
146
|
139
|
if (auth_token != camd35_auth)
|
147
|
|
- fprintf(stderr, "WARN: recv auth : 0x%08x != camd35_auth 0x%08x\n", auth_token, camd35_auth);
|
|
140
|
+ ts_LOGf("WARN: recv auth 0x%08x != camd35_auth 0x%08x\n", auth_token, camd35_auth);
|
148
|
141
|
|
149
|
|
- *data_len -= 4; // Remove header
|
150
|
|
- memmove(data, data + 4, *data_len); // Remove header
|
151
|
|
-
|
152
|
|
- for (i = 0; i < *data_len; i += 16) // Decrypt payload
|
|
142
|
+ *data_len = 256;
|
|
143
|
+ for (i = 0; i < *data_len; i += 16) { // Read and decrypt payload
|
|
144
|
+ fdread(server_fd, (char *)data + i, 16);
|
153
|
145
|
AES_decrypt(data + i, data + i, &camd35_aes_decrypt_key);
|
|
146
|
+ if (i == 0)
|
|
147
|
+ *data_len = boundary(4, data[1] + 20); // Initialize real data length
|
|
148
|
+ }
|
|
149
|
+ return *data_len;
|
|
150
|
+}
|
|
151
|
+
|
|
152
|
+#define ERR(x) do { fprintf(stderr, "%s", x); return NULL; } while (0)
|
|
153
|
+
|
|
154
|
+static uint8_t *camd35_recv_cw() {
|
|
155
|
+ uint8_t data[BUF_SIZE];
|
|
156
|
+ int data_len = 0;
|
|
157
|
+
|
|
158
|
+NEXT:
|
|
159
|
+ if (camd35_recv(data, &data_len) < 0)
|
|
160
|
+ ERR("No data!");
|
|
161
|
+
|
|
162
|
+ if (data_len < 48)
|
|
163
|
+ ERR("len mismatch != 48");
|
|
164
|
+
|
|
165
|
+ if (data[0] < 0x01) {
|
|
166
|
+ ts_LOGf("Not valid CW response, skipping it. data[0] = 0x%02x\n", data[0]);
|
|
167
|
+ goto NEXT;
|
|
168
|
+ }
|
154
|
169
|
|
155
|
|
- return 0;
|
|
170
|
+ if (data[1] < 0x10)
|
|
171
|
+ ERR("CW len mismatch != 0x10");
|
|
172
|
+
|
|
173
|
+ uint16_t ca_id = (data[10] << 8) | data[11];
|
|
174
|
+ uint16_t idx = (data[16] << 8) | data[17];
|
|
175
|
+ uint8_t *cw = data + 20;
|
|
176
|
+ memcpy(cur_cw, cw, 16);
|
|
177
|
+
|
|
178
|
+ char cw_dump[16 * 6];
|
|
179
|
+ ts_hex_dump_buf(cw_dump, 16 * 6, cw, 16, 0);
|
|
180
|
+ ts_LOGf("CW | CAID: 0x%04x ---------------------------------- IDX: 0x%04x Data: %s\n", ca_id, idx, cw_dump);
|
|
181
|
+
|
|
182
|
+ return NULL;
|
156
|
183
|
}
|
157
|
184
|
|
158
|
|
-static int camd35_send(uint8_t *data, uint8_t data_len, enum e_flag tp) {
|
|
185
|
+#undef ERR
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+static int camd35_send(uint8_t *data, uint8_t data_len) {
|
159
|
189
|
unsigned int i;
|
160
|
190
|
uint8_t buf[BUF_SIZE];
|
161
|
191
|
uint8_t *bdata = buf + 4;
|
|
@@ -171,9 +201,7 @@ static int camd35_send(uint8_t *data, uint8_t data_len, enum e_flag tp) {
|
171
|
201
|
for (i = 0; i < data_len; i += 16) // Encrypt payload
|
172
|
202
|
AES_encrypt(data + i, bdata + i, &camd35_aes_encrypt_key);
|
173
|
203
|
|
174
|
|
- savefile(buf, data_len + 4, tp);
|
175
|
|
-
|
176
|
|
- return 0;
|
|
204
|
+ return fdwrite(server_fd, (char *)buf, data_len + 4);
|
177
|
205
|
}
|
178
|
206
|
|
179
|
207
|
static void camd35_buf_init(uint8_t *buf, uint8_t *data, uint8_t data_len) {
|
|
@@ -199,7 +227,9 @@ static int camd35_send_ecm(uint16_t service_id, uint16_t ca_id, uint16_t idx, ui
|
199
|
227
|
buf[18] = 0xff;
|
200
|
228
|
buf[19] = 0xff;
|
201
|
229
|
|
202
|
|
- return camd35_send(buf, to_send, TYPE_ECM);
|
|
230
|
+ camd35_send(buf, to_send);
|
|
231
|
+ camd35_recv_cw();
|
|
232
|
+ return 0;
|
203
|
233
|
}
|
204
|
234
|
|
205
|
235
|
static int camd35_send_emm(uint16_t ca_id, uint8_t *data, uint8_t data_len) {
|
|
@@ -213,7 +243,7 @@ static int camd35_send_emm(uint16_t ca_id, uint8_t *data, uint8_t data_len) {
|
213
|
243
|
init_2b(ca_id , buf + 10);
|
214
|
244
|
init_4b(prov_id, buf + 12);
|
215
|
245
|
|
216
|
|
- return camd35_send(buf, to_send, TYPE_EMM);
|
|
246
|
+ return camd35_send(buf, to_send);
|
217
|
247
|
}
|
218
|
248
|
|
219
|
249
|
#define handle_table_changes(TABLE) \
|
|
@@ -353,41 +383,6 @@ void ts_process_packets(struct ts *ts, uint8_t *data, uint8_t data_len) {
|
353
|
383
|
}
|
354
|
384
|
|
355
|
385
|
|
356
|
|
-
|
357
|
|
-#define ERR(x) do { fprintf(stderr, "%s", x); return NULL; } while (0)
|
358
|
|
-
|
359
|
|
-static uint8_t *camd35_recv_cw(uint8_t *data, int data_len) {
|
360
|
|
- char *d;
|
361
|
|
-
|
362
|
|
- camd35_recv(data, &data_len);
|
363
|
|
-
|
364
|
|
- if (data_len < 48)
|
365
|
|
- ERR("len mismatch != 48");
|
366
|
|
-
|
367
|
|
- if (data[0] < 0x01)
|
368
|
|
- ERR("Not valid CW response");
|
369
|
|
-
|
370
|
|
- if (data[1] < 0x10)
|
371
|
|
- ERR("CW len mismatch != 0x10");
|
372
|
|
-
|
373
|
|
- d = ts_hex_dump(data, data_len, 16);
|
374
|
|
- fprintf(stderr, "Recv CW :\n%s\n", d);
|
375
|
|
- free(d);
|
376
|
|
-
|
377
|
|
- uint16_t ca_id = (data[10] << 8) | data[11];
|
378
|
|
- uint16_t idx = (data[16] << 8) | data[17];
|
379
|
|
- fprintf(stderr, "CW ca_id: 0x%04x\n", ca_id);
|
380
|
|
- fprintf(stderr, "CW idx : 0x%04x\n", idx);
|
381
|
|
-
|
382
|
|
- d = ts_hex_dump(data + 20, 16, 0);
|
383
|
|
- fprintf(stderr, "CW : %s\n", d);
|
384
|
|
- free(d);
|
385
|
|
-
|
386
|
|
- return data + 20;
|
387
|
|
-}
|
388
|
|
-
|
389
|
|
-#undef ERR
|
390
|
|
-
|
391
|
386
|
void show_help() {
|
392
|
387
|
printf("TSDECRYPT v1.0\n");
|
393
|
388
|
printf("Copyright (c) 2011 Unix Solutions Ltd.\n");
|
|
@@ -462,6 +457,7 @@ int main(int argc, char **argv) {
|
462
|
457
|
ssize_t readen;
|
463
|
458
|
uint8_t ts_packet[FRAME_SIZE];
|
464
|
459
|
|
|
460
|
+ memset(cur_cw, 0, sizeof(cur_cw));
|
465
|
461
|
ts_set_log_func(LOG_func);
|
466
|
462
|
|
467
|
463
|
parse_options(argc, argv);
|