diff --git a/openair2/LAYER2/Makefile.inc b/openair2/LAYER2/Makefile.inc
index 85100ca6f7ce909a3d9fb3bcc266a851f950e2c7..41cac88a1e83d43abc0c153930229bb6c6f1c995 100644
--- a/openair2/LAYER2/Makefile.inc
+++ b/openair2/LAYER2/Makefile.inc
@@ -26,6 +26,7 @@ SOURCES_L2 +=  $(PDCP_DIR)/pdcp_fifo.c
 SOURCES_L2 +=  $(PDCP_DIR)/pdcp_sequence_manager.c
 SOURCES_L2 +=  $(PDCP_DIR)/pdcp_primitives.c
 SOURCES_L2 +=  $(PDCP_DIR)/pdcp_util.c
+SOURCES_L2 +=  $(PDCP_DIR)/pdcp_security.c
 
 SOURCES_L2 +=  $(RLC_AM_DIR)/rlc_am.c
 SOURCES_L2 +=  $(RLC_AM_DIR)/rlc_am_init.c
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
index 29f5d9f773bb97e0b85cd699a5de7751c1440f73..635418ed8d018da3a67752fdd9d883e462491980 100755
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
@@ -52,6 +52,10 @@
 #include "platform_constants.h"
 #include "UTIL/LOG/vcd_signal_dumper.h"
 
+#if defined(ENABLE_SECURITY)
+# include "UTIL/OSA/osa_defs.h"
+#endif
+
 #define PDCP_DATA_REQ_DEBUG 0
 #define PDCP_DATA_IND_DEBUG 0
 
@@ -94,7 +98,7 @@ BOOL pdcp_data_req(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb
   mem_block_t* pdcp_pdu = NULL;
   rlc_op_status_t rlc_status;
 
-  if ((pdcp->instanciated_instance == 0) && (mode != PDCP_TM)) {
+ if ((pdcp->instanciated_instance == 0) && (mode != PDCP_TM)) {
     LOG_W(PDCP, "Instance is not configured, Ignoring SDU...\n");
     return FALSE;
   }
@@ -178,16 +182,28 @@ BOOL pdcp_data_req(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb
         free_mem_block(pdcp_pdu);
         return FALSE;
       }
-      
+
       LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn);
-      
+
       /* Then append data... */
       memcpy(&pdcp_pdu->data[pdcp_header_len], sdu_buffer, sdu_buffer_size);
+
       //For control plane data that are not integrity protected,
       // the MAC-I field is still present and should be padded with padding bits set to 0.
+      // NOTE: user-plane data are never integrity protected
       for (i=0;i<pdcp_tailer_len;i++)
-        pdcp_pdu->data[pdcp_header_len + sdu_buffer_size + i] = 0x00;// pdu_header.mac_i[i];
-      
+          pdcp_pdu->data[pdcp_header_len + sdu_buffer_size + i] = 0x00;// pdu_header.mac_i[i];
+
+#if defined(ENABLE_SECURITY)
+      if ((pdcp->security_activated != 0) &&
+          ((pdcp->cipheringAlgorithm) != 0) &&
+          ((pdcp->integrityProtAlgorithm) != 0)) {
+        pdcp_apply_security(pdcp, rb_id % NB_RB_MAX,
+                            pdcp_header_len, current_sn, pdcp_pdu->data,
+                            sdu_buffer_size);
+      }
+#endif
+
       /* Print octets of outgoing data in hexadecimal form */
       LOG_D(PDCP, "Following content with size %d will be sent over RLC (PDCP PDU header is the first two bytes)\n",
             pdcp_pdu_size);
@@ -275,7 +291,8 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb
   u16 sequence_number;
   u8 payload_offset=0;
 
-  LOG_I(PDCP,"Data indication notification for PDCP entity with module ID %d and radio bearer ID %d rlc sdu size %d\n", module_id, rb_id, sdu_buffer_size);
+  LOG_I(PDCP,"Data indication notification for PDCP entity with module "
+  "ID %d and radio bearer ID %d rlc sdu size %d eNB_flag %d\n", module_id, rb_id, sdu_buffer_size, eNB_flag);
 
   if (sdu_buffer_size == 0) {
     LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!");
@@ -335,18 +352,13 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb
     }
     // SRB1/2: control-plane data
     if ( (rb_id % NB_RB_MAX) <  DTCH ){
-      /*new_sdu = get_free_mem_block(sdu_buffer_size - pdcp_header_len - pdcp_tailer_len);
-	  if (new_sdu) {
-	  memcpy(new_sdu->data,
-	  &sdu_buffer->data[pdcp_header_len],
-	  sdu_buffer_size - pdcp_header_len - pdcp_tailer_len);
-	  rrc_lite_data_ind(module_id,
-	  frame,
-	  eNB_flag,
-	  rb_id,
-	  sdu_buffer_size - pdcp_header_len - pdcp_tailer_len,
-	  new_sdu->data);
-	  }*/
+#if defined(ENABLE_SECURITY)
+      if (pdcp->security_activated == 1) {
+        pdcp_validate_security(pdcp, rb_id % NB_RB_MAX, pdcp_header_len,
+                               sequence_number, sdu_buffer->data,
+                               sdu_buffer_size - pdcp_tailer_len);
+      }
+#endif
       //rrc_lite_data_ind(module_id, //Modified MW - L2 Interface
       pdcp_rrc_data_ind(module_id,
                         frame,
@@ -359,6 +371,13 @@ BOOL pdcp_data_ind(module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rb
       return TRUE;
     }
     payload_offset=PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE;
+#if defined(ENABLE_SECURITY)
+    if (pdcp->security_activated == 1) {
+        pdcp_validate_security(pdcp, rb_id % NB_RB_MAX, pdcp_header_len,
+                               sequence_number, sdu_buffer->data,
+                               sdu_buffer_size - pdcp_tailer_len);
+    }
+#endif
   } else {
     payload_offset=0;
   }
@@ -493,9 +512,6 @@ void
   // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer
   pdcp_fifo_read_input_sdus(frame,eNB_flag);
 
-  // NAS -> PDCP traffic
-  pdcp_fifo_read_input_sdus(frame,eNB_flag);
-
   // PDCP -> NAS/IP traffic: RX
   pdcp_fifo_flush_sdus(frame,eNB_flag);
 
@@ -505,9 +521,13 @@ void
 BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index,
                                SRB_ToAddModList_t* srb2add_list,
                                DRB_ToAddModList_t* drb2add_list,
-                               DRB_ToReleaseList_t*  drb2release_list
+                               DRB_ToReleaseList_t*  drb2release_list,
+                               u8 security_mode,
+                               u8 *kRRCenc,
+                               u8 *kRRCint,
+                               u8 *kUPenc
 #ifdef Rel10
-                               ,PMCH_InfoList_r9_t*  pmch_InfoList_r9
+                              ,PMCH_InfoList_r9_t*  pmch_InfoList_r9
 #endif
                                ){
 
@@ -537,7 +557,6 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
         (eNB_flag == 1)? "eNB": "UE", index);
   // srb2add_list does not define pdcp config, we use rlc info to setup the pdcp dcch0 and dcch1 channels
 
-
   if (srb2add_list != NULL) {
     for (cnt=0;cnt<srb2add_list->list.count;cnt++) {
       srb_id = srb2add_list->list.array[cnt]->srb_Identity;
@@ -570,7 +589,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
                                   srb_sn,
                                   0, // drb_report
                                   0, // header compression
-                                  0xff); //UNDEF_SECURITY_MODE
+                                  security_mode,
+                                  kRRCenc,
+                                  kRRCint,
+                                  kUPenc);
             break;
           }
           break;
@@ -659,7 +681,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
                               drb_sn,
                               drb_report,
                               header_compression_profile,
-                              0xff);
+                              security_mode,
+                              kRRCenc,
+                              kRRCint,
+                              kUPenc);
       }
     }
   }
@@ -681,7 +706,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
                             0,
                             0,
                             0,
-                            0xff);
+                            security_mode,
+                            kRRCenc,
+                            kRRCint,
+                            kUPenc);
     }
   }
 
@@ -717,7 +745,10 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
                               0, // set to deafult
                               0,
                               0,
-                              0xff);
+                              security_mode,
+                              kRRCenc,
+                              kRRCint,
+                              kUPenc);
       }
     }
   }
@@ -727,18 +758,19 @@ BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag
 
 }
 
-
 BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index,
                            rlc_mode_t rlc_mode, u32  action, u16 lc_id,u16 mch_id, rb_id_t rb_id,
                            u8 rb_sn, u8 rb_report, u16 header_compression_profile,
-                           u8 security_mode){
+                           u8 security_mode,
+                           u8 *kRRCenc,
+                           u8 *kRRCint,
+                           u8 *kUPenc){
   switch (action) {
   case ACTION_ADD:
     pdcp_array[module_id][lc_id].instanciated_instance = module_id + 1;
+    pdcp_array[module_id][lc_id].is_ue = (eNB_flag == 0) ? 1 : 0;
     pdcp_array[module_id][lc_id].lcid = lc_id;
     pdcp_array[module_id][lc_id].header_compression_profile=header_compression_profile;
-    pdcp_array[module_id][lc_id].cipheringAlgorithm=security_mode & 0x0f;
-    pdcp_array[module_id][lc_id].integrityProtAlgorithm=(security_mode>>4) & 0xf;
     pdcp_array[module_id][lc_id].status_report = rb_report;
     if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits)
       pdcp_array[module_id][lc_id].seq_num_size = 7;
@@ -761,16 +793,24 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16
           frame, lc_id, rb_id, pdcp_array[module_id][lc_id].seq_num_size,
           (rlc_mode == 1) ? "AM" : (rlc_mode == 2) ? "TM" : "UM");
 
+    /* Setup security */
+    if (security_mode != 0xff) {
+        pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc);
+    }
+
     LOG_D(PDCP,  "[MSC_NEW][FRAME %05d][PDCP][MOD %02d][RB %02d]\n", frame, module_id,rb_id);
 
     break;
     case ACTION_MODIFY:
     pdcp_array[module_id][lc_id].header_compression_profile=header_compression_profile;
-    pdcp_array[module_id][lc_id].cipheringAlgorithm=security_mode & 0x0f;
-    pdcp_array[module_id][lc_id].integrityProtAlgorithm=(security_mode>>4) & 0xf;
     pdcp_array[module_id][lc_id].status_report = rb_report;
     pdcp_array[module_id][lc_id].rlc_mode = rlc_mode;
 
+    /* Setup security */
+    if (security_mode != 0xff) {
+        pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc);
+    }
+
     if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits)
       pdcp_array[module_id][lc_id].seq_num_size = 7;
     else if (rb_sn == PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits)
@@ -800,8 +840,21 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16
     pdcp_array[module_id][lc_id].last_submitted_pdcp_rx_sn = 4095;
     pdcp_array[module_id][lc_id].seq_num_size = 0;
     pdcp_array[module_id][lc_id].first_missing_pdu = -1;
+    pdcp_array[module_id][lc_id].security_activated = 0;
+
     LOG_I(PDCP,"[%s %d] Config request : ACTION_REMOVE: Frame %d LCID %d RBID %d configured\n",
-          (eNB_flag) ? "eNB" : "UE", module_id, frame, lc_id,rb_id);
+          (eNB_flag) ? "eNB" : "UE", module_id, frame, lc_id, rb_id);
+    /* Security keys */
+    if (pdcp_array[module_id][lc_id].kUPenc != NULL) {
+        free(pdcp_array[module_id][lc_id].kUPenc);
+    }
+    if (pdcp_array[module_id][lc_id].kRRCint != NULL) {
+        free(pdcp_array[module_id][lc_id].kRRCint);
+    }
+    if (pdcp_array[module_id][lc_id].kRRCenc != NULL) {
+        free(pdcp_array[module_id][lc_id].kRRCenc);
+    }
+
 
     break;
     case ACTION_MBMS_ADD:
@@ -814,23 +867,37 @@ BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16
           (eNB_flag == 1) ? "eNB" : "UE", module_id, frame, mch_id, lc_id, rb_id);
     break;
     case ACTION_SET_SECURITY_MODE:
-    if ((security_mode >= 0 ) && (security_mode <=0x77)) {
-      pdcp_array[module_id][lc_id].cipheringAlgorithm= security_mode & 0x0f;
-      pdcp_array[module_id][lc_id].integrityProtAlgorithm = (security_mode>>4) & 0xf;
-      LOG_D(PDCP,"[%s %d] Set security mode : ACTION_SET_SECURITY_MODE: Frame %d  cipheringAlgorithm %d integrityProtAlgorithm %d\n",
-            (eNB_flag) ? "eNB" : "UE", module_id, frame,
-            pdcp_array[module_id][lc_id].cipheringAlgorithm,
-            pdcp_array[module_id][lc_id].integrityProtAlgorithm );
-    }else
-      LOG_D(PDCP,"[%s %d] bad security mode %d", security_mode);
-    break;
+        pdcp_config_set_security(module_id, frame, eNB_flag, rb_id, lc_id, security_mode, kRRCenc, kRRCint, kUPenc);
+        break;
     default:
-    LOG_W(PDCP,"unknown action %d for the config request\n",action);
-    break;
+        LOG_W(PDCP,"unknown action %d for the config request\n",action);
+        break;
   }
   return 0;
 }
- 
+
+void pdcp_config_set_security(module_id_t module_id, u32 frame, u8 eNB_flag, rb_id_t rb_id,
+                              u16 lc_id, u8 security_mode, u8 *kRRCenc, u8 *kRRCint, u8 *kUPenc)
+{
+    if ((security_mode >= 0) && (security_mode <= 0x77)) {
+        pdcp_array[module_id][lc_id].cipheringAlgorithm     = security_mode & 0x0f;
+        pdcp_array[module_id][lc_id].integrityProtAlgorithm = (security_mode>>4) & 0xf;
+        LOG_D(PDCP,"[%s %d][RB %02d] Set security mode : ACTION_SET_SECURITY_MODE: "
+              "Frame %d  cipheringAlgorithm %d integrityProtAlgorithm %d\n",
+              (eNB_flag) ? "eNB" : "UE", module_id, rb_id, frame,
+              pdcp_array[module_id][lc_id].cipheringAlgorithm,
+              pdcp_array[module_id][lc_id].integrityProtAlgorithm);
+        pdcp_array[module_id][lc_id].kRRCenc = kRRCenc;
+        pdcp_array[module_id][lc_id].kRRCint = kRRCint;
+        pdcp_array[module_id][lc_id].kUPenc  = kUPenc;
+
+        /* Activate security */
+        pdcp_array[module_id][lc_id].security_activated = 1;
+    } else {
+        LOG_D(PDCP,"[%s %d] bad security mode %d", security_mode);
+    }
+}
+
 void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB_flag, u32  action, rb_id_t rb_id, u8 security_mode){
 
   /*
@@ -867,6 +934,7 @@ void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB_flag, u32
     pdcp_array[module_id][rb_id%NB_RB_MAX].last_submitted_pdcp_rx_sn = 4095;
     pdcp_array[module_id][rb_id%NB_RB_MAX].seq_num_size = 0;
     pdcp_array[module_id][rb_id%NB_RB_MAX].first_missing_pdu = -1;
+    pdcp_array[module_id][rb_id].security_activated = 0;
     LOG_D(PDCP,"[%s %d] Config request : ACTION_REMOVE: Frame %d radio bearer id %d configured\n",
           (eNB_flag) ? "eNB" : "UE", module_id, frame, rb_id);
 
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
index d24ed4f4f3ae8d23dd96238d2408b4ddefb6b55b..06e4420db3f40ebecbf92f811e40c22bb3b61564 100755
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
@@ -110,9 +110,26 @@ typedef struct pdcp_t {
   BOOL instanciated_instance;
   u16  header_compression_profile;
 
+  /* SR: added this flag to distinguish UE/eNB instance as pdcp_run for virtual
+   * mode can receive data on NETLINK for eNB while eNB_flag = 0 and for UE when eNB_flag = 1
+   */
+  u8 is_ue;
+
+  /* Configured security algorithms */
   u8 cipheringAlgorithm;
   u8 integrityProtAlgorithm;
 
+  /* User-Plane encryption key
+   * Control-Plane RRC encryption key
+   * Control-Plane RRC integrity key
+   * These keys are configured by RRC layer
+   */
+  u8 *kUPenc;
+  u8 *kRRCint;
+  u8 *kRRCenc;
+
+  u8 security_activated;
+
   u8 rlc_mode;
   u8 status_report;
   u8 seq_num_size;
@@ -260,14 +277,25 @@ public_pdcp(void rrc_pdcp_config_req (module_id_t module_id, u32 frame, u8_t eNB
 * \param[in]  srb2add_list      SRB configuration list to be created.
 * \param[in]  drb2add_list      DRB configuration list to be created.
 * \param[in]  drb2release_list  DRB configuration list to be released.
+* \param[in]  security_mode     Security algorithm to apply for integrity/ciphering
+* \param[in]  kRRCenc           RRC encryption key
+* \param[in]  kRRCint           RRC integrity key
+* \param[in]  kUPenc            User-Plane encryption key
 * \return     A status about the processing, OK or error code.
 */
+public_pdcp(
+BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index,
+                               SRB_ToAddModList_t* srb2add_list,
+                               DRB_ToAddModList_t* drb2add_list,
+                               DRB_ToReleaseList_t*  drb2release_list,
+                               u8 security_mode,
+                               u8 *kRRCenc,
+                               u8 *kRRCint,
+                               u8 *kUPenc
 #ifdef Rel10
-public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t*  drb2release_list,PMCH_InfoList_r9_t*  pmch_InfoList_r9);)
-#else
-public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, u32_t index, SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t*  drb2release_list);)
+                              ,PMCH_InfoList_r9_t*  pmch_InfoList_r9
 #endif
-
+                               ));
 
 /*! \fn BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u32  action, rb_id_t rb_id, u8 rb_sn, u8 rb_report, u16 header_compression_profile, u8 security_mode)
 * \brief  Function for RRC to configure a Radio Bearer.
@@ -280,10 +308,18 @@ public_pdcp(BOOL rrc_pdcp_config_asn1_req (module_id_t module_id, u32_t frame, u
 * \param[in]  drb_report         set a pdcp report for this drb
 * \param[in]  header_compression set the rohc profile
 * \param[in]  security_mode      set the integrity and ciphering algs
+* \param[in]  kRRCenc            RRC encryption key
+* \param[in]  kRRCint            RRC integrity key
+* \param[in]  kUPenc             User-Plane encryption key
 * \return     A status about the processing, OK or error code.
 */
-public_pdcp(BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index, rlc_mode_t rlc_mode, u32  action, u16 lc_id, u16 mch_id, rb_id_t rb_id, u8 rb_sn, u8 rb_report, u16 header_compression_profile, u8 security_mode);)
-
+public_pdcp(BOOL pdcp_config_req_asn1 (module_id_t module_id, u32 frame, u8_t eNB_flag, u16 index,
+                                       rlc_mode_t rlc_mode, u32  action, u16 lc_id,u16 mch_id, rb_id_t rb_id,
+                                       u8 rb_sn, u8 rb_report, u16 header_compression_profile,
+                                       u8 security_mode,
+                                       u8 *kRRCenc,
+                                       u8 *kRRCint,
+                                       u8 *kUPenc));
 /*! \fn void rrc_pdcp_config_release(module_id_t, rb_id_t)
 * \brief This functions is unused
 * \param[in] module_id Module ID of relevant PDCP entity
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h
index 587c1ee977093204cf5ab676237c5d0228f4f153..10b868bc08e5b8b58ccda82684d8a1d6dbc2b8db 100755
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h
@@ -153,4 +153,17 @@ BOOL pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_b
 BOOL pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, \
      u8 bitmap[512], pdcp_control_pdu_for_pdcp_status_report* pdu);
 
+void pdcp_config_set_security(module_id_t module_id, u32 frame, u8 eNB_flag, rb_id_t rb_id,
+                              u16 lc_id, u8 security_mode, u8 *kRRCenc, u8 *kRRCint, u8 *kUPenc);
+
+#if defined(ENABLE_SECURITY)
+int pdcp_apply_security(pdcp_t *pdcp_entity, rb_id_t rb_id,
+                        u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer,
+                        u16 sdu_buffer_size);
+
+int pdcp_validate_security(pdcp_t *pdcp_entity, rb_id_t rb_id,
+                           u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer,
+                           u16 sdu_buffer_size);
+#endif /* defined(ENABLE_SECURITY) */
+
 #endif
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c
new file mode 100644
index 0000000000000000000000000000000000000000..88cc5c72e98691594e044cc375f481070b3093c6
--- /dev/null
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c
@@ -0,0 +1,190 @@
+/*******************************************************************************
+
+  Eurecom OpenAirInterface
+  Copyright(c) 1999 - 2013 Eurecom
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information
+  Openair Admin: openair_admin@eurecom.fr
+  Openair Tech : openair_tech@eurecom.fr
+  Forums       : http://forums.eurecom.fsr/openairinterface
+  Address      : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France
+
+*******************************************************************************/
+/*! \file pdcp_security.c
+ * \brief PDCP Security Methods
+ * \author ROUX Sebastien
+ * \date 2013
+ */
+#include <stdint.h>
+
+#include "assertions.h"
+
+#include "UTIL/LOG/log.h"
+#include "UTIL/OSA/osa_defs.h"
+
+#include "LAYER2/MAC/extern.h"
+
+#include "pdcp.h"
+#include "pdcp_primitives.h"
+
+#if defined(ENABLE_SECURITY)
+
+static
+u32 pdcp_get_next_count_tx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn);
+static
+u32 pdcp_get_next_count_rx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn);
+
+static
+u32 pdcp_get_next_count_tx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn)
+{
+    u32 count;
+    /* For TX COUNT = TX_HFN << length of SN | pdcp SN */
+    if (pdcp_header_len == PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE) {
+        /* 5 bits length SN */
+        count = (pdcp_entity->tx_hfn << 5)  | (pdcp_sn & 0x001F);
+    } else {
+        /* 12 bits length SN */
+        count = (pdcp_entity->tx_hfn << 12) | (pdcp_sn & 0x0FFF);
+    }
+//     LOG_D(PDCP, "[OSA] TX COUNT = 0x%08x\n", count);
+
+    return count;
+}
+
+static
+u32 pdcp_get_next_count_rx(pdcp_t *pdcp_entity, u8 pdcp_header_len, u16 pdcp_sn)
+{
+    u32 count;
+    /* For RX COUNT = RX_HFN << length of SN | pdcp SN of received PDU */
+    if (pdcp_header_len == PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE) {
+        /* 5 bits length SN */
+        count = (pdcp_entity->rx_hfn << 5)  | (pdcp_sn & 0x001F);
+    } else {
+        /* 12 bits length SN */
+        count = (pdcp_entity->rx_hfn << 12) | (pdcp_sn & 0x0FFF);
+    }
+//     LOG_D(PDCP, "[OSA] RX COUNT = 0x%08x\n", count);
+
+    return count;
+}
+
+int pdcp_apply_security(pdcp_t *pdcp_entity, rb_id_t rb_id,
+                        u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer,
+                        u16 sdu_buffer_size)
+{
+    u8 *buffer_encrypted = NULL;
+    stream_cipher_t encrypt_params;
+
+    DevAssert(pdcp_entity != NULL);
+    DevAssert(pdcp_pdu_buffer != NULL);
+    DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
+
+    encrypt_params.direction  = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
+    encrypt_params.bearer     = rb_id;
+    encrypt_params.count      = pdcp_get_next_count_tx(pdcp_entity, pdcp_header_len, current_sn);
+    encrypt_params.key_length = 16;
+
+    if (rb_id < DTCH) {
+        /* SRBs */
+        u8 *mac_i;
+
+        LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security\n",
+              rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");
+
+        encrypt_params.message    = pdcp_pdu_buffer;
+        encrypt_params.blength    = (pdcp_header_len + sdu_buffer_size) << 3;
+        encrypt_params.key        = pdcp_entity->kRRCint;
+
+        mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];
+
+        /* Both header and data parts are integrity protected for
+         * control-plane PDUs */
+        stream_compute_integrity(pdcp_entity->integrityProtAlgorithm, &encrypt_params,
+                                 mac_i);
+
+        encrypt_params.key = pdcp_entity->kRRCenc;
+    } else {
+        LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
+              rb_id, (pdcp_entity->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");
+
+        encrypt_params.key = pdcp_entity->kUPenc;
+    }
+
+    encrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
+    encrypt_params.blength    = sdu_buffer_size << 3;
+
+    buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len];
+
+    /* Apply ciphering if any requested */
+    stream_encrypt(pdcp_entity->cipheringAlgorithm, &encrypt_params,
+                   &buffer_encrypted);
+
+    return 0;
+}
+
+int pdcp_validate_security(pdcp_t *pdcp_entity, rb_id_t rb_id,
+                           u8 pdcp_header_len, u16 current_sn, u8 *pdcp_pdu_buffer,
+                           u16 sdu_buffer_size)
+{
+    u8 *buffer_decrypted = NULL;
+    stream_cipher_t decrypt_params;
+
+    DevAssert(pdcp_entity != NULL);
+
+    DevAssert(pdcp_pdu_buffer != NULL);
+    DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);
+
+    buffer_decrypted = (u8*)&pdcp_pdu_buffer[pdcp_header_len];
+
+    decrypt_params.direction  = (pdcp_entity->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ;
+    decrypt_params.bearer     = rb_id;
+    decrypt_params.count      = pdcp_get_next_count_rx(pdcp_entity, pdcp_header_len, current_sn);
+    decrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
+    decrypt_params.blength    = (sdu_buffer_size - pdcp_header_len) << 3;
+    decrypt_params.key_length = 16;
+
+    if (rb_id < DTCH) {
+        LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n",
+              rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
+        decrypt_params.key = pdcp_entity->kRRCenc;
+    } else {
+        LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n",
+              rb_id, (pdcp_entity->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
+        decrypt_params.key = pdcp_entity->kUPenc;
+    }
+
+    /* Uncipher the block */
+    stream_decrypt(pdcp_entity->cipheringAlgorithm, &decrypt_params, &buffer_decrypted);
+
+    if (rb_id < DTCH) {
+        /* Now check the integrity of the complete PDU */
+        decrypt_params.message    = pdcp_pdu_buffer;
+        decrypt_params.blength    = sdu_buffer_size << 3;
+        decrypt_params.key        = pdcp_entity->kRRCint;
+
+        if (stream_check_integrity(pdcp_entity->integrityProtAlgorithm,
+            &decrypt_params, &pdcp_pdu_buffer[sdu_buffer_size]) != 0) {
+            LOG_E(PDCP, "[OSA] failed to validate MAC-I of incoming PDU\n");
+            return -1;
+        }
+    }
+    return 0;
+}
+
+#endif /* ENABLE_SECURITY */
diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c
index a87afa1a5abe038074e69ecd0b8e16610cc6a2b1..6aeeef602bd2c9ca6a4545d6f914299daa0b7177 100644
--- a/openair2/LAYER2/openair2_proc.c
+++ b/openair2/LAYER2/openair2_proc.c
@@ -36,12 +36,22 @@
 # @ingroup _mac
 */
 
-#ifndef USER_MODE
+#ifdef USER_MODE
+# include <inttypes.h>
+#else
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 
+# ifndef PRIu64
+#  if __WORDSIZE == 64
+#     define PRIu64 "lu"
+#   else
+#     define PRIu64 "llu"
+#   endif
+# endif
 #endif
+
 #include "LAYER2/RLC/rlc.h"
 #include "LAYER2/MAC/defs.h"
 #include "LAYER2/MAC/extern.h"
@@ -114,7 +124,10 @@ int dump_eNB_l2_stats(char *buffer, int length){
 		       eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].ncce_used_retx 
 		       );
 	
-	len += sprintf(&buffer[len],"[MAC] DLSCH bitrate (TTI %d, avg %d), Transmitted bytes (TTI %d, total %d), Total Transmitted PDU %d, Overhead (TTI %d, total %d, avg %d)",
+	len += sprintf(&buffer[len],
+                       "[MAC] DLSCH bitrate (TTI %d, avg %d), Transmitted bytes "
+                       "(TTI %d, total %"PRIu64"), Total Transmitted PDU %d, Overhead "
+                       "(TTI %"PRIu64", total %"PRIu64", avg %"PRIu64,
 		       eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].dlsch_bitrate,
 		       eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].total_dlsch_bitrate,
 		       eNB_mac_inst[eNB_id].eNB_UE_stats[UE_id].TBS,
diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c
index e21df15a88a5077cb9cd5476f2e5ebcdba8e39e5..35f32b4104c14df1199d7180e07821bcf64f4fe8 100644
--- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c
+++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c
@@ -772,7 +772,7 @@ uint8_t do_SIB23(uint8_t Mod_id,
   *(*sib3)->intraFreqCellReselectionInfo.s_IntraSearch = 31;
   (*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth=CALLOC(1,sizeof(*(*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth));
 
-  (*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth=AllowedMeasBandwidth_mbw6;
+  *(*sib3)->intraFreqCellReselectionInfo.allowedMeasBandwidth = AllowedMeasBandwidth_mbw6;
 
   (*sib3)->intraFreqCellReselectionInfo.presenceAntennaPort1 = 0;
   (*sib3)->intraFreqCellReselectionInfo.neighCellConfig.buf = CALLOC(8,1);
@@ -1299,25 +1299,28 @@ uint8_t do_RRCConnectionSetup(uint8_t *buffer,
   return((enc_rval.encoded+7)/8);
 }
 uint8_t do_SecurityModeCommand(uint8_t Mod_id,
-				 uint8_t *buffer,
-				 uint8_t UE_id,
-				 uint8_t Transaction_id) {
+                               uint8_t *buffer,
+                               uint8_t UE_id,
+                               uint8_t Transaction_id,
+                               uint8_t cipheringAlgorithm,
+                               uint8_t integrityProtAlgorithm) {
  DL_DCCH_Message_t dl_dcch_msg;
  asn_enc_rval_t enc_rval;
 
  memset(&dl_dcch_msg,0,sizeof(DL_DCCH_Message_t));
 
- dl_dcch_msg.message.present           = DL_DCCH_MessageType_PR_c1;
- dl_dcch_msg.message.choice.c1.present = DL_DCCH_MessageType__c1_PR_securityModeCommand;
- 
- dl_dcch_msg.message.choice.c1.choice.securityModeCommand.rrc_TransactionIdentifier = Transaction_id;
- dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1;
- 
- dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.present = SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8;
- // the two following information could be based on the mod_id
- dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm=SecurityAlgorithmConfig__cipheringAlgorithm_spare1;
-  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm=SecurityAlgorithmConfig__integrityProtAlgorithm_spare1;
+  dl_dcch_msg.message.present           = DL_DCCH_MessageType_PR_c1;
+  dl_dcch_msg.message.choice.c1.present = DL_DCCH_MessageType__c1_PR_securityModeCommand;
+
+  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.rrc_TransactionIdentifier = Transaction_id;
+  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.present = SecurityModeCommand__criticalExtensions_PR_c1;
 
+  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.present = SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8;
+  // the two following information could be based on the mod_id
+  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm
+  = (e_SecurityAlgorithmConfig__cipheringAlgorithm)cipheringAlgorithm;
+  dl_dcch_msg.message.choice.c1.choice.securityModeCommand.criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm
+  = (e_SecurityAlgorithmConfig__integrityProtAlgorithm)integrityProtAlgorithm;
 
 #ifdef XER_PRINT
   xer_fprint(stdout, &asn_DEF_DL_DCCH_Message, (void*)&dl_dcch_msg);
@@ -1680,7 +1683,7 @@ uint8_t do_MeasurementReport(uint8_t *buffer,int measid,int phy_id,int rsrp_s,in
 				   100);
 
 #ifdef USER_MODE
-  printf("Measurement Report Encoded %d bits (%d bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8);
+  printf("Measurement Report Encoded %zu bits (%zu bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8);
 #endif
 
   return((enc_rval.encoded+7)/8);
diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h
index 3a53b1253a0c630b1852cd252ce728ac47b7f0bc..9741077b2e5556c2fd25de3e5f41ba7195d2d593 100644
--- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h
+++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h
@@ -141,6 +141,8 @@ uint8_t do_UECapabilityEnquiry(uint8_t Mod_id,
 			       uint8_t Transaction_id);
 
 uint8_t do_SecurityModeCommand(uint8_t Mod_id,
-			       uint8_t *buffer,
-			       uint8_t UE_id,
-			       uint8_t Transaction_id);
+                               uint8_t *buffer,
+                               uint8_t UE_id,
+                               uint8_t Transaction_id,
+                               uint8_t cipheringAlgorithm,
+                               uint8_t integrityProtAlgorithm);
diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h
index d2dcd5409c233e0db52622c01c7f0586c2adadb2..a609f414ec6ee97c3e341dc7930f866b0533e8a2 100644
--- a/openair2/RRC/LITE/defs.h
+++ b/openair2/RRC/LITE/defs.h
@@ -240,6 +240,15 @@ typedef struct{
   SRB_INFO                          Srb0;
   SRB_INFO_TABLE_ENTRY              Srb1[NUMBER_OF_UE_MAX+1];
   SRB_INFO_TABLE_ENTRY              Srb2[NUMBER_OF_UE_MAX+1];
+
+#if defined(ENABLE_SECURITY)
+  /* KeNB as derived from KASME received from EPC */
+  uint8_t kenb[NUMBER_OF_UE_MAX][32];
+#endif
+
+  /* Used integrity/ciphering algorithms */
+  e_SecurityAlgorithmConfig__cipheringAlgorithm     ciphering_algorithm[NUMBER_OF_UE_MAX];
+  e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm[NUMBER_OF_UE_MAX];
 } eNB_RRC_INST;
 
 #define MAX_UE_CAPABILITY_SIZE 255
@@ -300,6 +309,15 @@ typedef struct{
   struct SPS_Config               *sps_Config[NB_CNX_UE];
   MAC_MainConfig_t                *mac_MainConfig[NB_CNX_UE];
   MeasGapConfig_t                 *measGapConfig[NB_CNX_UE];
+
+#if defined(ENABLE_SECURITY)
+  /* KeNB as computed from parameters within USIM card */
+  uint8_t kenb[32];
+#endif
+
+  /* Used integrity/ciphering algorithms */
+  e_SecurityAlgorithmConfig__cipheringAlgorithm     ciphering_algorithm;
+  e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm;
 }UE_RRC_INST;
 
 //main.c
diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c
index 9488196283f3065370ef81bb7be9992729609507..2b66aef667375462620ea6f307a0125cdee257f9 100644
--- a/openair2/RRC/LITE/rrc_UE.c
+++ b/openair2/RRC/LITE/rrc_UE.c
@@ -68,6 +68,11 @@
 #include "RRC/NAS/nas_config.h"
 #include "RRC/NAS/rb_config.h"
 #endif
+
+#if defined(ENABLE_SECURITY)
+# include "UTIL/OSA/osa_defs.h"
+#endif
+
 #ifdef PHY_EMUL
 extern EMULATION_VARS *Emul_vars;
 #endif
@@ -110,9 +115,29 @@ void init_MCCH_UE(u8 Mod_id, u8 eNB_index) {
   UE_rrc_inst[Mod_id].MCCH_MESSAGE[eNB_index] = (u8 *)malloc16(32);
   UE_rrc_inst[Mod_id].mcch_message[eNB_index] = (MBSFNAreaConfiguration_r9_t *)malloc16(sizeof(MBSFNAreaConfiguration_r9_t));
   UE_rrc_inst[Mod_id].Info[eNB_index].MCCH_MESSAGEStatus = 0;
-  
-  }
+
+}
+#endif
+
+static
+void openair_rrc_lite_ue_init_security(u8 Mod_id)
+{
+#if defined(ENABLE_SECURITY)
+    uint8_t *kRRCenc;
+    uint8_t *kRRCint;
+    char ascii_buffer[65];
+    uint8_t i;
+
+    memset(UE_rrc_inst[Mod_id].kenb, Mod_id, 32);
+
+    for (i = 0; i < 32; i++) {
+        sprintf(&ascii_buffer[2 * i], "%02X", UE_rrc_inst[Mod_id].kenb[i]);
+    }
+
+    LOG_T(RRC, "[OSA][UE %02d] kenb    = %s\n",
+            Mod_id, ascii_buffer);
 #endif
+}
 
 /*------------------------------------------------------------------------------*/
 char openair_rrc_lite_ue_init(u8 Mod_id, unsigned char eNB_index){
@@ -130,6 +155,15 @@ char openair_rrc_lite_ue_init(u8 Mod_id, unsigned char eNB_index){
   UE_rrc_inst[Mod_id].Srb1[eNB_index].Active=0;
   UE_rrc_inst[Mod_id].Srb2[eNB_index].Active=0;
 
+  UE_rrc_inst[Mod_id].ciphering_algorithm = SecurityAlgorithmConfig__cipheringAlgorithm_eea0;
+#ifdef Rel10
+  UE_rrc_inst[Mod_id].integrity_algorithm = SecurityAlgorithmConfig__integrityProtAlgorithm_eia0_v920;
+#else
+  UE_rrc_inst[Mod_id].integrity_algorithm = SecurityAlgorithmConfig__integrityProtAlgorithm_reserved;
+#endif
+
+  openair_rrc_lite_ue_init_security(Mod_id);
+
   init_SI_UE(Mod_id,eNB_index);
   LOG_D(RRC,"[UE %d] INIT: phy_sync_2_ch_ind\n", Mod_id);
 
@@ -652,12 +686,26 @@ void	rrc_ue_process_radioResourceConfigDedicated(u8 Mod_id,u32 frame, u8 eNB_ind
   // Establish SRBs if present
   // loop through SRBToAddModList
   if (radioResourceConfigDedicated->srb_ToAddModList) {
+    uint8_t *kRRCenc = NULL;
+    uint8_t *kRRCint = NULL;
+
+#if defined(ENABLE_SECURITY)
+    derive_key_rrc_enc(UE_rrc_inst[Mod_id].ciphering_algorithm,
+                       UE_rrc_inst[Mod_id].kenb, &kRRCenc);
+    derive_key_rrc_int(UE_rrc_inst[Mod_id].integrity_algorithm,
+                       UE_rrc_inst[Mod_id].kenb, &kRRCint);
+#endif
 
 // Refresh SRBs
     rrc_pdcp_config_asn1_req(NB_eNB_INST+Mod_id,frame,0,eNB_index,
-			    radioResourceConfigDedicated->srb_ToAddModList,
-			    (DRB_ToAddModList_t*)NULL,
-			    (DRB_ToReleaseList_t*)NULL
+                             radioResourceConfigDedicated->srb_ToAddModList,
+                             (DRB_ToAddModList_t*)NULL,
+                             (DRB_ToReleaseList_t*)NULL,
+                             UE_rrc_inst[Mod_id].ciphering_algorithm |
+                             (UE_rrc_inst[Mod_id].integrity_algorithm << 4),
+                             kRRCenc,
+                             kRRCint,
+                             NULL
 #ifdef Rel10
 			    ,(MBMS_SessionInfoList_r9_t *)NULL
 #endif
@@ -790,12 +838,23 @@ void	rrc_ue_process_radioResourceConfigDedicated(u8 Mod_id,u32 frame, u8 eNB_ind
 
   // Establish DRBs if present
   if (radioResourceConfigDedicated->drb_ToAddModList) {
+    uint8_t *kUPenc;
+
+#if defined(ENABLE_SECURITY)
+    derive_key_up_enc(UE_rrc_inst[Mod_id].integrity_algorithm,
+                      UE_rrc_inst[Mod_id].kenb, &kUPenc);
+#endif
 
     // Refresh DRBs
     rrc_pdcp_config_asn1_req(NB_eNB_INST+Mod_id,frame,0,eNB_index,
-			    (SRB_ToAddModList_t*)NULL,
-			    radioResourceConfigDedicated->drb_ToAddModList,
-			    (DRB_ToReleaseList_t*)NULL
+                             (SRB_ToAddModList_t*)NULL,
+                             radioResourceConfigDedicated->drb_ToAddModList,
+                             (DRB_ToReleaseList_t*)NULL,
+                             UE_rrc_inst[Mod_id].ciphering_algorithm |
+                             (UE_rrc_inst[Mod_id].integrity_algorithm << 4),
+                             NULL,
+                             NULL,
+                             kUPenc
 #ifdef Rel10
 			    ,(MBMS_SessionInfoList_r9_t *)NULL
 #endif
@@ -907,7 +966,11 @@ void rrc_ue_process_securityModeCommand(uint8_t Mod_id,uint32_t frame,SecurityMo
     break;
   }
   LOG_D(RRC,"[UE %d] security mode is %x \n",Mod_id, securityMode);
-  
+
+  /* Store the parameters received */
+  UE_rrc_inst[Mod_id].ciphering_algorithm = securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.cipheringAlgorithm;
+  UE_rrc_inst[Mod_id].integrity_algorithm = securityModeCommand->criticalExtensions.choice.c1.choice.securityModeCommand_r8.securityConfigSMC.securityAlgorithmConfig.integrityProtAlgorithm;
+
   memset((void *)&ul_dcch_msg,0,sizeof(UL_DCCH_Message_t));
   //memset((void *)&SecurityModeCommand,0,sizeof(SecurityModeCommand_t));
 
@@ -1035,8 +1098,7 @@ void rrc_ue_process_rrcConnectionReconfiguration(u8 Mod_id, u32 frame,
       if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated) {
 	LOG_I(RRC,"Radio Resource Configuration is present\n");
 	rrc_ue_process_radioResourceConfigDedicated(Mod_id,frame,eNB_index,
-						    rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated);
-
+                                                    rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated);
       }
     } // c1 present
   } // critical extensions present
@@ -1219,6 +1281,7 @@ int decode_BCCH_DLSCH_Message(u8 Mod_id,u32 frame,u8 eNB_index,u8 *Sdu,u8 Sdu_le
 	}
 	break;
       case BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
+      default:
 	break;
       }
     }
@@ -1227,6 +1290,8 @@ int decode_BCCH_DLSCH_Message(u8 Mod_id,u32 frame,u8 eNB_index,u8 *Sdu,u8 Sdu_le
       (UE_rrc_inst[Mod_id].Info[eNB_index].SIStatus == 1) && (frame >= Mod_id * 20 + 10))
       SEQUENCE_free(&asn_DEF_BCCH_DL_SCH_Message, (void*)bcch_message, 0);*/
   vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT);
+
+  return 0;
 }
 
 
@@ -1385,10 +1450,10 @@ void dump_sib2(SystemInformationBlockType2_t *sib2) {
   LOG_D(RRC,"ue_TimersAndConstants.n311 : %ld\n", sib2->ue_TimersAndConstants.n311);
 
   LOG_D(RRC,"freqInfo.additionalSpectrumEmission : %ld\n",sib2->freqInfo.additionalSpectrumEmission);
-  LOG_D(RRC,"freqInfo.ul_CarrierFreq : %d\n",(int)sib2->freqInfo.ul_CarrierFreq);
-  LOG_D(RRC,"freqInfo.ul_Bandwidth : %d\n",(int)sib2->freqInfo.ul_Bandwidth);
-  LOG_D(RRC,"mbsfn_SubframeConfigList : %d\n",(int)sib2->mbsfn_SubframeConfigList);
-  LOG_D(RRC,"timeAlignmentTimerCommon : %ld\n",sib2->timeAlignmentTimerCommon);
+  LOG_D(RRC,"freqInfo.ul_CarrierFreq : %ld\n", sib2->freqInfo.ul_CarrierFreq);
+  LOG_D(RRC,"freqInfo.ul_Bandwidth : %ld\n", sib2->freqInfo.ul_Bandwidth);
+  LOG_D(RRC,"mbsfn_SubframeConfigList : %ld\n", sib2->mbsfn_SubframeConfigList);
+  LOG_D(RRC,"timeAlignmentTimerCommon : %ld\n", sib2->timeAlignmentTimerCommon);
 
 
 
diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c
index 8a83409c862f796c15c02d95bf2f8a0f4f306556..969acf6a5174a55a6f7cd78634393f65440e5833 100644
--- a/openair2/RRC/LITE/rrc_eNB.c
+++ b/openair2/RRC/LITE/rrc_eNB.c
@@ -64,6 +64,10 @@
 #include "OCG_extern.h"
 #endif
 
+#if defined(ENABLE_SECURITY)
+# include "UTIL/OSA/osa_defs.h"
+#endif
+
 #if defined(ENABLE_USE_MME)
 #include "../../S1AP/s1ap_eNB.h"
 #endif
@@ -412,6 +416,23 @@ init_MBMS (u8 Mod_id, u32 frame)
 
 #endif
 
+static
+void rrc_lite_eNB_init_security(u8 Mod_id, u8 UE_index)
+{
+#if defined(ENABLE_SECURITY)
+    char ascii_buffer[65];
+    uint8_t i;
+
+    memset(eNB_rrc_inst[Mod_id].kenb[UE_index], UE_index, 32);
+
+    for (i = 0; i < 32; i++) {
+        sprintf(&ascii_buffer[2 * i], "%02X", eNB_rrc_inst[Mod_id].kenb[UE_index][i]);
+    }
+
+    LOG_T(RRC, "[OSA][MOD %02d][UE %02d] kenb    = %s\n", Mod_id, UE_index, ascii_buffer);
+#endif
+}
+
 /*------------------------------------------------------------------------------*/
 char
 openair_rrc_lite_eNB_init (u8 Mod_id)
@@ -426,6 +447,13 @@ openair_rrc_lite_eNB_init (u8 Mod_id)
   for (j = 0; j < NUMBER_OF_UE_MAX; j++)
     eNB_rrc_inst[Mod_id].Info.Status[j] = RRC_IDLE;     //CH_READY;
 
+  /* Init security parameters */
+  for (j = 0; j < NUMBER_OF_UE_MAX; j++) {
+    eNB_rrc_inst[Mod_id].ciphering_algorithm[j] = SecurityAlgorithmConfig__cipheringAlgorithm_eea2;
+    eNB_rrc_inst[Mod_id].integrity_algorithm[j] = SecurityAlgorithmConfig__integrityProtAlgorithm_eia2;
+    rrc_lite_eNB_init_security(Mod_id, j);
+  }
+
 #if defined(ENABLE_USE_MME)
   /* Connect eNB to MME */
   if (oai_emulation.info.mme_enabled > 0)
@@ -931,7 +959,11 @@ rrc_eNB_decode_ccch (u8 Mod_id, u32 frame, SRB_INFO * Srb_info)
                                         eNB_rrc_inst[Mod_id].
                                         SRB_configList[UE_index],
                                         (DRB_ToAddModList_t *) NULL,
-                                        (DRB_ToReleaseList_t *) NULL
+                                        (DRB_ToReleaseList_t *) NULL,
+                                        0xff,
+                                        NULL,
+                                        NULL,
+                                        NULL
 #ifdef Rel10
                                         , (PMCH_InfoList_r9_t *) NULL
 #endif
@@ -1017,7 +1049,9 @@ rrc_eNB_generate_SecurityModeCommand (u8 Mod_id, u32 frame, u16 UE_index)
   uint8_t buffer[100];
   uint8_t size;
 
-  size = do_SecurityModeCommand (Mod_id, buffer, UE_index, 0);
+  size = do_SecurityModeCommand (Mod_id, buffer, UE_index, 0,
+                                 eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index],
+                                 eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index]);
 
   LOG_I (RRC,
          "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d, UE id %d)\n",
@@ -1611,15 +1645,38 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete (u8 Mod_id, u32 frame,
   int oip_ifup = 0;
   int dest_ip_offset = 0;
 #endif
+
+  uint8_t *kRRCenc = NULL;
+  uint8_t *kRRCint = NULL;
+  uint8_t *kUPenc  = NULL;
+
   DRB_ToAddModList_t *DRB_configList =
     eNB_rrc_inst[Mod_id].DRB_configList[UE_index];
   SRB_ToAddModList_t *SRB_configList =
     eNB_rrc_inst[Mod_id].SRB_configList[UE_index];
 
+#if defined(ENABLE_SECURITY)
+  /* Derive the keys from kenb */
+  if (DRB_configList != NULL) {
+    derive_key_up_enc(eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index],
+                      eNB_rrc_inst[Mod_id].kenb[UE_index], &kUPenc);
+  }
+
+  derive_key_rrc_enc(eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index],
+                     eNB_rrc_inst[Mod_id].kenb[UE_index], &kRRCenc);
+  derive_key_rrc_int(eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index],
+                     eNB_rrc_inst[Mod_id].kenb[UE_index], &kRRCint);
+#endif
+
   // Refresh SRBs/DRBs
   rrc_pdcp_config_asn1_req (Mod_id, frame, 1, UE_index,
                             SRB_configList,
-                            DRB_configList, (DRB_ToReleaseList_t *) NULL
+                            DRB_configList, (DRB_ToReleaseList_t *) NULL,
+                            eNB_rrc_inst[Mod_id].ciphering_algorithm[UE_index] |
+                            (eNB_rrc_inst[Mod_id].integrity_algorithm[UE_index] << 4),
+                            kRRCenc,
+                            kRRCint,
+                            kUPenc
 #ifdef Rel10
                             , (PMCH_InfoList_r9_t *) NULL
 #endif
diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c
index 3203544eea30554b72c4830f6147c69df8fcbc59..72a789727179ac5b4634380cb1ddc6a173278c7d 100755
--- a/openair2/UTIL/LOG/log.c
+++ b/openair2/UTIL/LOG/log.c
@@ -281,6 +281,14 @@ int logInit (void) {
     g_log->log_component[HW].filelog = 0;
     g_log->log_component[HW].filelog_name = "";
 
+    g_log->log_component[OSA].name = "OSA";
+    g_log->log_component[OSA].level = LOG_EMERG;
+    g_log->log_component[OSA].flag = LOG_MED;
+    g_log->log_component[OSA].interval = 1;
+    g_log->log_component[OSA].fd = 0;
+    g_log->log_component[OSA].filelog = 0;
+    g_log->log_component[OSA].filelog_name = "";
+
     g_log->level2string[LOG_EMERG]         = "G"; //EMERG
     g_log->level2string[LOG_ALERT]         = "A"; // ALERT
     g_log->level2string[LOG_CRIT]          = "C"; // CRITIC
diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h
index 67de407929a16e7285ea83a5aee51ac81d58c89a..9fbb7878402cbfbc336099c0f88d2c35c66b4af3 100755
--- a/openair2/UTIL/LOG/log.h
+++ b/openair2/UTIL/LOG/log.h
@@ -231,7 +231,34 @@ extern "C" {
 
 //static char *log_level_highlight_end[]   = {LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, "", "", "", LOG_RESET};	/*!< \brief Optional end-format strings for highlighting */
 
-  typedef enum {MIN_LOG_COMPONENTS=0, PHY, MAC, EMU, OCG, OMG,OPT,OTG,OTG_LATENCY,OTG_LATENCY_BG, OTG_GP, OTG_GP_BG,OTG_JITTER, RLC, PDCP, RRC, PERF,OIP, CLI, MSC, OCM, S1AP, SCTP, HW, MAX_LOG_COMPONENTS} comp_name_t;
+typedef enum {
+    MIN_LOG_COMPONENTS = 0,
+    PHY,
+    MAC,
+    EMU,
+    OCG,
+    OMG,
+    OPT,
+    OTG,
+    OTG_LATENCY,
+    OTG_LATENCY_BG,
+    OTG_GP,
+    OTG_GP_BG,
+    OTG_JITTER,
+    RLC,
+    PDCP,
+    RRC,
+    PERF,
+    OIP,
+    CLI,
+    MSC,
+    OCM,
+    S1AP,
+    SCTP,
+    HW,
+    OSA,
+    MAX_LOG_COMPONENTS
+} comp_name_t;
 
   //#define msg printf
 
diff --git a/openair2/UTIL/Makefile.inc b/openair2/UTIL/Makefile.inc
index ba96b53303347325c5cfa775dfefd4eb0a515ca4..75ec78cf434db19e79f67359a470103162cac152 100644
--- a/openair2/UTIL/Makefile.inc
+++ b/openair2/UTIL/Makefile.inc
@@ -12,6 +12,7 @@ CLI_DIR=$(OPENAIR2_TOP)/UTIL/CLI
 OMV_DIR=$(OPENAIR2_TOP)/UTIL/OMV
 SCTP_DIR=$(OPENAIR2_TOP)/UTIL/SCTP
 LFDS_DIR=$(OPENAIR2_TOP)/UTIL/LFDS/liblfds6.1.1/liblfds611
+OSA_DIR=$(OPENAIR2_TOP)/UTIL/OSA
 
 LIST_OBJ =  $(LIST_DIR)/list.o
 
@@ -34,6 +35,12 @@ OCG_OBJS +=  $(OCG_DIR)/OCG_parse_filename.o
 OCG_OBJS +=  $(OCG_DIR)/OCG_parse_XML.o
 OCG_OBJS +=  $(OCG_DIR)/OCG_save_XML.o
 
+ifdef SECU
+OSA_OBJS  = $(OSA_DIR)/osa_key_deriver.o
+OSA_OBJS += $(OSA_DIR)/osa_stream_eia.o
+OSA_OBJS += $(OSA_DIR)/osa_stream_eea.o
+endif
+
 OPT_OBJS =  $(OPT_DIR)/probe.o
 
 OMG_OBJS =  $(OMG_DIR)/omg.o
@@ -69,6 +76,22 @@ SCTP_OBJS = $(SCTP_DIR)/sctp_primitives_client.o
 else
 SCTP_OBJS = 
 endif
-UTIL_OBJ = $(FIFO_OBJ) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(LOG_OBJS) $(OCG_OBJS) $(MATH_OBJS) $(OTG_OBJS) $(CLI_OBJ) $(OMG_OBJS) $(OPT_OBJS) $(SCTP_OBJS)
+UTIL_OBJ = $(OSA_OBJS) $(FIFO_OBJ) $(LIST_OBJ) $(TIMER_OBJ) $(MEM_OBJ) $(LOG_OBJS) $(OCG_OBJS) $(MATH_OBJS) $(OTG_OBJS) $(CLI_OBJ) $(OMG_OBJS) $(OPT_OBJS) $(SCTP_OBJS)
 
-UTIL_incl = -I$(LFDS_DIR)/inc -I$(MEM_DIR) -I$(LIST_DIR) -I$(FIFO_DIR) -I$(OCG_DIR) -I$(LOG_DIR) -I$(MATH_DIR) -I$(TIMER_DIR) -I$(OMG_DIR) -I$(OTG_DIR) -I$(CLI_DIR) -I$(OPT_DIR) -I$(OMV_DIR) -I$(SCTP_DIR)
+UTIL_incl = \
+    -I$(OPENAIR2_TOP)/UTIL      \
+    -I$(OSA_DIR)                \
+    -I$(LFDS_DIR)/inc           \
+    -I$(MEM_DIR)                \
+    -I$(LIST_DIR)               \
+    -I$(FIFO_DIR)               \
+    -I$(OCG_DIR)                \
+    -I$(LOG_DIR)                \
+    -I$(MATH_DIR)               \
+    -I$(TIMER_DIR)              \
+    -I$(OMG_DIR)                \
+    -I$(OTG_DIR)                \
+    -I$(CLI_DIR)                \
+    -I$(OPT_DIR)                \
+    -I$(OMV_DIR)                \
+    -I$(SCTP_DIR)
diff --git a/openair2/UTIL/OSA/README b/openair2/UTIL/OSA/README
new file mode 100644
index 0000000000000000000000000000000000000000..1e54944308426b9000a73d8d3393f48877b859e2
--- /dev/null
+++ b/openair2/UTIL/OSA/README
@@ -0,0 +1,19 @@
+OAISIM Security Algorithms v0.1
+
+Dependencies:
+- nettle >= 2.5
+- openssl >= 1.0.1
+
+Compilation:
+
+When compiling oaisim, add SECU=1 to enable security features. The makefile will
+check for required dependencies and disable this feature if not all dependencies
+are met.
+
+OSA is based on 3GPP TS 33.401.
+Note that only EEA2 and EIA2 algorithms are supported, SNOW-3G is not implemented.
+
+Currently the kenb used to derive kRRCint, kRRCenc and kUPenc is composed of the
+UE_id. In the future this parameter can be either obtained by deriving KASME received
+from core epc (in the S1AP initial context setup request)
+or configurable via command line or XML file.
diff --git a/openair2/UTIL/OSA/osa_defs.h b/openair2/UTIL/OSA/osa_defs.h
new file mode 100644
index 0000000000000000000000000000000000000000..682e29363c3d47fe99b5f49a75c94d2953e9130b
--- /dev/null
+++ b/openair2/UTIL/OSA/osa_defs.h
@@ -0,0 +1,129 @@
+/*******************************************************************************
+
+  Eurecom OpenAirInterface
+  Copyright(c) 1999 - 2013 Eurecom
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information
+  Openair Admin: openair_admin@eurecom.fr
+  Openair Tech : openair_tech@eurecom.fr
+  Forums       : http://forums.eurecom.fr/openairinterface
+  Address      : EURECOM, Campus SophiaTech, 450 Route des Chappes
+                 06410 Biot FRANCE
+
+*******************************************************************************/
+
+/*!
+ * \file secu_defs.h
+ * \brief Openair security algorithms functions implementing 3GPP TS 33.401
+ * \note HMAC computations are done by nettle/openssl library
+ * \author Sebastien ROUX
+ * \date 2013
+ * \version 0.1
+ * @ingroup security
+*/
+
+#ifndef SECU_DEFS_H_
+#define SECU_DEFS_H_
+
+#define EIA0_ALG_ID     0x00
+#define EIA1_128_ALG_ID 0x01
+#define EIA2_128_ALG_ID 0x02
+
+#define EEA0_ALG_ID     EIA0_ALG_ID
+#define EEA1_128_ALG_ID EIA1_128_ALG_ID
+#define EEA2_128_ALG_ID EIA2_128_ALG_ID
+
+#define SECU_DIRECTION_UPLINK   0
+#define SECU_DIRECTION_DOWNLINK 1
+
+typedef enum {
+    NAS_ENC_ALG = 0x01,
+    NAS_INT_ALG = 0x02,
+    RRC_ENC_ALG = 0x03,
+    RRC_INT_ALG = 0x04,
+    UP_ENC_ALG  = 0x05
+} algorithm_type_dist_t;
+
+int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB);
+
+int derive_key(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id,
+               const uint8_t key[32], uint8_t **out);
+
+#define derive_key_nas_enc(aLGiD, kEY, kNAS)  \
+    derive_key(NAS_ENC_ALG, aLGiD, kEY, kNAS)
+
+#define derive_key_nas_int(aLGiD, kEY, kNAS)  \
+    derive_key(NAS_INT_ALG, aLGiD, kEY, kNAS)
+
+#define derive_key_rrc_enc(aLGiD, kEY, kNAS)  \
+    derive_key(RRC_ENC_ALG, aLGiD, kEY, kNAS)
+
+#define derive_key_rrc_int(aLGiD, kEY, kNAS)  \
+    derive_key(RRC_INT_ALG, aLGiD, kEY, kNAS)
+
+#define derive_key_up_enc(aLGiD, kEY, kNAS)  \
+    derive_key(UP_ENC_ALG, aLGiD, kEY, kNAS)
+
+#define derive_key_up_int(aLGiD, kEY, kNAS)  \
+    derive_key(UP_INT_ALG, aLGiD, kEY, kNAS)
+
+typedef struct {
+    uint8_t  *key;
+    uint32_t  key_length;
+    uint32_t  count;
+    uint8_t   bearer;
+    uint8_t   direction;
+    uint8_t  *message;
+    /* length in bits */
+    uint32_t  blength;
+} stream_cipher_t;
+
+/*!
+ * @brief Encrypt/Decrypt a block of data based on the provided algorithm
+ * @param[in] algorithm Algorithm used to encrypt the data
+ *      Possible values are:
+ *      - EIA0_ALG_ID for NULL encryption
+ *      - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now)
+ *      - EIA2_128_ALG_ID for 128 bits AES LTE encryption
+ * @param[in] stream_cipher All parameters used to compute the encrypted block of data
+ * @param[out] out The encrypted block of data dynamically allocated
+ * @return 0 if everything OK, -1 if something failed
+ */
+int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out);
+#define stream_decrypt stream_encrypt
+
+int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4]);
+
+/*!
+ * @brief Decrypt a block of data based on the provided algorithm
+ * @param[in] algorithm Algorithm used to encrypt the data
+ *      Possible values are:
+ *      - EIA0_ALG_ID for NULL encryption
+ *      - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now)
+ *      - EIA2_128_ALG_ID for 128 bits AES LTE encryption
+ * @param[in] stream_cipher All parameters used to compute the decrypted block of data
+ * @param[out] out The decrypted block of data dynamically allocated
+ * @return 0 if everything OK, -1 if something failed
+ */
+int stream_decrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out);
+
+int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected);
+#undef SECU_DEBUG
+
+#endif /* SECU_DEFS_H_ */
diff --git a/openair2/UTIL/OSA/osa_internal.h b/openair2/UTIL/OSA/osa_internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..318549b2f75b9c7c95e7f49c30c13f78eb1ef1ff
--- /dev/null
+++ b/openair2/UTIL/OSA/osa_internal.h
@@ -0,0 +1,26 @@
+#ifndef OSA_INTERNAL_H_
+#define OSA_INTERNAL_H_
+
+#define FC_KENB         (0x11)
+#define FC_NH           (0x12)
+#define FC_KENB_STAR    (0x13)
+/* 33401 #A.7 Algorithm for key derivation function.
+ * This FC should be used for:
+ * - NAS Encryption algorithm
+ * - NAS Integrity algorithm
+ * - RRC Encryption algorithm
+ * - RRC Integrity algorithm
+ * - User Plane Encryption algorithm
+ */
+#define FC_ALG_KEY_DER  (0x15)
+#define FC_KASME_TO_CK  (0x16)
+
+#ifndef hton_int32
+# define hton_int32(x)   \
+(((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) |  \
+((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24))
+#endif
+
+#define SECU_DEBUG
+
+#endif /* OSA_INTERNAL_H_ */
diff --git a/openair2/UTIL/OSA/osa_key_deriver.c b/openair2/UTIL/OSA/osa_key_deriver.c
new file mode 100644
index 0000000000000000000000000000000000000000..625fe0e4036d7c371f064a704bf5599a4ebd902a
--- /dev/null
+++ b/openair2/UTIL/OSA/osa_key_deriver.c
@@ -0,0 +1,113 @@
+#include <stdint.h>
+
+#include <nettle/hmac.h>
+
+#include "osa_defs.h"
+#include "osa_internal.h"
+#include "UTIL/LOG/log.h"
+
+static inline
+void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key,
+         const uint32_t key_length, uint8_t **out, uint32_t out_length)
+{
+    struct hmac_sha256_ctx ctx;
+
+    uint8_t *buffer;
+
+    buffer = malloc(sizeof(uint8_t) * out_length);
+
+    hmac_sha256_set_key(&ctx, key_length, key);
+    hmac_sha256_update(&ctx, s_length, s);
+    hmac_sha256_digest(&ctx, out_length, buffer);
+
+    *out = buffer;
+}
+
+/*!
+ * @brief Derive the keys from kasme and perform truncate on the generated key to
+ * reduce his size to 128 bits. Definition of the derivation function can
+ * be found in 3GPP TS.33401 #A.7
+ * @param[in] alg_type Algorithm distinguisher
+ * @param[in] alg_id Algorithm identifier.
+ * Possible values are:
+ *      - 0 for EIA0 algorithm (Null Integrity Protection algorithm)
+ *      - 1 for 128-EIA1 SNOW 3G
+ *      - 2 for 128-EIA2 AES
+ * @param[in] key The top key used to derive other subkeys
+ * @param[out] out Pointer to reference where output of KDF will be stored.
+ * NOTE: knas is dynamically allocated by the KDF function
+ */
+int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
+               const uint8_t key[32], uint8_t **out)
+{
+    uint8_t string[7];
+#if defined(SECU_DEBUG)
+    int i;
+#endif
+
+    /* FC */
+    string[0] = FC_ALG_KEY_DER;
+
+    /* P0 = algorithm type distinguisher */
+    string[1] = (uint8_t)(alg_type & 0xFF);
+
+    /* L0 = length(P0) = 1 */
+    string[2] = 0x00;
+    string[3] = 0x01;
+
+    /* P1 */
+    string[4] = alg_id;
+
+    /* L1 = length(P1) = 1 */
+    string[5] = 0x00;
+    string[6] = 0x01;
+
+#if defined(SECU_DEBUG)
+    {
+        int i;
+        char payload[6 * sizeof(string) + 1];
+        int  index = 0;
+
+        for (i = 0; i < sizeof(string); i++)
+            index += sprintf(&payload[index], "0x%02x ", string[i]);
+        LOG_D(OSA, "Key deriver input string: %s\n", payload);
+    }
+#endif
+
+    kdf(string, 7, key, 32, out, 32);
+
+    return 0;
+}
+
+int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB)
+{
+    uint8_t string[7];
+
+    /* FC */
+    string[0] = FC_KENB;
+    /* P0 = Uplink NAS count */
+    string[1] = (nas_count & 0xff000000) >> 24;
+    string[2] = (nas_count & 0x00ff0000) >> 16;
+    string[3] = (nas_count & 0x0000ff00) >> 8;
+    string[4] = (nas_count & 0x000000ff);
+
+    /* Length of NAS count */
+    string[5] = 0x00;
+    string[6] = 0x04;
+
+#if defined(SECU_DEBUG)
+    {
+        int i;
+        char payload[6 * sizeof(string) + 1];
+        int  index = 0;
+
+        for (i = 0; i < sizeof(string); i++)
+            index += sprintf(&payload[index], "0x%02x ", string[i]);
+        LOG_D(OSA, "KeNB deriver input string: %s\n", payload);
+    }
+#endif
+
+    kdf(string, 7, kasme, 32, keNB, 32);
+
+    return 0;
+}
diff --git a/openair2/UTIL/OSA/osa_stream_eea.c b/openair2/UTIL/OSA/osa_stream_eea.c
new file mode 100644
index 0000000000000000000000000000000000000000..7412669bc462205b4311d6846eb385cd8c653508
--- /dev/null
+++ b/openair2/UTIL/OSA/osa_stream_eea.c
@@ -0,0 +1,110 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <nettle/nettle-meta.h>
+#include <nettle/aes.h>
+#include <nettle/ctr.h>
+
+#include "UTIL/LOG/log.h"
+
+#include "assertions.h"
+#include "osa_defs.h"
+#include "osa_internal.h"
+
+int stream_encrypt_eea2(stream_cipher_t *stream_cipher, uint8_t **out)
+{
+    uint8_t m[16];
+    uint32_t local_count;
+
+    void *ctx;
+    uint8_t *data = NULL;
+
+    uint32_t zero_bit = 0;
+    uint32_t byte_length;
+
+    DevAssert(stream_cipher != NULL);
+    DevAssert(out != NULL);
+
+    LOG_D(OSA, "Entering stream_encrypt_eea2, bits length %u, bearer %u, "
+          "count %u, direction %s\n", stream_cipher->blength,
+          stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ?
+          "Downlink" : "Uplink");
+
+    zero_bit = stream_cipher->blength & 0x7;
+
+    byte_length = stream_cipher->blength >> 3;
+    if (zero_bit > 0)
+        byte_length += 1;
+
+    ctx = malloc(nettle_aes128.context_size);
+
+    if (*out == NULL) {
+        /* User provided output buffer */
+        data = malloc(byte_length);
+        *out = data;
+    } else {
+        data = *out;
+    }
+
+    local_count = hton_int32(stream_cipher->count);
+
+    memset(m, 0, sizeof(m));
+    memcpy(&m[0], &local_count, 4);
+    m[4] = ((stream_cipher->bearer & 0x1F) << 3) |
+              ((stream_cipher->direction & 0x01) << 2);
+    /* Other bits are 0 */
+
+#if defined(SECU_DEBUG)
+    {
+        int i;
+        char payload[6 * byte_length + 1];
+        int  index = 0;
+
+        for (i = 0; i < byte_length; i++)
+            index += sprintf(&payload[index], "0x%02x ", stream_cipher->message[i]);
+        LOG_D(OSA, "Original message: %s\n", payload);
+    }
+#endif
+
+    nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length,
+                                  stream_cipher->key);
+
+    nettle_ctr_crypt(ctx, nettle_aes128.encrypt,
+                     nettle_aes128.block_size, m,
+                     byte_length, data, stream_cipher->message);
+
+    if (zero_bit > 0)
+        data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit));
+
+    free(ctx);
+
+#if defined(SECU_DEBUG)
+    {
+        int i;
+        char payload[6 * byte_length + 1];
+        int  index = 0;
+
+        for (i = 0; i < byte_length; i++)
+            index += sprintf(&payload[index], "0x%02x ", data[i]);
+        LOG_D(OSA, "Encrypted message: %s\n", payload);
+    }
+#endif
+
+    return 0;
+}
+
+int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out)
+{
+    if (algorithm == EEA0_ALG_ID) {
+//         return stream_encrypt_eea0(stream_cipher, out);
+    } else if (algorithm == EEA1_128_ALG_ID) {
+        LOG_E(OSA, "SNOW-3G algorithms are currently not implemented\n");
+        return -1;
+    } else if (algorithm == EEA2_128_ALG_ID) {
+        return stream_encrypt_eea2(stream_cipher, out);
+    }
+    LOG_E(OSA, "Provided algorithm is currently not supported = %u\n", algorithm);
+    return -1;
+}
diff --git a/openair2/UTIL/OSA/osa_stream_eia.c b/openair2/UTIL/OSA/osa_stream_eia.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a2a1cb5ec577a2679bde743722fb86657390394
--- /dev/null
+++ b/openair2/UTIL/OSA/osa_stream_eia.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "assertions.h"
+
+#include <openssl/aes.h>
+#include <openssl/cmac.h>
+#include <openssl/evp.h>
+
+#include "UTIL/LOG/log.h"
+
+#include "osa_defs.h"
+#include "osa_internal.h"
+
+/*!
+ * @brief Create integrity cmac t for a given message.
+ * @param[in] stream_cipher Structure containing various variables to setup encoding
+ * @param[out] out For EIA2 the output string is 32 bits long
+ */
+int stream_compute_integrity_eia2(stream_cipher_t *stream_cipher, uint8_t out[4])
+{
+    uint8_t  *m;
+    uint32_t local_count;
+    size_t size = 4;
+
+    uint8_t  data[16];
+
+    CMAC_CTX *cmac_ctx;
+
+    uint32_t zero_bit = 0;
+    uint32_t m_length;
+
+    DevAssert(stream_cipher != NULL);
+    DevAssert(stream_cipher->key != NULL);
+
+    memset(data, 0, 16);
+
+    zero_bit = stream_cipher->blength & 0x7;
+
+    m_length = stream_cipher->blength >> 3;
+    if (zero_bit > 0)
+        m_length += 1;
+
+    local_count = hton_int32(stream_cipher->count);
+
+    m = calloc(m_length + 8, sizeof(uint8_t));
+
+    memcpy(&m[0], &local_count, 4);
+    m[4] = ((stream_cipher->bearer & 0x1F) << 3) | ((stream_cipher->direction & 0x01) << 2);
+
+    memcpy(&m[8], stream_cipher->message, m_length);
+
+    #if defined(SECU_DEBUG)
+    {
+        int i;
+        char payload[6 * sizeof(m) + 1];
+        int  index = 0;
+        LOG_T(OSA, "Blength: %u, Zero bits: %u\n",
+                       stream_cipher->blength, zero_bit);
+        for (i = 0; i < sizeof(m); i++)
+            index += sprintf(&payload[index], "0x%02x ", m[i]);
+        LOG_T(OSA, "Payload: %s\n", payload);
+    }
+    #endif
+
+    cmac_ctx = CMAC_CTX_new();
+
+    CMAC_Init(cmac_ctx, stream_cipher->key, stream_cipher->key_length, EVP_aes_128_cbc(), NULL);
+    CMAC_Update(cmac_ctx, m, m_length + 8);
+
+    CMAC_Final(cmac_ctx, data, &size);
+
+    CMAC_CTX_free(cmac_ctx);
+
+    memcpy(out, data, 4);
+    free(m);
+
+    return 0;
+}
+
+int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4])
+{
+    if (algorithm == EIA0_ALG_ID) {
+        //         return stream_encrypt_eea0(stream_cipher, out);
+    } else if (algorithm == EIA1_128_ALG_ID) {
+        LOG_E(OSA, "SNOW-3G algorithms are currently not implemented\n");
+        return -1;
+    } else if (algorithm == EIA2_128_ALG_ID) {
+        return stream_compute_integrity_eia2(stream_cipher, out);
+    }
+    LOG_E(OSA, "Provided algorithm is currently not supported = %u\n", algorithm);
+    return -1;
+}
+
+int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected)
+{
+    uint8_t result[4];
+
+    if (stream_compute_integrity(algorithm, stream_cipher, result) != 0) {
+        return -1;
+    }
+
+    if (memcmp(result, expected, 4) != 0) {
+        LOG_E(OSA, "Mismatch found in integrity for algorithm %u,\n"
+            "\tgot %02x.%02x.%02x.%02x, expecting %02x.%02x.%02x.%02x\n",
+            algorithm, result[0], result[1], result[2], result[3], expected[0],
+            expected[1], expected[2], expected[3]);
+        return -1;
+    }
+
+    /* Integrity verification succeeded */
+    return 0;
+}
diff --git a/targets/SIMU/USER/Makefile b/targets/SIMU/USER/Makefile
index 80532dbc61bf256171d8f93f7616c3917a3c03e3..4227e7fa93b6cf623cebf19ff0bcbe10abf38d78 100644
--- a/targets/SIMU/USER/Makefile
+++ b/targets/SIMU/USER/Makefile
@@ -72,7 +72,7 @@ ifeq ($(ENABLE_DB), 1)
 CFLAGS +=-I/usr/include/mysql -L/usr/lib/mysql -DENABLE_DB_STATS
 DB_LDFLAGS = -lmysqlclient
 endif 
-endif 
+endif
 
 ifdef PRINT_STATS
 CFLAGS += -DPRINT_STATS
@@ -162,6 +162,25 @@ ifneq ($(USE_MME), R8)
 UPDATE_RELEASE_9=1
 endif
 
+ifdef SECU
+NETTLE_FOUND = $(shell if pkg-config --exists nettle; then echo "1" ; else echo "0"; fi)
+OPENSSL_FOUND = $(shell if pkg-config --exists openssl; then echo "1" ; else echo "0"; fi)
+
+ifeq ($(NETTLE_FOUND), 0)
+@echo "Nettle library >= 2.5 is not installed on your system, continuing with security disabled"
+SECU=0
+else
+ifeq ($(OPENSSL_FOUND), 0)
+@echo "openssl library is not installed on your system, continuing with security disabled"
+SECU=0
+else
+CFLAGS += -DENABLE_SECURITY
+OSA_LDFLAGS += `pkg-config --libs nettle`
+OSA_LDFLAGS += `pkg-config --libs openssl`
+endif
+endif
+endif
+
 include $(OPENAIR1_DIR)/PHY/Makefile.inc
 include $(OPENAIR1_DIR)/SCHED/Makefile.inc
 include $(OPENAIR2_DIR)/RRC/LITE/MESSAGES/Makefile.inc
@@ -318,7 +337,8 @@ oaisim : $(ASN1_MSG_OBJS1) $(OBJ) oaisim.c $(LFDS_DIR)/bin/liblfds611.a
 endif
 	@echo "Compiling oaisim.c ..."
 	@$(CC) -I$(TOP_DIR) $(L2_incl) $(UTIL_incl) -I$(ASN1_MSG_INC) $(S1AP_Incl) -o oaisim $(CFLAGS) $(EXTRA_CFLAGS) $^ \
-	-lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt $(LFDS_DIR)/bin/liblfds611.a $(PGM_LDFLAGS) $(DB_LDFLAGS) 
+	-lm -lblas -lpthread -llapack_atlas -lforms -lxml2 -lX11 -lXpm -lrt \
+	$(LFDS_DIR)/bin/liblfds611.a $(PGM_LDFLAGS) $(DB_LDFLAGS) $(OSA_LDFLAGS)
 
 ifeq ($(rrc_cellular_eNB),1)
 	mv oaisim oaisim_eNB
diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c
index 2f8d9fecddb81137ef72c81a1e6e24f92197fad6..aaa1f3c6f66fb4b49cb35bdcbf7e3452cee2af08 100644
--- a/targets/SIMU/USER/oaisim_functions.c
+++ b/targets/SIMU/USER/oaisim_functions.c
@@ -939,6 +939,7 @@ int init_slot_isr(void)
 
         oai_emulation.info.slot_sfd = sfd;
     }
+    return 0;
 }
 
 void wait_for_slot_isr(void)