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

This commit is contained in:
Jaroslava Fiedlerova
2024-04-30 11:22:30 +02:00
27 changed files with 338 additions and 285 deletions
+7 -13
View File
@@ -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;
+8 -8
View File
@@ -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;
+2
View File
@@ -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);
}
}
+2
View File
@@ -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;
+53 -132
View File
@@ -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])
{
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);
/* Create a context for the CMAC operation */
EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(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);
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);
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])
cbc_cmac_ctx_t init_aes_128_cbc_cmac(const 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);
EVP_MAC *mac_implementation = EVP_MAC_fetch(NULL, "CMAC", NULL);
DevAssert(mac_implementation != NULL);
cbc_cmac_ctx_t ctx = {.lib_ctx = library_context, .mac = mac };
/* Create a context for the CMAC operation */
EVP_MAC_CTX* mac_context = EVP_MAC_CTX_new(mac_implementation);
DevAssert(mac_context != NULL);
assert(16 == sizeof(ctx.key));
cbc_cmac_ctx_t ctx = { .mac_implementation = mac_implementation, .mac_context = mac_context };
memcpy(ctx.key, key, 16);
return ctx;
// 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(mac_context, key, 16, params);
DevAssert(rc != 0);
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_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;
}
@@ -218,11 +140,11 @@ 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);
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
+3 -7
View File
@@ -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
+22 -12
View File
@@ -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);
}
+3
View File
@@ -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
+14 -3
View File
@@ -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);
}
+3 -34
View File
@@ -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
+19 -5
View File
@@ -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);
}
+3
View File
@@ -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
+16 -3
View File
@@ -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);
}
+3
View File
@@ -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
+67
View File
@@ -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);
}
+32 -3
View File
@@ -28,17 +28,46 @@
#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 {
uint8_t *key;
uint32_t key_length;
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 {
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_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