* - ...
*/
+/*****************************************************************************
+ * Callback prototypes
+ *****************************************************************************/
+static int ChangeKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#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.")
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 );
struct demux_sys_t
{
+ vlc_mutex_t csa_lock;
+
/* TS packet size (188, 192, 204) */
int i_packet_size;
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;
}
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 )
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 );
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 );
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:
*****************************************************************************/
/* 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;
}
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 )
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] );
/*****************************************************************************
* 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' ) )
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
{
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:
*****************************************************************************/
/*****************************************************************************
* 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;
/* 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;
}
#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 */
* 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
*****************************************************************************/
#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 " \
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 );
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
};
int i_pcr_pid;
sout_input_t *p_pcr_input;
+ vlc_mutex_t csa_lock;
+
int i_audio_bound;
int i_video_bound;
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;
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 )
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 );
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 );
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:
*****************************************************************************/
}
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 */