]> git.sesse.net Git - vlc/commitdiff
Dynamic two-keys CSA
authorKaloyan Kovachev <kkovachev@varna.net>
Wed, 11 Jun 2008 15:22:14 +0000 (18:22 +0300)
committerRémi Denis-Courmont <rdenis@simphalempin.com>
Sun, 15 Jun 2008 16:17:42 +0000 (19:17 +0300)
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: Rémi Denis-Courmont <rdenis@simphalempin.com>
modules/demux/ts.c
modules/mux/mpeg/csa.c
modules/mux/mpeg/csa.h
modules/mux/mpeg/ts.c

index b98666c0cf5406a9606c8fb23c6f4323c1892017..a6b0fe9bac6457325b71ba7ffe480b937b8456a8 100644 (file)
  *  - ...
  */
 
+/*****************************************************************************
+ * 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 )
index ea7b5897d5a700a7e23154f636b41e4460a0d352..9550297473671bf4dc0a0572cf9f193e486fb302 100644 (file)
@@ -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;
     }
index 18c1ecc97b0eec2b5e4265c269715188dbd021cc..288836607bd9995b0069bfd1600a16d92c8905d8 100644 (file)
@@ -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 */
index c2007cf260617f4c3053bbb633a4b1533c2910d5..7061ddf55ba2ac0c6393cdbab22bcaa02d78b9dd 100644 (file)
  *    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 */