[PR-54] Switch to libdvbcsa: update code word client and campt
As libdvbcsa works on packet payloads instead of full packets, I borrowed the packet inspection code from FFdecsa. Tested and found working with Irdeto2 CA system and OSCam's NewCamd emulation. As the capmt code doesn't use key change notification, there might be a race between key updates and decryption, when there is undecrypted data batched up. This has not been tested yet, as I don't have a capmt cardserver.
This commit is contained in:
parent
303313a82f
commit
7c1819ba92
3 changed files with 164 additions and 60 deletions
110
src/capmt.c
110
src/capmt.c
|
@ -42,7 +42,7 @@
|
|||
#include "tcp.h"
|
||||
#include "psi.h"
|
||||
#include "tsdemux.h"
|
||||
#include "ffdecsa/FFdecsa.h"
|
||||
#include <dvbcsa/dvbcsa.h>
|
||||
#include "capmt.h"
|
||||
#include "notify.h"
|
||||
#include "subscriptions.h"
|
||||
|
@ -155,13 +155,18 @@ typedef struct capmt_service {
|
|||
CT_FORBIDDEN
|
||||
} ct_keystate;
|
||||
|
||||
/* buffer for keystruct */
|
||||
void *ct_keys;
|
||||
/* buffers for keystructs */
|
||||
struct dvbcsa_bs_key_s *ct_key_even;
|
||||
struct dvbcsa_bs_key_s *ct_key_odd;
|
||||
|
||||
/* CSA */
|
||||
int ct_cluster_size;
|
||||
uint8_t *ct_tsbcluster;
|
||||
struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
|
||||
struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
|
||||
int ct_fill;
|
||||
int ct_fill_even;
|
||||
int ct_fill_odd;
|
||||
|
||||
/* current sequence number */
|
||||
uint16_t ct_seq;
|
||||
|
@ -359,7 +364,10 @@ capmt_service_destroy(th_descrambler_t *td)
|
|||
|
||||
LIST_REMOVE(ct, ct_link);
|
||||
|
||||
free_key_struct(ct->ct_keys);
|
||||
dvbcsa_bs_key_free(ct->ct_key_odd);
|
||||
dvbcsa_bs_key_free(ct->ct_key_even);
|
||||
free(ct->ct_tsbbatch_odd);
|
||||
free(ct->ct_tsbbatch_even);
|
||||
free(ct->ct_tsbcluster);
|
||||
free(ct);
|
||||
}
|
||||
|
@ -498,9 +506,9 @@ handle_ca0(capmt_t* capmt) {
|
|||
continue;
|
||||
|
||||
if (memcmp(even, invalid, 8))
|
||||
set_even_control_word(ct->ct_keys, even);
|
||||
dvbcsa_bs_key_set(even, ct->ct_key_even);
|
||||
if (memcmp(odd, invalid, 8))
|
||||
set_odd_control_word(ct->ct_keys, odd);
|
||||
dvbcsa_bs_key_set(odd, ct->ct_key_odd);
|
||||
|
||||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
|
||||
|
@ -839,8 +847,14 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
|
|||
const uint8_t *tsb)
|
||||
{
|
||||
capmt_service_t *ct = (capmt_service_t *)td;
|
||||
int r, i;
|
||||
unsigned char *vec[3];
|
||||
uint8_t *pkt;
|
||||
int xc0;
|
||||
int ev_od;
|
||||
int len;
|
||||
int offset;
|
||||
int n;
|
||||
// FIXME: //int residue;
|
||||
int i;
|
||||
uint8_t *t0;
|
||||
|
||||
if(ct->ct_keystate == CT_FORBIDDEN)
|
||||
|
@ -849,28 +863,67 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
|
|||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
return -1;
|
||||
|
||||
memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
|
||||
pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
|
||||
memcpy(pkt, tsb, 188);
|
||||
ct->ct_fill++;
|
||||
|
||||
do { // handle this packet
|
||||
xc0 = pkt[3] & 0xc0;
|
||||
if(xc0 == 0x00) { // clear
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x40) { // reserved
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
|
||||
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
|
||||
pkt[3] &= 0x3f; // consider it decrypted now
|
||||
if(pkt[3] & 0x20) { // incomplete packet
|
||||
offset = 4 + pkt[4] + 1;
|
||||
len = 188 - offset;
|
||||
n = len >> 3;
|
||||
// FIXME: //residue = len - (n << 3);
|
||||
if(n == 0) { // decrypted==encrypted!
|
||||
break; // this doesn't need more processing
|
||||
}
|
||||
} else {
|
||||
len = 184;
|
||||
offset = 4;
|
||||
// FIXME: //n = 23;
|
||||
// FIXME: //residue = 0;
|
||||
}
|
||||
if(ev_od == 0) {
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].data = pkt + offset;
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].len = len;
|
||||
ct->ct_fill_even++;
|
||||
} else {
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = pkt + offset;
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].len = len;
|
||||
ct->ct_fill_odd++;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(ct->ct_fill != ct->ct_cluster_size)
|
||||
return 0;
|
||||
|
||||
ct->ct_fill = 0;
|
||||
if(ct->ct_fill_even) {
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->ct_key_even, ct->ct_tsbbatch_even, 184);
|
||||
ct->ct_fill_even = 0;
|
||||
}
|
||||
if(ct->ct_fill_odd) {
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->ct_key_odd, ct->ct_tsbbatch_odd, 184);
|
||||
ct->ct_fill_odd = 0;
|
||||
}
|
||||
|
||||
vec[0] = ct->ct_tsbcluster;
|
||||
vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
|
||||
vec[2] = NULL;
|
||||
|
||||
while(1) {
|
||||
t0 = vec[0];
|
||||
r = decrypt_packets(ct->ct_keys, vec);
|
||||
if(r == 0)
|
||||
break;
|
||||
for(i = 0; i < r; i++) {
|
||||
t0 = ct->ct_tsbcluster;
|
||||
for(i = 0; i < ct->ct_fill; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
}
|
||||
ct->ct_fill = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -898,10 +951,14 @@ capmt_service_start(service_t *t)
|
|||
elementary_stream_t *st;
|
||||
|
||||
/* create new capmt service */
|
||||
ct = calloc(1, sizeof(capmt_service_t));
|
||||
ct->ct_cluster_size = get_suggested_cluster_size();
|
||||
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
|
||||
ct->ct_seq = capmt->capmt_seq++;
|
||||
ct = calloc(1, sizeof(capmt_service_t));
|
||||
ct->ct_cluster_size = dvbcsa_bs_batch_size();
|
||||
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
|
||||
ct->ct_tsbbatch_even = malloc((ct->ct_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->ct_tsbbatch_odd = malloc((ct->ct_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->ct_seq = capmt->capmt_seq++;
|
||||
|
||||
TAILQ_FOREACH(st, &t->s_components, es_link) {
|
||||
caid_t *c;
|
||||
|
@ -924,7 +981,8 @@ capmt_service_start(service_t *t)
|
|||
}
|
||||
}
|
||||
|
||||
ct->ct_keys = get_key_struct();
|
||||
ct->ct_key_even = dvbcsa_bs_key_alloc();
|
||||
ct->ct_key_odd = dvbcsa_bs_key_alloc();
|
||||
ct->ct_capmt = capmt;
|
||||
ct->ct_service = t;
|
||||
|
||||
|
|
112
src/cwc.c
112
src/cwc.c
|
@ -31,7 +31,7 @@
|
|||
#include "tcp.h"
|
||||
#include "psi.h"
|
||||
#include "tsdemux.h"
|
||||
#include "ffdecsa/FFdecsa.h"
|
||||
#include <dvbcsa/dvbcsa.h>
|
||||
#include "cwc.h"
|
||||
#include "notify.h"
|
||||
#include "atomic.h"
|
||||
|
@ -155,7 +155,8 @@ typedef struct cwc_service {
|
|||
CS_IDLE
|
||||
} cs_keystate;
|
||||
|
||||
void *cs_keys;
|
||||
struct dvbcsa_bs_key_s *cs_key_even;
|
||||
struct dvbcsa_bs_key_s *cs_key_odd;
|
||||
|
||||
|
||||
uint8_t cs_cw[16];
|
||||
|
@ -166,7 +167,11 @@ typedef struct cwc_service {
|
|||
*/
|
||||
int cs_cluster_size;
|
||||
uint8_t *cs_tsbcluster;
|
||||
struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
|
||||
struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
|
||||
int cs_fill;
|
||||
int cs_fill_even;
|
||||
int cs_fill_odd;
|
||||
|
||||
LIST_HEAD(, ecm_pid) cs_pids;
|
||||
|
||||
|
@ -1884,13 +1889,13 @@ update_keys(cwc_service_t *ct)
|
|||
ct->cs_pending_cw_update = 0;
|
||||
for(i = 0; i < 8; i++)
|
||||
if(ct->cs_cw[i]) {
|
||||
set_even_control_word(ct->cs_keys, ct->cs_cw);
|
||||
dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
if(ct->cs_cw[8 + i]) {
|
||||
set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
|
||||
dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1904,8 +1909,13 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
|||
const uint8_t *tsb)
|
||||
{
|
||||
cwc_service_t *ct = (cwc_service_t *)td;
|
||||
int r;
|
||||
unsigned char *vec[3];
|
||||
uint8_t *pkt;
|
||||
int xc0;
|
||||
int ev_od;
|
||||
int len;
|
||||
int offset;
|
||||
int n;
|
||||
// FIXME: //int residue;
|
||||
|
||||
if(ct->cs_keystate == CS_FORBIDDEN)
|
||||
return 1;
|
||||
|
@ -1916,42 +1926,72 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
|||
if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
|
||||
pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
|
||||
memcpy(pkt, tsb, 188);
|
||||
ct->cs_fill++;
|
||||
|
||||
do { // handle this packet
|
||||
xc0 = pkt[3] & 0xc0;
|
||||
if(xc0 == 0x00) { // clear
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x40) { // reserved
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
|
||||
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
|
||||
pkt[3] &= 0x3f; // consider it decrypted now
|
||||
if(pkt[3] & 0x20) { // incomplete packet
|
||||
offset = 4 + pkt[4] + 1;
|
||||
len = 188 - offset;
|
||||
n = len >> 3;
|
||||
// FIXME: //residue = len - (n << 3);
|
||||
if(n == 0) { // decrypted==encrypted!
|
||||
break; // this doesn't need more processing
|
||||
}
|
||||
} else {
|
||||
len = 184;
|
||||
offset = 4;
|
||||
// FIXME: //n = 23;
|
||||
// FIXME: //residue = 0;
|
||||
}
|
||||
if(ev_od == 0) {
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].data = pkt + offset;
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].len = len;
|
||||
ct->cs_fill_even++;
|
||||
} else {
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = pkt + offset;
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].len = len;
|
||||
ct->cs_fill_odd++;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(ct->cs_fill != ct->cs_cluster_size)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
if(ct->cs_fill_even) {
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->cs_key_even, ct->cs_tsbbatch_even, 184);
|
||||
ct->cs_fill_even = 0;
|
||||
}
|
||||
if(ct->cs_fill_odd) {
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->cs_key_odd, ct->cs_tsbbatch_odd, 184);
|
||||
ct->cs_fill_odd = 0;
|
||||
}
|
||||
|
||||
vec[0] = ct->cs_tsbcluster;
|
||||
vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
|
||||
vec[2] = NULL;
|
||||
|
||||
r = decrypt_packets(ct->cs_keys, vec);
|
||||
if(r > 0) {
|
||||
{
|
||||
int i;
|
||||
const uint8_t *t0 = ct->cs_tsbcluster;
|
||||
|
||||
for(i = 0; i < r; i++) {
|
||||
for(i = 0; i < ct->cs_fill; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
|
||||
r = ct->cs_fill - r;
|
||||
assert(r >= 0);
|
||||
|
||||
if(r > 0)
|
||||
memmove(ct->cs_tsbcluster, t0, r * 188);
|
||||
ct->cs_fill = r;
|
||||
|
||||
if(ct->cs_pending_cw_update && r > 0)
|
||||
continue;
|
||||
} else {
|
||||
ct->cs_fill = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ct->cs_fill = 0;
|
||||
|
||||
if(ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
|
@ -1980,7 +2020,10 @@ cwc_service_destroy(th_descrambler_t *td)
|
|||
|
||||
LIST_REMOVE(ct, cs_link);
|
||||
|
||||
free_key_struct(ct->cs_keys);
|
||||
dvbcsa_bs_key_free(ct->cs_key_odd);
|
||||
dvbcsa_bs_key_free(ct->cs_key_even);
|
||||
free(ct->cs_tsbbatch_odd);
|
||||
free(ct->cs_tsbbatch_even);
|
||||
free(ct->cs_tsbcluster);
|
||||
free(ct);
|
||||
}
|
||||
|
@ -2025,10 +2068,15 @@ cwc_service_start(service_t *t)
|
|||
continue;
|
||||
|
||||
ct = calloc(1, sizeof(cwc_service_t));
|
||||
ct->cs_cluster_size = get_suggested_cluster_size();
|
||||
ct->cs_cluster_size = dvbcsa_bs_batch_size();
|
||||
ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
|
||||
ct->cs_tsbbatch_even = malloc((ct->cs_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->cs_tsbbatch_odd = malloc((ct->cs_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
|
||||
ct->cs_keys = get_key_struct();
|
||||
ct->cs_key_even = dvbcsa_bs_key_alloc();
|
||||
ct->cs_key_odd = dvbcsa_bs_key_alloc();
|
||||
ct->cs_cwc = cwc;
|
||||
ct->cs_service = t;
|
||||
ct->cs_okchannel = -3;
|
||||
|
|
|
@ -468,8 +468,6 @@ main(int argc, char **argv)
|
|||
|
||||
htsp_init();
|
||||
|
||||
ffdecsa_init();
|
||||
|
||||
if(rawts_input != NULL)
|
||||
rawts_init(rawts_input);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue