Commit d7931ea4 authored by Cedric Roux's avatar Cedric Roux

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.
parent c0934b26
......@@ -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_ */
......@@ -1009,8 +1009,7 @@ static int _nas_message_decrypt(
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.context = emm_security_context->security_container->ciphering_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......@@ -1045,8 +1044,7 @@ static int _nas_message_decrypt(
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.context = emm_security_context->security_container->ciphering_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......@@ -1178,8 +1176,7 @@ static int _nas_message_encrypt(
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.context = emm_security_context->security_container->ciphering_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......@@ -1208,8 +1205,7 @@ static int _nas_message_encrypt(
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.context = emm_security_context->security_container->ciphering_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......@@ -1347,8 +1343,7 @@ static uint32_t _nas_message_get_mac(
fflush(stderr);
#endif
stream_cipher.key = emm_security_context->knas_int.value;
stream_cipher.key_length = AUTH_KNAS_INT_SIZE;
stream_cipher.context = emm_security_context->security_container->integrity_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......@@ -1391,8 +1386,7 @@ static uint32_t _nas_message_get_mac(
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_int.value;
stream_cipher.key_length = AUTH_KNAS_INT_SIZE;
stream_cipher.context = emm_security_context->security_container->integrity_context;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
......
......@@ -515,6 +515,10 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype
static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf)
{
derive_ue_keys(buf, nas);
/* todo: as of now, nia2 is hardcoded in derive_ue_keys(), remove this hardcoding, use NAS signalling for getting proper algorithm */
/* todo: deal with ciphering for this stream_security_container_create() (handle ciphering in general) */
/* todo: stream_security_container_delete() is not called anywhere, deal with that */
nas->security_container = stream_security_container_create(0, 2 /* hardcoded: nia2 */, NULL, nas->security.knas_int);
OctetString res;
res.length = 16;
res.value = calloc(1,16);
......@@ -598,8 +602,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16;
stream_cipher.context = nas->security_container->integrity_context;
stream_cipher.count = nas->security.mm_counter++;
stream_cipher.bearer = 1;
stream_cipher.direction = 0;
......@@ -701,8 +704,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
}
initialNasMsg->length = length;
stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16;
stream_cipher.context = nas->security_container->integrity_context;
stream_cipher.count = nas->security.mm_counter++;
stream_cipher.bearer = 1;
stream_cipher.direction = 0;
......@@ -764,8 +766,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
initialNasMsg->length = security_header_len + mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len);
nas_stream_cipher_t stream_cipher = {
.key = nas->security.knas_int,
.key_length = 16,
.context = nas->security_container->integrity_context,
.count = nas->security.mm_counter++,
.bearer = 1,
.direction = 0,
......@@ -857,8 +858,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16;
stream_cipher.context = nas->security_container->integrity_context;
stream_cipher.count = nas->security.mm_counter++;
stream_cipher.bearer = 1;
stream_cipher.direction = 0;
......
......@@ -41,6 +41,7 @@
#include "as_message.h"
#include "FGSUplinkNasTransport.h"
#include <openair3/UICC/usim_interface.h>
#include "secu_defs.h"
#define PLAIN_5GS_MSG 0b0000
#define INTEGRITY_PROTECTED 0b0001
......@@ -98,6 +99,7 @@ typedef struct {
typedef struct {
uicc_t *uicc;
ue_sa_security_key_t security;
stream_security_container_t *security_container;
Guti5GSMobileIdentity_t *guti;
bool termination_procedure;
} nr_ue_nas_t;
......
......@@ -258,6 +258,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi,
LOG_TRACE(INFO,
"EMM-PROC - Update Current security context");
/* Release non-current security context */
stream_security_container_delete(user->emm_data->security->security_container);
_security_release(user->emm_data->security);
user->emm_data->security = user->emm_data->non_current;
/* Reset the uplink NAS COUNT counter */
......@@ -265,6 +266,12 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi,
user->emm_data->security->ul_count.seq_num = 0;
/* Set new security context indicator */
security_context_is_new = true;
/* create contexts */
user->emm_data->security->security_container = stream_security_container_create(
seea,
seia,
user->emm_data->non_current->knas_enc.value,
user->emm_data->non_current->knas_int.value);
}
}
......
......@@ -42,6 +42,7 @@ Description Defines internal private data handled by EPS Mobility
#include "commonDef.h"
#include "networkDef.h"
#include "securityDef.h"
#include "openair3/SECU/secu_defs.h"
#include "OctetString.h"
#include "nas_timer.h"
......@@ -138,6 +139,7 @@ typedef struct emm_security_context_s {
//OctetString ksgsn; /* SGSN security key (mapped context) */
OctetString knas_enc; /* NAS cyphering key */
OctetString knas_int; /* NAS integrity key */
stream_security_container_t *security_container; /* container for NAS security */
struct count_s{
uint32_t spare:8;
uint32_t overflow:16;
......
......@@ -31,101 +31,56 @@
// code for version 3.0 or greater
#include <openssl/core_names.h>
static
const char *propq = NULL;
void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out])
cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16])
{
OSSL_LIB_CTX* library_context = OSSL_LIB_CTX_new();
DevAssert(library_context != NULL);
DevAssert(key != NULL);
/* Fetch the CMAC implementation */
EVP_MAC* mac = EVP_MAC_fetch(library_context, "CMAC", propq);
DevAssert(mac != NULL);
EVP_MAC *mac_implementation = EVP_MAC_fetch(NULL, "CMAC", NULL);
DevAssert(mac_implementation != NULL);
/* Create a context for the CMAC operation */
EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(mac);
DevAssert(mctx != NULL);
EVP_MAC_CTX* mac = EVP_MAC_CTX_new(mac_implementation);
DevAssert(mac != NULL);
cbc_cmac_ctx_t ctx = { .lib_ctx = mac_implementation, .mac = mac };
memcpy(ctx.key, key, 16);
// The underlying cipher to be used
// The underlying cipher to be used
char cipher_name[] = "aes128";
OSSL_PARAM params[2] = {0};
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name,
sizeof(cipher_name));
params[1] = OSSL_PARAM_construct_end();
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name,
sizeof(cipher_name));
params[1] = OSSL_PARAM_construct_end();
/* Initialise the CMAC operation */
int rc = EVP_MAC_init(mctx, k_iv->key, sizeof(k_iv->key), params);
DevAssert(rc != 0);
size_t sz_iv = 0;
uint8_t* iv = NULL;
if(k_iv->type == AES_INITIALIZATION_VECTOR_8){
sz_iv = 8;
iv = (uint8_t*)k_iv->iv8.iv;
} else if(k_iv->type == AES_INITIALIZATION_VECTOR_16) {
sz_iv = 16;
iv = (uint8_t*)k_iv->iv16.iv;
} else {
DevAssert(0!=0 && "Unknwon Initialization vector");
}
/* Make one or more calls to process the data to be authenticated */
rc = EVP_MAC_update(mctx, iv, sz_iv);
DevAssert(rc != 0);
/* Make one or more calls to process the data to be authenticated */
rc = EVP_MAC_update(mctx, msg.buf, msg.len);
int rc = EVP_MAC_init(mac, key, 16, params);
DevAssert(rc != 0);
/* Make a call to the final with a NULL buffer to get the length of the MAC */
size_t out_len = 0;
rc = EVP_MAC_final(mctx, out, &out_len, len_out);
DevAssert(rc != 0);
EVP_MAC_CTX_free(mctx);
EVP_MAC_free(mac);
OSSL_LIB_CTX_free(library_context);
}
cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16])
{
DevAssert(key != NULL);
OSSL_LIB_CTX* library_context = OSSL_LIB_CTX_new();
DevAssert(library_context != NULL);
/* Fetch the CMAC implementation */
EVP_MAC* mac = EVP_MAC_fetch(library_context, "CMAC", propq);
DevAssert(mac != NULL);
cbc_cmac_ctx_t ctx = {.lib_ctx = library_context, .mac = mac };
assert(16 == sizeof(ctx.key));
memcpy(ctx.key, key, 16);
return ctx;
return ctx;
}
void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out])
{
DevAssert(ctx != NULL);
DevAssert(k_iv != NULL);
/* Create a context for the CMAC operation */
EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(ctx->mac);
DevAssert(mctx != NULL);
// The underlying cipher to be used
char cipher_name[] = "aes128";
OSSL_PARAM params[2] = {0};
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name,
sizeof(cipher_name));
params[1] = OSSL_PARAM_construct_end();
/* Initialise the CMAC operation */
int rc = EVP_MAC_init(mctx, k_iv->key, sizeof(k_iv->key), params);
/* reset the CMAC */
/* There is a bug with version <= 3.0.2 of OpenSSL for which we must
* pass the key to reset. (Some Ubuntu version provide this version.)
* Passing the key has some impact on performance.
* todo: drop support for old versions of openssl.
*/
#if OPENSSL_VERSION_NUMBER <= 0x30000020
/* todo: when/if we remove this code, don't forget to check use of k_iv->key
* somewhere else in the codebase.
* If not used, remove from aes_128_t*
*/
int rc = EVP_MAC_init(ctx->mac, k_iv->key, 16, NULL);
#else
int rc = EVP_MAC_init(ctx->mac, NULL, 0, NULL);
#endif
DevAssert(rc != 0);
size_t sz_iv = 0;
......@@ -141,66 +96,33 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b
}
/* Make one or more calls to process the data to be authenticated */
rc = EVP_MAC_update(mctx, iv, sz_iv);
rc = EVP_MAC_update(ctx->mac, iv, sz_iv);
DevAssert(rc != 0);
/* Make one or more calls to process the data to be authenticated */
rc = EVP_MAC_update(mctx, msg.buf, msg.len);
rc = EVP_MAC_update(ctx->mac, msg.buf, msg.len);
DevAssert(rc != 0);
/* Make a call to the final with a NULL buffer to get the length of the MAC */
size_t out_len = 0;
rc = EVP_MAC_final(mctx, out, &out_len, len_out);
rc = EVP_MAC_final(ctx->mac, out, &out_len, len_out);
DevAssert(rc != 0);
EVP_MAC_CTX_free(mctx);
}
void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx)
{
DevAssert(ctx != NULL);
EVP_MAC_free(ctx->mac);
OSSL_LIB_CTX_free(ctx->lib_ctx);
EVP_MAC_CTX_free(ctx->mac);
EVP_MAC_free(ctx->lib_ctx);
}
#else
// code for 1.1.x or lower
void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out])
{
DevAssert(k_iv != NULL);
CMAC_CTX *ctx = CMAC_CTX_new();
DevAssert(ctx != NULL);
CMAC_Init(ctx, k_iv->key, sizeof(k_iv->key), EVP_aes_128_cbc(), NULL);
size_t sz_iv = 0;
uint8_t* iv = NULL;
if(k_iv->type == AES_INITIALIZATION_VECTOR_8){
sz_iv = 8;
iv = (uint8_t*)k_iv->iv8.iv;
} else if(k_iv->type == AES_INITIALIZATION_VECTOR_16) {
sz_iv = 16;
iv = (uint8_t*)k_iv->iv16.iv;
} else {
AssertFatal(0 != 0, "Unknwon Initialization vector");
}
CMAC_Update(ctx, iv, sz_iv);
CMAC_Update(ctx, msg.buf, msg.len);
size_t len_res = 0;
CMAC_Final(ctx, out, &len_res);
DevAssert(len_res <= len_out);
CMAC_CTX_free(ctx);
}
cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16])
cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16])
{
DevAssert(key != NULL);
cbc_cmac_ctx_t ctx = {.lib_ctx = NULL, .mac = NULL };
cbc_cmac_ctx_t ctx = {.lib_ctx = NULL, .mac = NULL };
ctx.mac = CMAC_CTX_new();
DevAssert(ctx.mac != NULL);
......@@ -218,9 +140,9 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b
DevAssert(k_iv != NULL);
//From https://man.openbsd.org/CMAC_Init.3
//If ctx is already initialized, CMAC_Init() can be called again with key,
//cipher, and impl all set to NULL and key_len set to 0. In that case, any
//data already processed is discarded and ctx is re-initialized to start
//If ctx is already initialized, CMAC_Init() can be called again with key,
//cipher, and impl all set to NULL and key_len set to 0. In that case, any
//data already processed is discarded and ctx is re-initialized to start
//reading data anew.
CMAC_Init(ctx->mac, NULL, 0, NULL, NULL);
......@@ -251,4 +173,3 @@ void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx)
}
#endif
......@@ -36,12 +36,8 @@ typedef struct {
uint8_t key[16];
} cbc_cmac_ctx_t ;
void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]);
cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16]);
cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16]);
void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]);
void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx);
#endif
......
......@@ -38,10 +38,9 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t *
//uint32_t byte_length;
uint32_t *KS;
uint32_t K[4],IV[4];
uint8_t *key = (uint8_t *)stream_cipher->context;
DevAssert(stream_cipher != NULL);
DevAssert(stream_cipher->key != NULL);
DevAssert(stream_cipher->key_length == 16);
DevAssert(out != NULL);
n = ( stream_cipher->blength + 31 ) / 32;
......@@ -50,22 +49,20 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t *
memset(&snow_3g_context, 0, sizeof(snow_3g_context));
/*Initialisation*/
/* Load the confidentiality key for SNOW 3G initialization as in section
3.4. */
memcpy(K+3,stream_cipher->key+0,4); /*K[3] = key[0]; we assume
/* Load the confidentiality key for SNOW 3G initialization as in section 3.4. */
memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume
K[3]=key[0]||key[1]||...||key[31] , with key[0] the
* most important bit of key*/
memcpy(K+2,stream_cipher->key+4,4); /*K[2] = key[1];*/
memcpy(K+1,stream_cipher->key+8,4); /*K[1] = key[2];*/
memcpy(K+0,stream_cipher->key+12,4); /*K[0] = key[3]; we assume
K[0]=key[96]||key[97]||...||key[127] , with key[127] the
* least important bit of key*/
memcpy(K+2,key+4,4); /*K[2] = key[1];*/
memcpy(K+1,key+8,4); /*K[1] = key[2];*/
memcpy(K+0,key+12,4); /*K[0] = key[3]; we assume
* K[0]=key[96]||key[97]||...||key[127] , with key[127] the
* least important bit of key*/
K[3] = hton_int32(K[3]);
K[2] = hton_int32(K[2]);
K[1] = hton_int32(K[1]);
K[0] = hton_int32(K[0]);
/* Prepare the initialization vector (IV) for SNOW 3G initialization as in
section 3.4. */
/* Prepare the initialization vector (IV) for SNOW 3G initialization as in section 3.4. */
IV[3] = stream_cipher->count;
IV[2] = ((((uint32_t)stream_cipher->bearer) << 3) | ((((uint32_t)stream_cipher->direction) & 0x1) << 2)) << 24;
IV[1] = IV[3];
......@@ -104,3 +101,16 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t *
out[ceil_index - 1] = stream_cipher->message[ceil_index - 1];
}
}
stream_security_context_t *stream_ciphering_init_eea1(const uint8_t *ciphering_key)
{
void *ret = calloc(1, 16);
AssertFatal(ret != NULL, "out of memory\n");
memcpy(ret, ciphering_key, 16);
return (stream_security_context_t *)ret;
}
void stream_ciphering_free_eea1(stream_security_context_t *ciphering_context)
{
free(ciphering_context);
}
......@@ -29,4 +29,7 @@
void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t *out);
stream_security_context_t *stream_ciphering_init_eea1(const uint8_t *ciphering_key);
void stream_ciphering_free_eea1(stream_security_context_t *ciphering_context);
#endif
......@@ -33,15 +33,13 @@
void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t *out)
{
DevAssert(stream_cipher != NULL);
DevAssert(stream_cipher->key != NULL);
DevAssert(stream_cipher->key_length == 32);
DevAssert(stream_cipher->bearer < 32);
DevAssert(stream_cipher->direction < 2);
DevAssert(stream_cipher->message != NULL);
DevAssert(stream_cipher->blength > 7);
aes_128_t p = {0};
memcpy(p.key, stream_cipher->key, stream_cipher->key_length);
memcpy(p.key, stream_cipher->context, 16);
p.type = AES_INITIALIZATION_VECTOR_16;
p.iv16.d.count = htonl(stream_cipher->count);
p.iv16.d.bearer = stream_cipher->bearer;
......@@ -54,3 +52,16 @@ void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t *
byte_array_t msg = {.buf = stream_cipher->message, .len = byte_lenght};
aes_128_ctr(&p, msg, len_out, out);
}
stream_security_context_t *stream_ciphering_init_eea2(const uint8_t *ciphering_key)
{
void *ret = calloc(1, 16);
AssertFatal(ret != NULL, "out of memory\n");
memcpy(ret, ciphering_key, 16);
return (stream_security_context_t *)ret;
}
void stream_ciphering_free_eea2(stream_security_context_t *ciphering_context)
{
free(ciphering_context);
}
......@@ -26,40 +26,9 @@
#include "secu_defs.h"
#include <stdint.h>
/* Rijndael S-box OSA_SR */
static const uint8_t OSA_SR[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
/* S-box OSA_SQ */
static const uint8_t OSA_SQ[256] = {
0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB, 0xE4, 0x8E, 0x48, 0x49,
0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED, 0x40, 0x2F, 0x11, 0x28,
0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, 0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, 0x07, 0x4B, 0x0E, 0xC1,
0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01, 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, 0x9F, 0x20, 0x4C, 0x64,
0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4, 0x8D, 0xB0, 0xE5, 0x93,
0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52, 0x1D, 0x55, 0x1A, 0xC5,
0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, 0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, 0x50, 0x8A, 0xB6, 0x62,
0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C, 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, 0x81, 0x32, 0xA0, 0x00,
0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53, 0x63, 0x75, 0x35, 0x2C,
0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B, 0x54, 0x0B, 0xE0, 0x38,
0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, 0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, 0x74, 0x91, 0xAB, 0x26,
0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99, 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, 0x3E, 0x18, 0x10, 0x3A,
0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86};
void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t *out);
stream_security_context_t *stream_ciphering_init_eea2(const uint8_t *ciphering_key);
void stream_ciphering_free_eea2(stream_security_context_t *ciphering_context);
#endif
......@@ -126,16 +126,17 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
uint64_t M_D_2;
int rem_bits;
uint32_t mask = 0;
uint32_t *message;
uint32_t *message;
uint8_t *key = (uint8_t *)stream_cipher->context;
message = (uint32_t*)stream_cipher->message; /* To operate 32 bit message internally. */
/* Load the Integrity Key for SNOW3G initialization as in section 4.4. */
memcpy(K+3,stream_cipher->key+0,4); /*K[3] = key[0]; we assume
memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume
K[3]=key[0]||key[1]||...||key[31] , with key[0] the
* most important bit of key*/
memcpy(K+2,stream_cipher->key+4,4); /*K[2] = key[1];*/
memcpy(K+1,stream_cipher->key+8,4); /*K[1] = key[2];*/
memcpy(K+0,stream_cipher->key+12,4); /*K[0] = key[3]; we assume
memcpy(K+2,key+4,4); /*K[2] = key[1];*/
memcpy(K+1,key+8,4); /*K[1] = key[2];*/
memcpy(K+0,key+12,4); /*K[0] = key[3]; we assume
K[0]=key[96]||key[97]||...||key[127] , with key[127] the
* least important bit of key*/
K[3] = hton_int32(K[3]);
......@@ -213,3 +214,16 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
MAC_I = hton_int32(MAC_I);
memcpy(out, &MAC_I, 4);
}
stream_security_context_t *stream_integrity_init_eia1(const uint8_t *integrity_key)
{
void *ret = calloc(1, 16);
AssertFatal(ret != NULL, "out of memory\n");
memcpy(ret, integrity_key, 16);
return (stream_security_context_t *)ret;
}
void stream_integrity_free_eia1(stream_security_context_t *integrity_context)
{
free(integrity_context);
}
......@@ -26,4 +26,7 @@
void nas_stream_encrypt_eia1(nas_stream_cipher_t const* stream_cipher, uint8_t out[4]);
stream_security_context_t *stream_integrity_init_eia1(const uint8_t *integrity_key);
void stream_integrity_free_eia1(stream_security_context_t *integrity_context);
#endif
......@@ -45,11 +45,11 @@ void nas_stream_encrypt_eia2(nas_stream_cipher_t const *stream_cipher, uint8_t o
DevAssert(stream_cipher != NULL);
DevAssert(stream_cipher->message != NULL);
DevAssert(stream_cipher->bearer < 32);
DevAssert(stream_cipher->key_length == 16);
DevAssert((stream_cipher->blength & 0x7) == 0);
cbc_cmac_ctx_t *ctx = (cbc_cmac_ctx_t *)stream_cipher->context;
aes_128_t k_iv = {0};
memcpy(k_iv.key, stream_cipher->key, sizeof(k_iv.key));
memcpy(&k_iv.key, ctx->key, 16);
k_iv.type = AES_INITIALIZATION_VECTOR_8;
k_iv.iv8.d.bearer = stream_cipher->bearer;
k_iv.iv8.d.direction = stream_cipher->direction;
......@@ -58,8 +58,21 @@ void nas_stream_encrypt_eia2(nas_stream_cipher_t const *stream_cipher, uint8_t o
size_t const m_length = stream_cipher->blength >> 3;
uint8_t result[16] = {0};
byte_array_t msg = {.buf = stream_cipher->message, .len = m_length };
aes_128_cbc_cmac(&k_iv, msg, sizeof(result), result);
cipher_aes_128_cbc_cmac((cbc_cmac_ctx_t *)stream_cipher->context, &k_iv, msg, sizeof(result), result);
memcpy(out, result, 4);
}
stream_security_context_t *stream_integrity_init_eia2(const uint8_t *integrity_key)
{
cbc_cmac_ctx_t *ret = calloc(1, sizeof(cbc_cmac_ctx_t));
AssertFatal(ret != NULL, "out of memory\n");
*ret = init_aes_128_cbc_cmac(integrity_key);
return (stream_security_context_t *)ret;
}
void stream_integrity_free_eia2(stream_security_context_t *integrity_context)
{
free_aes_128_cbc_cmac((cbc_cmac_ctx_t *)integrity_context);
free(integrity_context);
}
......@@ -26,4 +26,7 @@
void nas_stream_encrypt_eia2(nas_stream_cipher_t const* stream_cipher, uint8_t out[4]);
stream_security_context_t *stream_integrity_init_eia2(const uint8_t *integrity_key);
void stream_integrity_free_eia2(stream_security_context_t *integrity_context);
#endif
......@@ -64,3 +64,70 @@ void stream_compute_encrypt(eea_alg_id_e alg, nas_stream_cipher_t const* stream_
}
}
stream_security_context_t *stream_integrity_init(int integrity_algorithm, const uint8_t *integrity_key)
{
switch (integrity_algorithm) {
case EEA0_ALG_ID: return NULL;
case EEA1_128_ALG_ID: return stream_integrity_init_eia1(integrity_key);
case EEA2_128_ALG_ID: return stream_integrity_init_eia2(integrity_key);
default: AssertFatal(0, "unsupported integrity algorithm\n");
}
}
void stream_integrity_free(int integrity_algorithm, stream_security_context_t *integrity_context)
{
switch (integrity_algorithm) {
case EEA0_ALG_ID: return;
case EEA1_128_ALG_ID: return stream_integrity_free_eia1(integrity_context);
case EEA2_128_ALG_ID: return stream_integrity_free_eia2(integrity_context);
default: AssertFatal(0, "unsupported integrity algorithm\n");
}
}
stream_security_context_t *stream_ciphering_init(int ciphering_algorithm, const uint8_t *ciphering_key)
{
switch (ciphering_algorithm) {
case EEA0_ALG_ID: return NULL;
case EEA1_128_ALG_ID: return stream_ciphering_init_eea1(ciphering_key);
case EEA2_128_ALG_ID: return stream_ciphering_init_eea2(ciphering_key);
default: AssertFatal(0, "unsupported ciphering algorithm\n");
}
}
void stream_ciphering_free(int ciphering_algorithm, stream_security_context_t *ciphering_context)
{
switch (ciphering_algorithm) {
case EEA0_ALG_ID: return;
case EEA1_128_ALG_ID: return stream_ciphering_free_eea1(ciphering_context);
case EEA2_128_ALG_ID: return stream_ciphering_free_eea2(ciphering_context);
default: AssertFatal(0, "unsupported ciphering algorithm\n");
}
}
stream_security_container_t *stream_security_container_create(int ciphering_algorithm,
int integrity_algorithm,
const uint8_t *ciphering_key,
const uint8_t *integrity_key)
{
stream_security_container_t *container = calloc(1, sizeof(*container));
AssertFatal(container != NULL, "out of memory\n");
container->integrity_algorithm = integrity_algorithm;
container->ciphering_algorithm = ciphering_algorithm;
container->integrity_context = stream_integrity_init(integrity_algorithm, integrity_key);
container->ciphering_context = stream_ciphering_init(ciphering_algorithm, ciphering_key);
return container;
}
void stream_security_container_delete(stream_security_container_t *container)
{
/* passing NULL is accepted */
if (container == NULL)
return;
stream_integrity_free(container->integrity_algorithm, container->integrity_context);
stream_ciphering_free(container->ciphering_algorithm, container->ciphering_context);
free(container);
}
......@@ -28,17 +28,42 @@
#define SECU_DIRECTION_UPLINK 0
#define SECU_DIRECTION_DOWNLINK 1
/* stream_security_context_t is an opaque structure
* it is different for each integrity and ciphering algorithm in use
*/
typedef void stream_security_context_t;
/* stream_security_container_t contains the current configuration
* of integrity and ciphering. It is used by PDCP and NAS.
*/
typedef struct {
uint8_t *key;
uint32_t key_length;
int integrity_algorithm;
int ciphering_algorithm;
stream_security_context_t *ciphering_context;
stream_security_context_t *integrity_context;
} stream_security_container_t;
typedef struct {
stream_security_context_t *context;
uint32_t count;
uint8_t bearer;
uint8_t direction;
uint8_t *message;
/* length in bits */
uint32_t blength;
uint32_t blength;
} nas_stream_cipher_t;
stream_security_context_t *stream_integrity_init(int integrity_algorithm, const uint8_t *integrity_key);
stream_security_context_t *stream_ciphering_init(int ciphering_algorithm, const uint8_t *ciphering_key);
void stream_integrity_free(int integrity_algorithm, stream_security_context_t *integrity_context);
void stream_ciphering_free(int ciphering_algorithm, stream_security_context_t *ciphering_context);
stream_security_container_t *stream_security_container_create(int ciphering_algorithm,
int integrity_algorithm,
const uint8_t *ciphering_key,
const uint8_t *integrity_key);
void stream_security_container_delete(stream_security_container_t *container);
/*!
* @brief Encrypt/Decrypt a block of data based on the provided algorithm
* @param[in] algorithm Algorithm used to encrypt the data
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment