Permalink
Browse files

Add support for DES decryption

To make a use of this you need recent OSCam with:
extended_cw_api=1
option in the [dvbapi] section

original patch by @newspaperman
merged with minor changes

Closes #101
  • Loading branch information...
manio committed Feb 5, 2016
1 parent 9ecee67 commit b4cd00a69ca523ef5f76c108f7dd230f5d0c84e5
Showing with 102 additions and 27 deletions.
  1. +61 −26 DeCSA.cpp
  2. +3 −0 DeCSA.h
  3. +1 −1 Makefile
  4. +18 −0 SocketHandler.cpp
  5. +19 −0 SocketHandler.h
View
@@ -18,6 +18,7 @@
#include "DeCSA.h"
#include "Log.h"
#include "cscrypt/des.h"
#ifndef LIBDVBCSA
#include "FFdecsa/FFdecsa.h"
@@ -104,6 +105,7 @@ bool DeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
{
DEBUGLOG("%d.%d: %4s key set", cardindex, idx, ca_descr->parity ? "odd" : "even");
cwSeen[idx] = time(NULL);
des_set_key(ca_descr->cw, des_key_schedule[idx][ca_descr->parity]);
if (ca_descr->parity == 0)
{
#ifndef LIBDVBCSA
@@ -137,7 +139,12 @@ bool DeCSA::SetCaPid(uint8_t adapter_index, ca_pid_t *ca_pid)
return true;
}
#ifdef LIBDVBCSA
void DeCSA::SetAlgo(uint32_t index, uint32_t usedAlgo)
{
if (index < MAX_CSA_IDX)
algo[index] = usedAlgo;
}
unsigned char ts_packet_get_payload_offset(unsigned char *ts_packet)
{
if (ts_packet[0] != TS_SYNC_BYTE)
@@ -165,7 +172,6 @@ unsigned char ts_packet_get_payload_offset(unsigned char *ts_packet)
return 4; // No adaptation, data starts directly after TS header
}
}
#endif
bool DeCSA::Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool force)
{
@@ -180,13 +186,14 @@ bool DeCSA::Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool fo
return false;
}
int offset;
#ifndef LIBDVBCSA
int r = -2, ccs = 0, currIdx = -1;
bool newRange = true;
range[0] = 0;
#else
int ccs = 0, currIdx = -1;
int payload_len, offset;
int payload_len;
int cs_fill_even = 0;
int cs_fill_odd = 0;
#endif
@@ -199,10 +206,17 @@ bool DeCSA::Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool fo
break;
}
unsigned int ev_od = data[l + 3] & 0xC0;
if (ev_od == 0x80 || ev_od == 0xC0)
/*
we could have the following values:
'00' = Not scrambled
'01' (0x40) = Reserved for future use
'10' (0x80) = Scrambled with even key
'11' (0xC0) = Scrambled with odd key
*/
if (ev_od & 0x80)
{ // encrypted
#ifdef LIBDVBCSA
offset = ts_packet_get_payload_offset(data + l);
#ifdef LIBDVBCSA
payload_len = TS_SIZE - offset;
#endif
int idx = pidmap[make_pair(adapter_index, ((data[l + 1] << 8) + data[l + 2]) & (MAX_CSA_PIDS - 1))];
@@ -212,32 +226,51 @@ bool DeCSA::Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool fo
// return if the key is expired
if (CheckExpiredCW && time(NULL) - cwSeen[currIdx] > MAX_KEY_WAIT)
return false;
#ifndef LIBDVBCSA
if (newRange)
{
r += 2;
newRange = false;
range[r] = &data[l];
range[r + 2] = 0;
}
range[r + 1] = &data[l + TS_SIZE];
#else
data[l + 3] &= 0x3f; // consider it decrypted now
if (((ev_od & 0x40) >> 6) == 0)
if (algo[currIdx] == CA_ALGO_DES)
{
cs_tsbbatch_even[cs_fill_even].data = &data[l + offset];
cs_tsbbatch_even[cs_fill_even].len = payload_len;
cs_fill_even++;
if ((ev_od & 0x40) == 0)
{
for (int j = offset; j + 7 < 188; j += 8)
des(&data[l + j], des_key_schedule[currIdx][0], 0);
}
else
{
for (int j = offset; j + 7 < 188; j += 8)
des(&data[l + j], des_key_schedule[currIdx][1], 0);
}
data[l + 3] &= 0x3f; // consider it decrypted now
}
else
{
cs_tsbbatch_odd[cs_fill_odd].data = &data[l + offset];
cs_tsbbatch_odd[cs_fill_odd].len = payload_len;
cs_fill_odd++;
}
#ifndef LIBDVBCSA
if (newRange)
{
r += 2;
newRange = false;
range[r] = &data[l];
range[r + 2] = 0;
}
range[r + 1] = &data[l + TS_SIZE];
#else
data[l + 3] &= 0x3f; // consider it decrypted now
if (((ev_od & 0x40) >> 6) == 0)
{
cs_tsbbatch_even[cs_fill_even].data = &data[l + offset];
cs_tsbbatch_even[cs_fill_even].len = payload_len;
cs_fill_even++;
}
else
{
cs_tsbbatch_odd[cs_fill_odd].data = &data[l + offset];
cs_tsbbatch_odd[cs_fill_odd].len = payload_len;
cs_fill_odd++;
}
#endif
if (++ccs >= cs)
break;
if (++ccs >= cs)
break;
}
}
#ifndef LIBDVBCSA
else
@@ -249,6 +282,8 @@ bool DeCSA::Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool fo
// nothing, we don't create holes for unencrypted packets
}
}
if (algo[currIdx] == CA_ALGO_DES)
return true;
#ifndef LIBDVBCSA
if (r >= 0)
{ // we have some range
View
@@ -51,6 +51,8 @@ class DeCSA
struct dvbcsa_bs_key_s *cs_key_even[MAX_CSA_IDX];
struct dvbcsa_bs_key_s *cs_key_odd[MAX_CSA_IDX];
#endif
uint32_t des_key_schedule[MAX_CSA_IDX][2][32];
uint32_t algo[MAX_CSA_IDX];
time_t cwSeen[MAX_CSA_IDX]; // last time the CW for the related key was seen
map<pair<int, int>, unsigned char> pidmap;
cMutex mutex;
@@ -67,6 +69,7 @@ class DeCSA
bool Decrypt(uint8_t adapter_index, unsigned char *data, int len, bool force);
bool SetDescr(ca_descr_t *ca_descr, bool initial);
bool SetCaPid(uint8_t adapter_index, ca_pid_t *ca_pid);
void SetAlgo(uint32_t index, uint32_t usedAlgo);
};
extern DeCSA *decsa;
View
@@ -58,7 +58,7 @@ endif
### The object files (add further files here):
OBJS = CAPMT.o DeCSA.o DVBAPI.o DVBAPISetup.o SocketHandler.o SCCIAdapter.o Frame.o SCCAMSlot.o Filter.o
OBJS = CAPMT.o DeCSA.o DVBAPI.o DVBAPISetup.o SocketHandler.o SCCIAdapter.o Frame.o SCCAMSlot.o Filter.o cscrypt/des.o
ifndef LIBDVBCSA
# FFdeCSA
View
@@ -334,6 +334,8 @@ void SocketHandler::Action(void)
cRead = recv(sock, buff+4, sizeof(ca_pid_t), MSG_DONTWAIT);
else if (*request == CA_SET_DESCR)
cRead = recv(sock, buff+4, sizeof(ca_descr_t), MSG_DONTWAIT);
else if (*request == CA_SET_DESCR_MODE)
cRead = recv(sock, buff+4, sizeof(ca_descr_mode_t), MSG_DONTWAIT);
else if (*request == DMX_SET_FILTER)
cRead = recv(sock, buff+4, 2 + sizeof(struct dmx_sct_filter_params) + (protocol_version >= 1 ? -2 : 0), MSG_DONTWAIT);
else if (*request == DMX_STOP)
@@ -394,6 +396,22 @@ void SocketHandler::Action(void)
decsa->SetDescr(&ca_descr, false);
DEBUGLOG("%s: Got CA_SET_DESCR request, adapter_index=%d, index=%x", __FUNCTION__, adapter_index, ca_descr.index);
}
else if (*request == CA_SET_DESCR_MODE)
{
memcpy(&ca_descr_mode, &buff[sizeof(int)], sizeof(ca_descr_mode_t));
if (protocol_version >= 1)
{
ca_descr_mode.index = ntohl(ca_descr_mode.index);
ca_descr_mode.algo = (ca_descr_algo) ntohl(ca_descr_mode.algo);
}
else if (changeEndianness)
{
ca_descr_mode.index = htonl(ca_descr_mode.index);
ca_descr_mode.algo = (ca_descr_algo) htonl(ca_descr_mode.algo);
}
decsa->SetAlgo(ca_descr_mode.index, ca_descr_mode.algo);
DEBUGLOG("%s: Got CA_SET_DESCR_MODE request, adapter_index=%d, index=%x", __FUNCTION__, adapter_index, ca_descr.index);
}
else if (*request == DMX_SET_FILTER)
{
unsigned char demux_index = buff[4];
View
@@ -39,9 +39,27 @@
#define DVBAPI_CLIENT_INFO 0xFFFF0001
#define DVBAPI_SERVER_INFO 0xFFFF0002
#define DVBAPI_ECM_INFO 0xFFFF0003
#define CA_SET_DESCR_MODE 0x400c6f88
#define INFO_VERSION "vdr-plugin-dvbapi " VERSION " / VDR " VDRVERSION
enum ca_descr_algo {
CA_ALGO_DVBCSA,
CA_ALGO_DES,
CA_ALGO_AES128,
};
enum ca_descr_cipher_mode {
CA_MODE_ECB,
CA_MODE_CBC,
};
typedef struct ca_descr_mode {
uint32_t index;
enum ca_descr_algo algo;
enum ca_descr_cipher_mode cipher_mode;
} ca_descr_mode_t;
extern int OSCamNetworkMode;
extern char OSCamHost[HOST_NAME_MAX];
extern int OSCamPort;
@@ -64,6 +82,7 @@ class SocketHandler : public cThread
int sock;
cMutex mutex;
ca_descr_t ca_descr;
ca_descr_mode_t ca_descr_mode;
ca_pid_t ca_pid;
dmx_sct_filter_params sFP2;
cTimeMs checkTimer;

0 comments on commit b4cd00a

Please sign in to comment.