Commit 252a7caf authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/bugfix-speedup-integrity' into integration_2024_w17

parents 434b2b22 39a5e728
......@@ -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_init(pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm, pdcp_pP->kRRCenc, pdcp_pP->kRRCint);
pdcp_pP->security_container_up = stream_security_container_init(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,15 +1044,14 @@ 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;
stream_cipher.message = (unsigned char *)src;
/* length in bits */
stream_cipher.blength = length << 3;
stream_compute_encrypt(EEA1_128_ALG_ID, &stream_cipher, (unsigned char *)dest);
stream_compute_encrypt(EEA2_128_ALG_ID, &stream_cipher, (unsigned char *)dest);
/* Decode the first octet (security header type or EPS bearer identity,
* and protocol discriminator) */
......@@ -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_init() (handle ciphering in general) */
/* todo: stream_security_container_delete() is not called anywhere, deal with that */
nas->security_container = stream_security_container_init(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;
......@@ -699,8 +702,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;
......@@ -762,8 +764,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,
......@@ -853,8 +854,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_init(
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,21 +31,20 @@
// 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_context = EVP_MAC_CTX_new(mac_implementation);
DevAssert(mac_context != NULL);
cbc_cmac_ctx_t ctx = { .mac_implementation = mac_implementation, .mac_context = mac_context };
memcpy(ctx.key, key, 16);
// The underlying cipher to be used
char cipher_name[] = "aes128";
......@@ -56,55 +55,9 @@ void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, u
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);
int rc = EVP_MAC_init(mac_context, key, 16, params);
DevAssert(rc != 0);
/* Make one or more calls to process the data to be authenticated */
rc = EVP_MAC_update(mctx, 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);
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;
}
......@@ -112,20 +65,22 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b
{
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_context, k_iv->key, 16, NULL);
#else
int rc = EVP_MAC_init(ctx->mac_context, NULL, 0, NULL);
#endif
DevAssert(rc != 0);
size_t sz_iv = 0;
......@@ -141,74 +96,41 @@ 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_context, 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_context, 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_context, 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_context);
EVP_MAC_free(ctx->mac_implementation);
}
#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 = {.mac_implementation = NULL, .mac_context = NULL };
ctx.mac = CMAC_CTX_new();
DevAssert(ctx.mac != NULL);
ctx.mac_context = CMAC_CTX_new();
DevAssert(ctx.mac_context != NULL);
//assert(16 == sizeof(ctx.key));
memcpy(ctx.key, key, 16); //sizeof(ctx.key));
CMAC_Init(ctx.mac, ctx.key, 16, EVP_aes_128_cbc(), NULL);
CMAC_Init(ctx.mac_context, ctx.key, 16, EVP_aes_128_cbc(), NULL);
return ctx;
}
......@@ -222,7 +144,7 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b
//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);
CMAC_Init(ctx->mac_context, NULL, 0, NULL, NULL);
size_t sz_iv = 0;
uint8_t* iv = NULL;
......@@ -236,19 +158,18 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b
AssertFatal(0 != 0, "Unknwon Initialization vector");
}
CMAC_Update(ctx->mac, iv, sz_iv);
CMAC_Update(ctx->mac_context, iv, sz_iv);
CMAC_Update(ctx->mac, msg.buf, msg.len);
CMAC_Update(ctx->mac_context, msg.buf, msg.len);
size_t len_res = 0;
CMAC_Final(ctx->mac, out, &len_res);
CMAC_Final(ctx->mac_context, out, &len_res);
DevAssert(len_res <= len_out);
}
void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx)
{
DevAssert(ctx != NULL);
CMAC_CTX_free(ctx->mac);
CMAC_CTX_free(ctx->mac_context);
}
#endif
......@@ -31,17 +31,13 @@
#include <stdlib.h>
typedef struct {
void* lib_ctx;
void* mac;
void *mac_implementation;
void *mac_context;
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
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
......@@ -127,15 +127,16 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
int rem_bits;
uint32_t mask = 0;
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(ctx, &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_init(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,9 +28,27 @@
#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.
* Defined as a struct to have compilation time type checking
* (the "context" field is never actually used).
*/
typedef struct {
void *context;
} 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;
......@@ -39,6 +57,17 @@ typedef struct {
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_init(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