Commit 320337e0 authored by Kaloyan Kovachev's avatar Kaloyan Kovachev Committed by Rémi Denis-Courmont

Dynamic two-keys CSA

N.B.: I suspect there is a small race condition whereby the callbacks are
invoked while being deleted, but this looks like yet another LibVLC
objects insanity.
Signed-off-by: default avatarRémi Denis-Courmont <rdenis@simphalempin.com>
parent 75bd4e63
......@@ -87,6 +87,11 @@
* - ...
*/
/*****************************************************************************
* Callback prototypes
*****************************************************************************/
static int ChangeKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
......@@ -113,6 +118,10 @@ static void Close ( vlc_object_t * );
#define CSA_TEXT N_("CSA ck")
#define CSA_LONGTEXT N_("Control word for the CSA encryption algorithm")
#define CSA2_TEXT N_("Second CSA Key")
#define CSA2_LONGTEXT N_("The even CSA encryption key. This must be a " \
"16 char string (8 hexadecimal bytes).")
#define SILENT_TEXT N_("Silent mode")
#define SILENT_LONGTEXT N_("Do not complain on encrypted PES.")
......@@ -149,6 +158,7 @@ vlc_module_begin();
add_integer( "ts-out-mtu", 1400, NULL, MTUOUT_TEXT,
MTUOUT_LONGTEXT, true );
add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
add_string( "ts-csa2-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
add_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true );
add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, true );
......@@ -311,6 +321,8 @@ typedef struct
struct demux_sys_t
{
vlc_mutex_t csa_lock;
/* TS packet size (188, 192, 204) */
int i_packet_size;
......@@ -539,6 +551,7 @@ static int Open( vlc_object_t *p_this )
return VLC_ENOMEM;
memset( p_sys, 0, sizeof( demux_sys_t ) );
p_sys->i_packet_size = i_packet_size;
vlc_mutex_init( &p_sys->csa_lock );
/* Fill dump mode fields */
p_sys->i_write = 0;
......@@ -773,24 +786,42 @@ static int Open( vlc_object_t *p_this )
}
free( val.psz_string );
var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
var_Get( p_demux, "ts-csa-ck", &val );
if( val.psz_string && *val.psz_string )
{
int i_res;
vlc_value_t csa2;
p_sys->csa = csa_New();
i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, 1 );
if( i_res != VLC_SUCCESS || csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, 0 ) != VLC_SUCCESS )
var_Create( p_demux, "ts-csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND);
var_Get( p_demux, "ts-csa2-ck", &csa2 );
i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, true );
if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
{
if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
{
csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
}
}
else if ( i_res == VLC_SUCCESS )
{
csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
}
else
{
csa_Delete( p_sys->csa );
p_sys->csa = NULL;
}
if( p_sys->csa )
{
vlc_value_t pkt_val;
var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 );
var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
var_Create( p_demux, "ts-csa-pkt", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Get( p_demux, "ts-csa-pkt", &pkt_val );
if( pkt_val.i_int < 4 || pkt_val.i_int > 188 )
......@@ -802,6 +833,7 @@ static int Open( vlc_object_t *p_this )
else p_sys->i_csa_pkt_size = pkt_val.i_int;
msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
}
free( csa2.psz_string );
}
free( val.psz_string );
......@@ -873,10 +905,15 @@ static void Close( vlc_object_t *p_this )
net_Close( p_sys->fd );
free( p_sys->buffer );
}
vlc_mutex_lock( &p_sys->csa_lock );
if( p_sys->csa )
{
var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
csa_Delete( p_sys->csa );
p_sys->csa = NULL;
}
vlc_mutex_unlock( &p_sys->csa_lock );
if( p_sys->i_pmt ) free( p_sys->pmt );
......@@ -905,9 +942,32 @@ static void Close( vlc_object_t *p_this )
free( p_sys->psz_file );
p_sys->psz_file = NULL;
vlc_mutex_destroy( &p_sys->csa_lock );
free( p_sys );
}
/*****************************************************************************
* ChangeKeyCallback: called when changing the odd encryption key on the fly.
*****************************************************************************/
static int ChangeKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys;
int i_tmp = (intptr_t)p_data;
vlc_mutex_lock( &p_sys->csa_lock );
if ( i_tmp )
i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, true );
else
i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, false );
vlc_mutex_unlock( &p_sys->csa_lock );
return i_tmp;
}
/*****************************************************************************
* DemuxFile:
*****************************************************************************/
......@@ -997,7 +1057,11 @@ static int DemuxFile( demux_t *p_demux )
/* Test if user wants to decrypt it first */
if( p_sys->csa )
{
vlc_mutex_lock( &p_sys->csa_lock );
csa_Decrypt( p_demux->p_sys->csa, &p_buffer[i_pos], p_demux->p_sys->i_csa_pkt_size );
vlc_mutex_unlock( &p_sys->csa_lock );
}
i_pos += p_sys->i_packet_size;
}
......@@ -1789,7 +1853,9 @@ static bool GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
if( p_demux->p_sys->csa )
{
vlc_mutex_lock( &p_demux->p_sys->csa_lock );
csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer, p_demux->p_sys->i_csa_pkt_size );
vlc_mutex_unlock( &p_demux->p_sys->csa_lock );
}
if( !b_adaptation )
......
......@@ -50,6 +50,8 @@ struct csa_t
int X, Y, Z;
int D, E, F;
int p, q, r;
bool use_odd;
};
static void csa_ComputeKey( uint8_t kk[57], uint8_t ck[8] );
......@@ -81,12 +83,12 @@ void csa_Delete( csa_t *c )
/*****************************************************************************
* csa_SetCW:
*****************************************************************************/
int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, int set_odd )
int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, bool set_odd )
{
if ( !c )
{
msg_Dbg( p_caller, "no CSA found" );
return VLC_EGENERIC;
return VLC_ENOOBJ;
}
/* skip 0x */
if( psz_ck[0] == '0' && ( psz_ck[1] == 'x' || psz_ck[1] == 'X' ) )
......@@ -96,7 +98,7 @@ int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, int set_odd )
if( strlen( psz_ck ) != 16 )
{
msg_Warn( p_caller, "invalid csa ck (it must be 16 chars long)" );
return VLC_EGENERIC;
return VLC_EBADVAR;
}
else
{
......@@ -113,23 +115,38 @@ int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, int set_odd )
ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
}
#ifndef TS_NO_CSA_CK_MSG
msg_Dbg( p_caller, "using CSA (de)scrambling with %s key=%x:%x:%x:%x:%x:%x:%x:%x", ((set_odd == 1) ? "odd" : "even" ),
msg_Dbg( p_caller, "using CSA (de)scrambling with %s "
"key=%x:%x:%x:%x:%x:%x:%x:%x", set_odd ? "odd" : "even",
ck[0], ck[1], ck[2], ck[3], ck[4], ck[5], ck[6], ck[7] );
#endif
if ( set_odd == 1 )
if( set_odd )
{
memcpy( c->o_ck, ck, 8 );
csa_ComputeKey( c->o_kk, ck );
memcpy( c->o_ck, ck, 8 );
csa_ComputeKey( c->o_kk, ck );
}
else
{
memcpy( c->e_ck , ck, 8 );
csa_ComputeKey( c->e_kk , ck );
memcpy( c->e_ck , ck, 8 );
csa_ComputeKey( c->e_kk , ck );
}
return VLC_SUCCESS;
}
}
/*****************************************************************************
* csa_UseKey:
*****************************************************************************/
int csa_UseKey( vlc_object_t *p_caller, csa_t *c, bool use_odd )
{
if ( !c ) return VLC_ENOOBJ;
c->use_odd = use_odd;
#ifndef TS_NO_CSA_CK_MSG
msg_Dbg( p_caller, "using the %s key for scrambling",
use_odd ? "odd" : "even" );
#endif
return VLC_SUCCESS;
}
/*****************************************************************************
* csa_Decrypt:
*****************************************************************************/
......@@ -222,7 +239,7 @@ void csa_Decrypt( csa_t *c, uint8_t *pkt, int i_pkt_size )
/*****************************************************************************
* csa_Encrypt:
*****************************************************************************/
void csa_Encrypt( csa_t *c, uint8_t *pkt, int i_pkt_size, int b_odd )
void csa_Encrypt( csa_t *c, uint8_t *pkt, int i_pkt_size )
{
uint8_t *ck;
uint8_t *kk;
......@@ -234,13 +251,10 @@ void csa_Encrypt( csa_t *c, uint8_t *pkt, int i_pkt_size, int b_odd )
/* set transport scrambling control */
pkt[3] |= 0x80;
if( b_odd )
{
pkt[3] |= 0x40;
}
if( b_odd )
if( c->use_odd )
{
pkt[3] |= 0x40;
ck = c->o_ck;
kk = c->o_kk;
}
......
......@@ -28,15 +28,17 @@ typedef struct csa_t csa_t;
#define csa_New __csa_New
#define csa_Delete __csa_Delete
#define csa_SetCW __csa_SetCW
#define csa_UseKey __csa_UseKey
#define csa_Decrypt __csa_decrypt
#define csa_Encrypt __csa_encrypt
csa_t *csa_New( void );
void csa_Delete( csa_t * );
int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, int set_odd );
int csa_SetCW( vlc_object_t *p_caller, csa_t *c, char *psz_ck, bool odd );
int csa_UseKey( vlc_object_t *p_caller, csa_t *, bool use_odd );
void csa_Decrypt( csa_t *, uint8_t *pkt, int i_pkt_size );
void csa_Encrypt( csa_t *, uint8_t *pkt, int i_pkt_size, int b_odd );
void csa_Encrypt( csa_t *, uint8_t *pkt, int i_pkt_size );
#endif /* _CSA_H */
......@@ -79,6 +79,13 @@
* if they arrive a bit late
* (We cannot rely on the fact that the fifo should be full)
*/
/*****************************************************************************
* Callback prototypes
*****************************************************************************/
static int ChangeKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
static int ActiveKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
......@@ -160,6 +167,14 @@ static void Close ( vlc_object_t * );
#define CK_LONGTEXT N_("CSA encryption key. This must be a " \
"16 char string (8 hexadecimal bytes).")
#define CK2_TEXT N_("Second CSA Key")
#define CK2_LONGTEXT N_("The even CSA encryption key. This must be a " \
"16 char string (8 hexadecimal bytes).")
#define CU_TEXT N_("CSA Key in use")
#define CU_LONGTEXT N_("CSA encryption key used. It can be the odd/first/1 " \
"(default) or the even/second/2 one.")
#define CPKT_TEXT N_("Packet size in bytes to encrypt")
#define CPKT_LONGTEXT N_("Size of the TS packet to encrypt. " \
"The encryption routines subtract the TS-header from the value before " \
......@@ -227,6 +242,10 @@ vlc_module_begin();
add_string( SOUT_CFG_PREFIX "csa-ck", NULL, NULL, CK_TEXT, CK_LONGTEXT,
true );
add_string( SOUT_CFG_PREFIX "csa2-ck", NULL, NULL, CK2_TEXT, CK2_LONGTEXT,
true );
add_string( SOUT_CFG_PREFIX "csa-use", "1", NULL, CU_TEXT, CU_LONGTEXT,
true );
add_integer( SOUT_CFG_PREFIX "csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true );
set_callbacks( Open, Close );
......@@ -238,7 +257,7 @@ vlc_module_end();
static const char *const ppsz_sout_options[] = {
"pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "netid",
"es-id-pid", "shaping", "pcr", "bmin", "bmax", "use-key-frames",
"dts-delay", "csa-ck", "csa-pkt", "crypt-audio", "crypt-video",
"dts-delay", "csa-ck", "csa2-ck", "csa-use", "csa-pkt", "crypt-audio", "crypt-video",
"muxpmt", "sdtdesc", "program-pmt", "alignment",
NULL
};
......@@ -356,6 +375,8 @@ struct sout_mux_sys_t
int i_pcr_pid;
sout_input_t *p_pcr_input;
vlc_mutex_t csa_lock;
int i_audio_bound;
int i_video_bound;
......@@ -493,6 +514,8 @@ static int Open( vlc_object_t *p_this )
p_sys->dvbpmt = NULL;
memset( &p_sys->pmtmap, 0, sizeof(p_sys->pmtmap) );
vlc_mutex_init( &p_sys->csa_lock );
p_mux->pf_control = Control;
p_mux->pf_addstream = AddStream;
p_mux->pf_delstream = DelStream;
......@@ -768,22 +791,49 @@ static int Open( vlc_object_t *p_this )
p_sys->i_pcr = 0;
p_sys->csa = NULL;
var_Create( p_mux, SOUT_CFG_PREFIX "csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
var_Get( p_mux, SOUT_CFG_PREFIX "csa-ck", &val );
if( val.psz_string && *val.psz_string )
{
int i_res;
vlc_value_t csa2;
p_sys->csa = csa_New();
i_res = csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, 1 );
if( i_res != VLC_SUCCESS || csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, 0 ) != VLC_SUCCESS )
var_Create( p_mux, SOUT_CFG_PREFIX "csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
var_Get( p_mux, SOUT_CFG_PREFIX "csa2-ck", &csa2 );
i_res = csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, true );
if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
{
if( csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
{
csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
}
}
else if( i_res == VLC_SUCCESS )
{
csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
}
else
{
csa_Delete( p_sys->csa );
}
if( p_sys->csa )
{
vlc_value_t pkt_val;
vlc_value_t use_val, pkt_val;
var_Create( p_mux, SOUT_CFG_PREFIX "csa-use", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
var_Get( p_mux, SOUT_CFG_PREFIX "csa-use", &use_val );
var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, (void *)1 );
var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
if ( var_Set( p_mux, SOUT_CFG_PREFIX "csa-use", use_val ) != VLC_SUCCESS )
{
var_SetString( p_mux, SOUT_CFG_PREFIX "csa-use", "odd" );
}
free( use_val.psz_string );
var_Get( p_mux, SOUT_CFG_PREFIX "csa-pkt", &pkt_val );
if( pkt_val.i_int < 12 || pkt_val.i_int > 188 )
......@@ -795,6 +845,7 @@ static int Open( vlc_object_t *p_this )
else p_sys->i_csa_pkt_size = pkt_val.i_int;
msg_Dbg( p_mux, "encrypting %d bytes of packet", p_sys->i_csa_pkt_size );
}
free( csa2.psz_string );
}
free( val.psz_string );
......@@ -816,10 +867,17 @@ static void Close( vlc_object_t * p_this )
sout_mux_sys_t *p_sys = p_mux->p_sys;
int i;
vlc_mutex_lock( &p_sys->csa_lock );
if( p_sys->csa )
{
var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, NULL );
var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
csa_Delete( p_sys->csa );
}
vlc_mutex_unlock( &p_sys->csa_lock );
vlc_mutex_destroy( &p_sys->csa_lock );
for( i = 0; i < MAX_PMT; i++ )
{
free( p_sys->sdt_descriptors[i].psz_service_name );
......@@ -830,6 +888,58 @@ static void Close( vlc_object_t * p_this )
free( p_sys );
}
/*****************************************************************************
* ChangeKeyCallback: called when changing the odd encryption key on the fly.
*****************************************************************************/
static int ChangeKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
sout_mux_t *p_mux = (sout_mux_t*)p_this;
sout_mux_sys_t *p_sys = p_mux->p_sys;
int i_tmp = (int)p_data;
vlc_mutex_lock( &p_sys->csa_lock );
if ( i_tmp )
{
i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, true );
}
else
{
i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, false );
}
vlc_mutex_unlock( &p_sys->csa_lock );
return i_tmp;
}
/*****************************************************************************
* ActiveKeyCallback: called when changing the active (in use) encryption key on the fly.
*****************************************************************************/
static int ActiveKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
sout_mux_t *p_mux = (sout_mux_t*)p_this;
sout_mux_sys_t *p_sys = p_mux->p_sys;
int i_res = VLC_EBADVAR;
vlc_mutex_lock( &p_sys->csa_lock );
if( !strcmp(newval.psz_string, "odd" ) || !strcmp(newval.psz_string, "first" ) || !strcmp(newval.psz_string, "1" ) )
{
i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 1 );
}
else if( !strcmp(newval.psz_string, "even" ) || !strcmp(newval.psz_string, "second" ) || !strcmp(newval.psz_string, "2" ) )
{
i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 0 );
}
vlc_mutex_unlock( &p_sys->csa_lock );
return i_res;
}
/*****************************************************************************
* Control:
*****************************************************************************/
......@@ -1869,7 +1979,9 @@ static void TSDate( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
}
if( p_ts->i_flags & BLOCK_FLAG_SCRAMBLED )
{
csa_Encrypt( p_sys->csa, p_ts->p_buffer, p_sys->i_csa_pkt_size, 0 );
vlc_mutex_lock( &p_sys->csa_lock );
csa_Encrypt( p_sys->csa, p_ts->p_buffer, p_sys->i_csa_pkt_size );
vlc_mutex_unlock( &p_sys->csa_lock );
}
/* latency */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment