bugfix: speedup integrity computation
The main work of this commit is to rewrite cipher_aes_128_cbc_cmac() which was too slow and created issues when running the 4G eNB on some machines (LLL when using a b210). Instead of creating the security context, use it, and delete it, all in cipher_aes_128_cbc_cmac(), we introduce the function init_aes_128_cbc_cmac() to create it, and we change cipher_aes_128_cbc_cmac() to just use it, and we also adapt free_aes_128_cbc_cmac(). The function aes_128_cbc_cmac() is removed, it does not follow the new init/use/free API. Doing so, on the primary test machine used to do this work (a powerful and fast machine where it is possible to set the CPUs' frequencies) it was possible to limit the CPUs' frequencies to 500 MHz (it was not possible to go lower) without any LLL (using a b210, quectel UE in idle, no data traffic, only periodic measurement reports). Before this commit, it was necessary to set a frequency of at least 1.8 GHz otherwise some LLL would appear. Then we need to adapt the rest of the code to take into account those changes. A notion of security container (stream_security_container_t) containing ciphering and integrity contexts is introduced. And the code is harmonized for, hopefully, better readability. The (opaque) type stream_security_context_t is introduced, used by both integrity and ciphering contexts. The idea is to use a init()/use()/free() API for all the security procedures, identical for all the ciphering and integrity procedures.
This commit is contained in:
@@ -2124,9 +2124,12 @@ pdcp_config_set_security(
|
||||
pdcp_pP->cipheringAlgorithm,
|
||||
pdcp_pP->integrityProtAlgorithm);
|
||||
|
||||
kRRCenc != NULL ? memcpy(pdcp_pP->kRRCenc, kRRCenc, 32) : memset(pdcp_pP->kRRCenc, 0, 32);
|
||||
kRRCint != NULL ? memcpy(pdcp_pP->kRRCint, kRRCint, 32) : memset(pdcp_pP->kRRCint, 0, 32);
|
||||
kUPenc != NULL ? memcpy(pdcp_pP->kUPenc, kUPenc, 32) : memset(pdcp_pP->kUPenc, 0, 32);
|
||||
kRRCenc != NULL ? memcpy(pdcp_pP->kRRCenc, kRRCenc+16, 16) : memset(pdcp_pP->kRRCenc, 0, 16);
|
||||
kRRCint != NULL ? memcpy(pdcp_pP->kRRCint, kRRCint+16, 16) : memset(pdcp_pP->kRRCint, 0, 16);
|
||||
kUPenc != NULL ? memcpy(pdcp_pP->kUPenc, kUPenc+16, 16) : memset(pdcp_pP->kUPenc, 0, 16);
|
||||
|
||||
pdcp_pP->security_container_rrc = stream_security_container_create(pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm, pdcp_pP->kRRCenc, pdcp_pP->kRRCint);
|
||||
pdcp_pP->security_container_up = stream_security_container_create(pdcp_pP->cipheringAlgorithm, 0, pdcp_pP->kUPenc, NULL);
|
||||
|
||||
/* Activate security */
|
||||
pdcp_pP->security_activated = 1;
|
||||
@@ -2196,6 +2199,8 @@ void rrc_pdcp_config_req (
|
||||
pdcp_p->last_submitted_pdcp_rx_sn = 4095;
|
||||
pdcp_p->seq_num_size = 0;
|
||||
pdcp_p->first_missing_pdu = -1;
|
||||
stream_security_container_delete(pdcp_p->security_container_rrc);
|
||||
stream_security_container_delete(pdcp_p->security_container_up);
|
||||
pdcp_p->security_activated = 0;
|
||||
h_rc = hashtable_remove(pdcp_coll_p, key);
|
||||
break;
|
||||
|
||||
@@ -181,9 +181,12 @@ typedef struct pdcp_s {
|
||||
* Control-Plane RRC integrity key
|
||||
* These keys are configured by RRC layer
|
||||
*/
|
||||
uint8_t kUPenc[32];
|
||||
uint8_t kRRCint[32];
|
||||
uint8_t kRRCenc[32];
|
||||
uint8_t kUPenc[16];
|
||||
uint8_t kRRCint[16];
|
||||
uint8_t kRRCenc[16];
|
||||
|
||||
stream_security_container_t *security_container_rrc;
|
||||
stream_security_container_t *security_container_up;
|
||||
|
||||
uint8_t security_activated;
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ pdcp_apply_security(
|
||||
{
|
||||
uint8_t *buffer_encrypted = NULL;
|
||||
nas_stream_cipher_t encrypt_params = {0};
|
||||
stream_security_container_t *container;
|
||||
|
||||
DevAssert(pdcp_pP != NULL);
|
||||
DevAssert(pdcp_pdu_buffer != NULL);
|
||||
@@ -122,7 +123,11 @@ pdcp_apply_security(
|
||||
encrypt_params.direction = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
|
||||
encrypt_params.bearer = rb_id - 1;
|
||||
encrypt_params.count = pdcp_get_next_count_tx(pdcp_pP, srb_flagP, current_sn);
|
||||
encrypt_params.key_length = 16;
|
||||
|
||||
if (srb_flagP)
|
||||
container = pdcp_pP->security_container_rrc;
|
||||
else
|
||||
container = pdcp_pP->security_container_up;
|
||||
|
||||
if (srb_flagP) {
|
||||
/* SRBs */
|
||||
@@ -133,7 +138,7 @@ pdcp_apply_security(
|
||||
|
||||
encrypt_params.message = pdcp_pdu_buffer;
|
||||
encrypt_params.blength = (pdcp_header_len + sdu_buffer_size) << 3;
|
||||
encrypt_params.key = pdcp_pP->kRRCint + 16; // + 128;
|
||||
encrypt_params.context = container->integrity_context;
|
||||
|
||||
mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];
|
||||
|
||||
@@ -142,15 +147,13 @@ pdcp_apply_security(
|
||||
stream_compute_integrity(pdcp_pP->integrityProtAlgorithm,
|
||||
&encrypt_params,
|
||||
mac_i);
|
||||
|
||||
encrypt_params.key = pdcp_pP->kRRCenc; // + 128 // bit key
|
||||
} else {
|
||||
LOG_D(PDCP, "[OSA][RB %ld] %s Applying user-plane security\n",
|
||||
rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");
|
||||
|
||||
encrypt_params.key = pdcp_pP->kUPenc;// + 128;
|
||||
}
|
||||
|
||||
encrypt_params.context = container->ciphering_context;
|
||||
|
||||
encrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len];
|
||||
encrypt_params.blength = sdu_buffer_size << 3;
|
||||
|
||||
@@ -180,6 +183,7 @@ pdcp_validate_security(
|
||||
{
|
||||
uint8_t *buffer_decrypted = NULL;
|
||||
nas_stream_cipher_t decrypt_params = {0};
|
||||
stream_security_container_t *container;
|
||||
|
||||
DevAssert(pdcp_pP != NULL);
|
||||
|
||||
@@ -195,17 +199,17 @@ pdcp_validate_security(
|
||||
decrypt_params.count = pdcp_get_next_count_rx(pdcp_pP, srb_flagP, hfn, 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 (srb_flagP) {
|
||||
LOG_D(PDCP, "[OSA][RB %ld] %s Validating control-plane security\n", rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
|
||||
decrypt_params.key = pdcp_pP->kRRCenc;// + 128;
|
||||
container = pdcp_pP->security_container_rrc;
|
||||
} else {
|
||||
LOG_D(PDCP, "[OSA][RB %ld] %s Validating user-plane security\n", rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
|
||||
decrypt_params.key = pdcp_pP->kUPenc;// + 128;
|
||||
container = pdcp_pP->security_container_up;
|
||||
}
|
||||
|
||||
/* Uncipher the block */
|
||||
decrypt_params.context = container->ciphering_context;
|
||||
stream_compute_encrypt(pdcp_pP->cipheringAlgorithm, &decrypt_params, buffer_decrypted);
|
||||
|
||||
if (!IS_SOFTMODEM_IQPLAYER) {
|
||||
@@ -213,7 +217,7 @@ pdcp_validate_security(
|
||||
/* 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_pP->kRRCint + 16;// 128;
|
||||
decrypt_params.context = container->integrity_context;
|
||||
|
||||
if (pdcp_pP->integrityProtAlgorithm != EIA0_ALG_ID) {
|
||||
uint8_t result[4] = {0};
|
||||
@@ -221,10 +225,9 @@ pdcp_validate_security(
|
||||
|
||||
if (memcmp(result, &pdcp_pdu_buffer[sdu_buffer_size], 4) != 0) {
|
||||
LOG_E(PDCP,
|
||||
"[OSA][RB %ld] %s failed to validate MAC-I (key %llx) of incoming PDU\n",
|
||||
"[OSA][RB %ld] %s failed to validate MAC-I of incoming PDU\n",
|
||||
rb_id,
|
||||
(pdcp_pP->is_ue != 0) ? "UE" : "eNB",
|
||||
((long long unsigned int *)decrypt_params.key)[0]);
|
||||
(pdcp_pP->is_ue != 0) ? "UE" : "eNB");
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "nr_pdcp_sdu.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h"
|
||||
#include "openair3/SECU/secu_defs.h"
|
||||
|
||||
/* PDCP Formats according to clause 6.2 of 3GPP TS 38.323 */
|
||||
/* SN Size applicable to SRBs, UM DRBs and AM DRBs */
|
||||
@@ -151,16 +152,17 @@ typedef struct nr_pdcp_entity_t {
|
||||
int integrity_algorithm;
|
||||
unsigned char ciphering_key[16];
|
||||
unsigned char integrity_key[16];
|
||||
void *security_context;
|
||||
void (*cipher)(void *security_context,
|
||||
stream_security_context_t *security_context;
|
||||
void (*cipher)(stream_security_context_t *security_context,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction);
|
||||
void (*free_security)(void *security_context);
|
||||
void *integrity_context;
|
||||
void (*integrity)(void *integrity_context, unsigned char *out,
|
||||
void (*free_security)(stream_security_context_t *security_context);
|
||||
stream_security_context_t *integrity_context;
|
||||
void (*integrity)(stream_security_context_t *integrity_context,
|
||||
unsigned char *out,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction);
|
||||
void (*free_integrity)(void *integrity_context);
|
||||
void (*free_integrity)(stream_security_context_t *integrity_context);
|
||||
/* security/integrity algorithms need to know uplink/downlink information
|
||||
* which is reverse for gnb and ue, so we need to know if this
|
||||
* pdcp entity is for a gnb or an ue
|
||||
|
||||
@@ -28,24 +28,23 @@
|
||||
#include "openair3/SECU/secu_defs.h"
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
|
||||
void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key)
|
||||
stream_security_context_t *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key)
|
||||
{
|
||||
nas_stream_cipher_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(*ret)); if (ret == NULL) abort();
|
||||
ret->key = malloc(16); if (ret->key == NULL) abort();
|
||||
memcpy(ret->key, integrity_key, 16);
|
||||
ret->key_length = 16; /* unused */
|
||||
ret->context = malloc(16); if (ret->context == NULL) abort();
|
||||
memcpy(ret->context, integrity_key, 16);
|
||||
|
||||
return ret;
|
||||
return (stream_security_context_t *)ret;
|
||||
}
|
||||
|
||||
void nr_pdcp_integrity_nia1_integrity(void *integrity_context,
|
||||
void nr_pdcp_integrity_nia1_integrity(stream_security_context_t *integrity_context,
|
||||
unsigned char *out,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction)
|
||||
{
|
||||
nas_stream_cipher_t *ctx = integrity_context;
|
||||
nas_stream_cipher_t *ctx = (nas_stream_cipher_t *)integrity_context;
|
||||
|
||||
ctx->message = buffer;
|
||||
ctx->count = count;
|
||||
@@ -56,9 +55,9 @@ void nr_pdcp_integrity_nia1_integrity(void *integrity_context,
|
||||
stream_compute_integrity(EIA1_128_ALG_ID, ctx, out);
|
||||
}
|
||||
|
||||
void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context)
|
||||
void nr_pdcp_integrity_nia1_free_integrity(stream_security_context_t *integrity_context)
|
||||
{
|
||||
nas_stream_cipher_t *ctx = integrity_context;
|
||||
free(ctx->key);
|
||||
nas_stream_cipher_t *ctx = (nas_stream_cipher_t *)integrity_context;
|
||||
free(ctx->context);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
#ifndef _NR_PDCP_INTEGRITY_NIA1_H_
|
||||
#define _NR_PDCP_INTEGRITY_NIA1_H_
|
||||
|
||||
void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key);
|
||||
#include "openair3/SECU/secu_defs.h"
|
||||
|
||||
void nr_pdcp_integrity_nia1_integrity(void *integrity_context,
|
||||
stream_security_context_t *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key);
|
||||
|
||||
void nr_pdcp_integrity_nia1_integrity(stream_security_context_t *integrity_context,
|
||||
unsigned char *out,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction);
|
||||
|
||||
void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context);
|
||||
void nr_pdcp_integrity_nia1_free_integrity(stream_security_context_t *integrity_context);
|
||||
|
||||
#endif /* _NR_PDCP_INTEGRITY_NIA1_H_ */
|
||||
|
||||
@@ -30,29 +30,25 @@
|
||||
#include "openair3/SECU/aes_128.h"
|
||||
#include "openair3/SECU/aes_128_cbc_cmac.h"
|
||||
|
||||
void *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16])
|
||||
stream_security_context_t *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16])
|
||||
{
|
||||
// This is a hack. Reduce the 3 functions to just cipher?
|
||||
// No. The overhead is x8 times more. Don't change before measuring
|
||||
// return integrity_key;
|
||||
cbc_cmac_ctx_t* ctx = calloc(1, sizeof(cbc_cmac_ctx_t));
|
||||
AssertFatal(ctx, "Memory exhausted");
|
||||
|
||||
*ctx = init_aes_128_cbc_cmac(integrity_key);
|
||||
return ctx;
|
||||
return (stream_security_context_t *)ctx;
|
||||
}
|
||||
|
||||
void nr_pdcp_integrity_nia2_integrity(void *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction)
|
||||
void nr_pdcp_integrity_nia2_integrity(stream_security_context_t *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction)
|
||||
{
|
||||
DevAssert(integrity_context != NULL);
|
||||
DevAssert(out != NULL);
|
||||
DevAssert(buffer != NULL);
|
||||
DevAssert(length > -1);
|
||||
// Strange range: [1-32] instead of [0-31]
|
||||
DevAssert(bearer > 0 && bearer < 33);
|
||||
DevAssert(count > -1);
|
||||
|
||||
cbc_cmac_ctx_t* ctx = (cbc_cmac_ctx_t*)integrity_context;
|
||||
cbc_cmac_ctx_t *ctx = (cbc_cmac_ctx_t *)integrity_context;
|
||||
|
||||
aes_128_t k_iv = {0};
|
||||
memcpy(&k_iv.key, ctx->key, sizeof(k_iv.key));
|
||||
@@ -64,18 +60,13 @@ void nr_pdcp_integrity_nia2_integrity(void *integrity_context, unsigned char *ou
|
||||
uint8_t result[16] = {0};
|
||||
byte_array_t msg = {.buf = buffer, .len = length};
|
||||
|
||||
cipher_aes_128_cbc_cmac((cbc_cmac_ctx_t*)integrity_context, &k_iv, msg, sizeof(result), result);
|
||||
//aes_128_cbc_cmac(&k_iv, msg, sizeof(result), result);
|
||||
cipher_aes_128_cbc_cmac(ctx, &k_iv, msg, sizeof(result), result);
|
||||
|
||||
// AES CMAC (RFC 4493) outputs 128 bits but NR PDCP PDUs have a MAC-I of
|
||||
// 32 bits (see 38.323 6.2). RFC 4493 2.1 says to truncate most significant
|
||||
// bit first (so seems to say 33.401 B.2.3)
|
||||
// Precondition: out should have enough space...
|
||||
memcpy(out, result, 4);
|
||||
}
|
||||
|
||||
void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context)
|
||||
void nr_pdcp_integrity_nia2_free_integrity(stream_security_context_t *integrity_context)
|
||||
{
|
||||
free( ( cbc_cmac_ctx_t*) integrity_context);
|
||||
free_aes_128_cbc_cmac((cbc_cmac_ctx_t *)integrity_context);
|
||||
free(integrity_context);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]);
|
||||
#include "openair3/SECU/secu_defs.h"
|
||||
|
||||
void nr_pdcp_integrity_nia2_integrity(void *integrity_context,
|
||||
stream_security_context_t *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]);
|
||||
|
||||
void nr_pdcp_integrity_nia2_integrity(stream_security_context_t *integrity_context,
|
||||
unsigned char *out,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction);
|
||||
|
||||
void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context);
|
||||
void nr_pdcp_integrity_nia2_free_integrity(stream_security_context_t *integrity_context);
|
||||
|
||||
#endif /* _NR_PDCP_INTEGRITY_NIA2_H_ */
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *nr_pdcp_security_nea2_init(unsigned char *ciphering_key)
|
||||
stream_security_context_t *nr_pdcp_security_nea2_init(unsigned char *ciphering_key)
|
||||
{
|
||||
// This is a hack, IMO init, cipher and free functions should be reduced to cipher.
|
||||
// Test show a ~10% more processing time
|
||||
return ciphering_key;
|
||||
return (stream_security_context_t *)ciphering_key;
|
||||
}
|
||||
|
||||
void nr_pdcp_security_nea2_cipher(void *security_context, unsigned char *buffer, int length, int bearer, int count, int direction)
|
||||
void nr_pdcp_security_nea2_cipher(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, int count, int direction)
|
||||
{
|
||||
DevAssert(security_context != NULL);
|
||||
DevAssert(buffer != NULL);
|
||||
@@ -62,7 +62,7 @@ void nr_pdcp_security_nea2_cipher(void *security_context, unsigned char *buffer,
|
||||
memcpy(buffer, out, length);
|
||||
}
|
||||
|
||||
void nr_pdcp_security_nea2_free_security(void *security_context)
|
||||
void nr_pdcp_security_nea2_free_security(stream_security_context_t *security_context)
|
||||
{
|
||||
(void)security_context;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
#ifndef _NR_PDCP_SECURITY_NEA2_H_
|
||||
#define _NR_PDCP_SECURITY_NEA2_H_
|
||||
|
||||
void *nr_pdcp_security_nea2_init(unsigned char *ciphering_key);
|
||||
#include "openair3/SECU/secu_defs.h"
|
||||
|
||||
void nr_pdcp_security_nea2_cipher(void *security_context,
|
||||
stream_security_context_t *nr_pdcp_security_nea2_init(unsigned char *ciphering_key);
|
||||
|
||||
void nr_pdcp_security_nea2_cipher(stream_security_context_t *security_context,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, int count, int direction);
|
||||
|
||||
void nr_pdcp_security_nea2_free_security(void *security_context);
|
||||
void nr_pdcp_security_nea2_free_security(stream_security_context_t *security_context);
|
||||
|
||||
#endif /* _NR_PDCP_SECURITY_NEA2_H_ */
|
||||
|
||||
Reference in New Issue
Block a user