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:
Cedric Roux
2024-04-26 23:31:06 +02:00
parent c0934b26da
commit d7931ea412
27 changed files with 323 additions and 274 deletions
+8 -3
View File
@@ -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;
+6 -3
View File
@@ -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;
+16 -13
View File
@@ -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;
}