Commit 986a1a80 authored by mir's avatar mir Committed by Robert Schmidt

Remove nettle library from OAI, support OpenSSL 3.0 and 1.1

Add byte_array_t structure under common/
parent 0afa3f31
......@@ -83,27 +83,6 @@ else()
include_directories(${OPENPGM_INCLUDE_DIRS})
endif()
pkg_search_module(NETTLE nettle)
if(NOT ${NETTLE_FOUND})
message( FATAL_ERROR "PACKAGE nettle not found: some targets will fail. Run build_oai -I again!")
else()
include_directories(${NETTLE_INCLUDE_DIRS})
endif()
message ("NETTLE VERSION_INSTALLED = ${NETTLE_VERSION}")
string(REGEX REPLACE "([0-9]+).*" "\\1" NETTLE_VERSION_MAJOR ${NETTLE_VERSION})
string(REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" NETTLE_VERSION_MINOR ${NETTLE_VERSION})
message ("NETTLE_VERSION_MAJOR = ${NETTLE_VERSION_MAJOR}")
message ("NETTLE_VERSION_MINOR = ${NETTLE_VERSION_MINOR}")
if ("${NETTLE_VERSION_MAJOR}" STREQUAL "" OR "${NETTLE_VERSION_MINOR}" STREQUAL "")
message( FATAL_ERROR "The nettle version not detected properly. Try to run build_oai -I again" )
endif()
add_definitions("-DNETTLE_VERSION_MAJOR=${NETTLE_VERSION_MAJOR}")
add_definitions("-DNETTLE_VERSION_MINOR=${NETTLE_VERSION_MINOR}")
pkg_search_module(XPM xpm)
if(NOT ${XPM_FOUND})
message("PACKAGE xpm not found: some targets will fail")
......@@ -885,12 +864,17 @@ set(SECU_OSA_SRC
${OPENAIR2_DIR}/UTIL/OSA/osa_snow3g.c
${OPENAIR2_DIR}/UTIL/OSA/osa_stream_eea.c
${OPENAIR2_DIR}/UTIL/OSA/osa_stream_eia.c
)
add_library(SECU_OSA ${SECU_OSA_SRC})
target_link_libraries(SECU_OSA ${NETTLE_LIBRARIES})
)
add_library(SECU_OSA ${SECU_OSA_SRC} $<TARGET_OBJECTS:ds> )
target_include_directories(SECU_OSA PRIVATE ${OPENAIR_DIR}/common/utils/ds/)
set(SECU_CN_SRC
${OPENAIR3_DIR}/SECU/secu_defs.c
${OPENAIR3_DIR}/SECU/kdf.c
${OPENAIR3_DIR}/SECU/aes_128_ctr.c
${OPENAIR3_DIR}/SECU/aes_128_cbc_cmac.c
${OPENAIR3_DIR}/SECU/sha_256_hmac.c
${OPENAIR3_DIR}/SECU/rijndael.c
${OPENAIR3_DIR}/SECU/snow3g.c
${OPENAIR3_DIR}/SECU/key_nas_deriver.c
......@@ -899,9 +883,9 @@ set(SECU_CN_SRC
${OPENAIR3_DIR}/SECU/nas_stream_eea2.c
${OPENAIR3_DIR}/SECU/nas_stream_eia2.c
)
add_library(SECU_CN ${SECU_CN_SRC})
target_link_libraries(SECU_CN ${NETTLE_LIBRARIES})
add_library(SECU_CN ${SECU_CN_SRC} $<TARGET_OBJECTS:ds>)
target_include_directories(SECU_CN PRIVATE ${OPENAIR_DIR}/common/utils/ds/)
# Physical Channel Procedures Scheduling
################################"
......@@ -2053,8 +2037,13 @@ add_library(LIB_NAS_SIMUE
${libnas_ue_esm_sap_OBJS}
${libnrnas_emm_msg_OBJS}
${libnrnas_ies_OBJS}
$<TARGET_OBJECTS:ds>
)
target_include_directories(LIB_NAS_SIMUE PRIVATE ${OPENAIR_DIR}/common/utils/ds/)
target_link_libraries(LIB_NAS_SIMUE PRIVATE lte_rrc)
set(NAS_SIM_LIB LIB_NAS_SIMUE)
target_link_libraries(LIB_NAS_SIMUE PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2074,7 +2063,9 @@ add_library(LIB_NAS_UE
${libnas_ue_emm_sap_OBJS}
${libnas_ue_esm_OBJS}
${libnas_ue_esm_sap_OBJS}
$<TARGET_OBJECTS:ds>
)
target_include_directories(LIB_NAS_UE PRIVATE ${OPENAIR_DIR}/common/utils/ds/)
target_link_libraries(LIB_NAS_UE PRIVATE lte_rrc)
set(NAS_UE_LIB LIB_NAS_UE)
target_link_libraries(LIB_NAS_UE PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2106,6 +2097,8 @@ add_library(LIB_5GNAS_GNB
${NAS_SRC}/NR_UE/ue_process_nas.c
${OPENAIR3_DIR}//UICC/usim_interface.c
)
target_include_directories(LIB_5GNAS_GNB PRIVATE ${OPENAIR_DIR}/common/utils/ds/)
target_link_libraries(LIB_5GNAS_GNB PRIVATE SECU_CN ${CRYPTO_LIBRARIES})
target_link_libraries(LIB_5GNAS_GNB PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2715,8 +2708,7 @@ endforeach(myExe)
foreach(myExe s1ap
secu_knas_encrypt_eia1
secu_kenb
aes128_ctr_encrypt
aes128_ctr_decrypt
aes128_ctr
secu_knas_encrypt_eea2
secu_knas secu_knas_encrypt_eea1
kdf
......@@ -2846,6 +2838,7 @@ include (common/utils/telnetsrv/telnetsrv_CMakeLists.txt)
include(${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt)
include (${OPENAIR_DIR}/common/utils/websrv/websrv_CMakeLists.txt)
add_subdirectory(common)
add_subdirectory(doc)
add_subdirectory(openair2)
add_subdirectory(openair3)
......@@ -86,49 +86,8 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.2 -std=gnu99 -Wall -Wstrict-prototype
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -DMALLOC_CHECK_=3")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ggdb -DMALLOC_CHECK_=3 -O2")
##This is to detect nettle version changes between Ubuntu 14.04/16.04
#set ( nettle_cmd "nettle-hash" )
#set ( nettle_arg "-V" )
#execute_process(COMMAND ${nettle_cmd} ${nettle_arg} RESULT_VARIABLE rv OUTPUT_VARIABLE ov ERROR_VARIABLE ev)
#
#string(REGEX MATCH "[+-]?[0-9]+([.][0-9]+)?" nv ${ov})
#
#message("NETTLE_VERSION = ${nv}")
#
## we need to remove decimal as floating point arithematic does not work properly with C preprocessor
#STRING(REGEX REPLACE "[.]" "" nv ${nv})
#
#if ("${nv}" STREQUAL "")
# message( FATAL_ERROR "The nettle version not detected properly. Try to run build_oai -I again" )
#endif()
#
#set (NETTLE_VERSION "${nv}")
#add_definitions("-DNETTLE_VERSION=${NETTLE_VERSION}")
include(FindPkgConfig)
pkg_search_module(NETTLE nettle)
if(NOT ${NETTLE_FOUND})
message( FATAL_ERROR "PACKAGE nettle not found: some targets will fail. Run build_oai -I again!")
else()
include_directories(${NETTLE_INCLUDE_DIRS})
endif()
message ("NETTLE VERSION_INSTALLED = ${NETTLE_VERSION}")
string(REGEX REPLACE "([0-9]+).*" "\\1" NETTLE_VERSION_MAJOR ${NETTLE_VERSION})
string(REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" NETTLE_VERSION_MINOR ${NETTLE_VERSION})
message ("NETTLE_VERSION_MAJOR = ${NETTLE_VERSION_MAJOR}")
message ("NETTLE_VERSION_MINOR = ${NETTLE_VERSION_MINOR}")
if ("${NETTLE_VERSION_MAJOR}" STREQUAL "" OR "${NETTLE_VERSION_MINOR}" STREQUAL "")
message( FATAL_ERROR "The nettle version not detected properly. Try to run build_oai -I again" )
endif()
add_definitions("-DNETTLE_VERSION_MAJOR=${NETTLE_VERSION_MAJOR}")
add_definitions("-DNETTLE_VERSION_MINOR=${NETTLE_VERSION_MINOR}")
pkg_search_module(OPENSSL openssl REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIRS})
......@@ -159,6 +118,9 @@ add_boolean_option(NAS_MME False "NAS_UE and NAS_MME are incompa
# SECU LIB
################################################################################
set(secu_cn_SRC
${OPENAIR3_DIR}/SECU/aes_128_ctr.c
${OPENAIR3_DIR}/SECU/aes_128_cbc_cmac.c
${OPENAIR3_DIR}/SECU/sha_256_hmac.c
${OPENAIR3_DIR}/SECU/kdf.c
${OPENAIR3_DIR}/SECU/rijndael.c
${OPENAIR3_DIR}/SECU/snow3g.c
......@@ -719,7 +681,6 @@ target_link_libraries (at_nas_ue
-Wl,-whole-archive
api_network api_user api_usim emm esm ies util secu_cn
-Wl,-no-whole-archive
${NETTLE_LIBRARIES}
${OPENSSL_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} m )
......
# Find the native Nettle includes, library, and flags
#
# NETTLE_INCLUDE_DIR - where to find nettle.h, etc.
# NETTLE_LIBRARIES - List of libraries when using Nettle.
# NETTLE_FOUND - True if Nettle found.
IF (NETTLE_INCLUDE_DIR)
# Already in cache, be silent
SET(NETTLE_FIND_QUIETLY TRUE)
ENDIF (NETTLE_INCLUDE_DIR)
FIND_PATH(NETTLE_INCLUDE_DIR nettle/nettle-meta.h)
SET(NETTLE_NAMES nettle)
FIND_LIBRARY(NETTLE_LIBRARY NAMES ${NETTLE_NAMES} )
# handle the QUIETLY and REQUIRED arguments and set NETTLE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(NETTLE DEFAULT_MSG NETTLE_LIBRARY NETTLE_INCLUDE_DIR)
IF(NETTLE_FOUND)
SET(NETTLE_LIBRARIES ${NETTLE_LIBRARY})
ELSE(NETTLE_FOUND)
SET(NETTLE_LIBRARIES )
ENDIF(NETTLE_FOUND)
MARK_AS_ADVANCED(NETTLE_LIBRARY NETTLE_INCLUDE_DIR)
......@@ -725,7 +725,6 @@ check_install_oai_software() {
$SUDO update-alternatives --set "$LAPACK_LIBNAME" "$LAPACK_TARGET"
$SUDO apt-get install -y nettle-dev nettle-bin
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then
if rpm -q epel-release > /dev/null; then
......@@ -771,7 +770,6 @@ check_install_oai_software() {
mariadb-devel \
lksctp-tools \
lksctp-tools-devel \
openssl-devel \
libtasn1 \
libtool \
libusb-devel \
......@@ -783,6 +781,7 @@ check_install_oai_software() {
openssh-clients \
openssh-server \
openssl \
openssl-devel \
patch \
psmisc \
python \
......@@ -793,7 +792,6 @@ check_install_oai_software() {
wget \
kernel-headers \
kernel-devel \
nettle-devel \
gnutls-devel \
libXpm-devel \
lapack \
......
add_subdirectory(utils)
add_subdirectory(ds)
add_library(ds OBJECT
byte_array.c
)
target_include_directories(ds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "byte_array.h"
#include "common/utils/assertions.h"
#include <string.h>
byte_array_t copy_byte_array(byte_array_t src)
{
byte_array_t dst = {0};
dst.buf = malloc(src.len);
DevAssert(dst.buf != NULL && "Memory exhausted");
memcpy(dst.buf, src.buf, src.len);
dst.len = src.len;
return dst;
}
void free_byte_array(byte_array_t ba)
{
free(ba.buf);
}
bool eq_byte_array(const byte_array_t* m0, const byte_array_t* m1)
{
if (m0 == m1)
return true;
if (m0 == NULL || m1 == NULL)
return false;
if (m0->len != m1->len)
return false;
const int rc = memcmp(m0->buf, m1->buf, m0->len);
if (rc != 0)
return false;
return true;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef BYTE_ARRAY_H_OAI
#define BYTE_ARRAY_H_OAI
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
size_t len;
uint8_t* buf;
} byte_array_t;
typedef struct {
uint8_t buf[32];
} byte_array_32_t;
byte_array_t copy_byte_array(byte_array_t src);
void free_byte_array(byte_array_t ba);
bool eq_byte_array(const byte_array_t* m0, const byte_array_t* m1);
#endif
......@@ -15,9 +15,6 @@ OPENAIR_DIR = /usr/local/oai/oai-develop/openairinterface5g
FreeDiameter prefix not found, install freeDiameter if EPC, HSS
3. building the compilation directives ...
running cmake ../../..
NETTLE VERSION_INSTALLED = 3.5.1
NETTLE_VERSION_MAJOR = 3
NETTLE_VERSION_MINOR = 5
cuda include /usr/include
cuda library
-- CMAKE_BUILD_TYPE is RelWithDebInfo
......@@ -61,9 +58,6 @@ Call Stack (most recent call first):
FreeDiameter prefix not found, install freeDiameter if EPC, HSS
3. building the compilation directives ...
running cmake ../../..
NETTLE VERSION_INSTALLED = 3.5.1
NETTLE_VERSION_MAJOR = 3
NETTLE_VERSION_MINOR = 5
cuda include /usr/include
cuda library
-- CMAKE_BUILD_TYPE is RelWithDebInfo
......@@ -209,4 +203,4 @@ The interface should be intuitive enough, keeping in mind the following restrict
Some front-end objects, which usage are less intuitive provide a tooltip to help interface usage.
[oai web serverinterface home](websrv.md)
\ No newline at end of file
[oai web serverinterface home](websrv.md)
......@@ -39,7 +39,6 @@ ENV TZ=Europe/Paris
RUN yum update -y && \
yum install -y --enablerepo="ubi-8-codeready-builder" \
lksctp-tools \
nettle \
tzdata \
procps-ng \
atlas \
......
......@@ -44,7 +44,6 @@ RUN apt-get update && \
tzdata \
procps \
libsctp1 \
libnettle6 \
libblas3 \
libatlas3-base \
libconfig9 \
......
......@@ -52,7 +52,6 @@ RUN yum repolist --disablerepo=* && \
libX11 \
atlas \
lksctp-tools \
nettle \
tzdata \
net-tools \
iputils \
......
......@@ -44,7 +44,6 @@ RUN yum repolist --disablerepo=* && \
libX11 \
atlas \
lksctp-tools \
nettle \
tzdata \
gdb \
python3 \
......
......@@ -44,7 +44,6 @@ RUN apt-get update && \
procps \
libsctp1 \
tzdata \
libnettle6 \
libblas3 \
libatlas3-base \
libconfig9 \
......
......@@ -41,7 +41,6 @@ RUN yum update -y && \
yum install -y --enablerepo="ubi-8-codeready-builder" \
lksctp-tools \
procps-ng \
nettle \
tzdata \
atlas \
gdb \
......
......@@ -45,7 +45,6 @@ RUN apt-get update && \
tzdata \
procps \
libsctp1 \
libnettle6 \
liblapacke \
libatlas3-base \
libconfig9 \
......
......@@ -41,7 +41,6 @@ RUN yum update -y && \
lksctp-tools \
procps-ng \
tzdata \
nettle \
net-tools \
iputils \
iproute \
......
......@@ -44,7 +44,6 @@ RUN apt-get update && \
libsctp1 \
procps \
tzdata \
libnettle6 \
liblapacke \
libatlas3-base \
libconfig9 \
......
......@@ -46,7 +46,6 @@ FROM registry.access.redhat.com/ubi8/ubi:latest as oai-physim
RUN yum update -y && \
yum install -y --enablerepo="ubi-8-codeready-builder" \
lksctp-tools \
nettle \
tzdata \
atlas \
hostname \
......
......@@ -21,62 +21,61 @@
#include "nr_pdcp_integrity_nia2.h"
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <openssl/cmac.h>
void *nr_pdcp_integrity_nia2_init(unsigned char *integrity_key)
{
CMAC_CTX *ctx;
ctx = CMAC_CTX_new();
if (ctx == NULL) abort();
#include "common/utils/assertions.h"
#include "openair3/SECU/aes_128.h"
#include "openair3/SECU/aes_128_cbc_cmac.h"
CMAC_Init(ctx, integrity_key, 16, EVP_aes_128_cbc(), NULL);
void *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));
DevAssert(ctx != NULL && "Memory exhausted");
*ctx = init_aes_128_cbc_cmac(integrity_key);
return ctx;
}
static void compute_t(unsigned char *t, uint32_t count, int bearer,
int direction)
void nr_pdcp_integrity_nia2_integrity(void *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction)
{
t[0] = (count >> 24) & 255;
t[1] = (count >> 16) & 255;
t[2] = (count >> 8) & 255;
t[3] = (count ) & 255;
t[4] = ((bearer-1) << 3) | (direction << 2);
memset(&t[5], 0, 8-5);
}
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);
void nr_pdcp_integrity_nia2_integrity(void *integrity_context,
unsigned char *out,
unsigned char *buffer, int length,
int bearer, int count, int direction)
{
CMAC_CTX *ctx = integrity_context;
unsigned char t[8];
unsigned char mac[16];
size_t maclen;
cbc_cmac_ctx_t* ctx = (cbc_cmac_ctx_t*)integrity_context;
/* see 33.401 B.2.3 for the input to 128-EIA2
* (which is identical to 128-NIA2, see 33.501 D.3.1.3) */
compute_t(t, count, bearer, direction);
aes_128_t k_iv = {0};
memcpy(&k_iv.key, ctx->key, sizeof(k_iv.key));
k_iv.type = AES_INITIALIZATION_VECTOR_8;
k_iv.iv8.d.bearer = bearer -1;
k_iv.iv8.d.direction = direction;
k_iv.iv8.d.count = htonl(count);
CMAC_Init(ctx, NULL, 0, NULL, NULL);
CMAC_Update(ctx, t, 8);
CMAC_Update(ctx, buffer, length);
CMAC_Final(ctx, mac, &maclen);
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);
/* 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)
*/
memcpy(out, mac, 4);
// 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)
{
CMAC_CTX *ctx = integrity_context;
CMAC_CTX_free(ctx);
free( ( cbc_cmac_ctx_t*) integrity_context);
}
......@@ -22,7 +22,9 @@
#ifndef _NR_PDCP_INTEGRITY_NIA2_H_
#define _NR_PDCP_INTEGRITY_NIA2_H_
void *nr_pdcp_integrity_nia2_init(unsigned char *integrity_key);
#include <stdint.h>
void *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]);
void nr_pdcp_integrity_nia2_integrity(void *integrity_context,
unsigned char *out,
......
......@@ -19,55 +19,50 @@
* contact@openairinterface.org
*/
#include "openair3/SECU/aes_128_ctr.h"
#include "common/utils/assertions.h"
#include "nr_pdcp_security_nea2.h"
#include <arpa/inet.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
#ifndef NETTLE_VERSION_MAJOR
/* hack: include bignum.h, not version.h because version.h does not exist
* in old versions and bignum.h includes version.h (as of today).
* May completely fail to work... maybe we should skip support of old
* versions of nettle.
*/
#include <nettle/bignum.h>
#endif
void *nr_pdcp_security_nea2_init(unsigned char *ciphering_key)
{
void *ctx = calloc(1, nettle_aes128.context_size);
if (ctx == NULL) exit(1);
#if !defined(NETTLE_VERSION_MAJOR) || NETTLE_VERSION_MAJOR < 3
nettle_aes128.set_encrypt_key(ctx, 16, ciphering_key);
#else
nettle_aes128.set_encrypt_key(ctx, ciphering_key);
#endif
return ctx;
// 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;
}
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(void *security_context, unsigned char *buffer, int length, int bearer, int count, int direction)
{
unsigned char t[16] = {0};
DevAssert(security_context != NULL);
DevAssert(buffer != NULL);
DevAssert(length > 0);
DevAssert(bearer > -1 && bearer < 32);
DevAssert(direction > -1 && direction < 2);
DevAssert(count > -1);
aes_128_t p = {0};
const uint8_t *ciphering_key = (uint8_t const *)security_context;
memcpy(p.key, ciphering_key, 16);
p.type = AES_INITIALIZATION_VECTOR_16;
p.iv16.d.count = ntohl(count);
p.iv16.d.bearer = bearer;
p.iv16.d.direction = direction;
uint8_t out[length];
memset(out, 0, length);
t[0] = (count >> 24) & 255;
t[1] = (count >> 16) & 255;
t[2] = (count >> 8) & 255;
t[3] = (count ) & 255;
t[4] = ((bearer-1) << 3) | (direction << 2);
byte_array_t msg = {.buf = buffer, .len = length};;
aes_128_ctr(&p, msg, length, out);
nettle_ctr_crypt(security_context, nettle_aes128.encrypt,
nettle_aes128.block_size, t,
length, buffer, buffer);
memcpy(buffer, out, length);
}
void nr_pdcp_security_nea2_free_security(void *security_context)
{
free(security_context);
(void)security_context;
}
Algorithms and Data Structures in C for common usage
add_subdirectory(ALG_DS)
OAISIM Security Algorithms v0.1
Dependencies:
- nettle >= 2.5
- openssl >= 1.0.1
Compilation:
......
......@@ -22,7 +22,7 @@
/*!
* \file secu_defs.h
* \brief Openair security algorithms functions implementing 3GPP TS 33.401
* \note HMAC computations are done by nettle/openssl library
* \note HMAC computations are done by openssl library
* \author Sebastien ROUX
* \date 2013
* \version 0.1
......
......@@ -19,31 +19,15 @@
* contact@openairinterface.org
*/
#include <stdint.h>
#include "../../../openair3/SECU/kdf.h"
#include <nettle/hmac.h>
#include <stdint.h>
#include <string.h>
#include "osa_defs.h"
#include "osa_internal.h"
#include "common/utils/LOG/log.h"
static inline
void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key,
const uint32_t key_length, uint8_t **out, uint32_t out_length)
{
struct hmac_sha256_ctx ctx;
uint8_t *buffer;
buffer = malloc(sizeof(uint8_t) * out_length);
hmac_sha256_set_key(&ctx, key_length, key);
hmac_sha256_update(&ctx, s_length, s);
hmac_sha256_digest(&ctx, out_length, buffer);
*out = buffer;
}
/*!
* @brief Derive the keys from key and perform truncate on the generated key to
* reduce his size to 128 bits. Definition of the derivation function can
......@@ -58,10 +42,9 @@ void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key,
* @param[out] out Pointer to reference where output of KDF will be stored.
* NOTE: knas is dynamically allocated by the KDF function
*/
int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
const uint8_t key[32], uint8_t **out)
int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t key[32], uint8_t **out)
{
uint8_t string[7];
uint8_t string[7] = {0};
/* FC */
string[0] = FC_ALG_KEY_DER;
......@@ -84,7 +67,7 @@ int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
{
int i;
char payload[6 * sizeof(string) + 1];
int index = 0;
int index = 0;
for (i = 0; i < sizeof(string); i++)
index += sprintf(&payload[index], "0x%02x ", string[i]);
......@@ -93,13 +76,17 @@ int derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
}
#endif
kdf(string, 7, key, 32, out, 32);
byte_array_t data = {.buf = string, .len = 7};
if (*out == NULL) {
*out = malloc(sizeof(uint8_t) * 32);
DevAssert(*out != NULL && "Memory exhausted");
}
kdf(key, data, 32, *out);
return 0;
}
int nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
const uint8_t key[32], uint8_t **out)
int nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t key[32], uint8_t **out)
{
uint8_t string[7];
......@@ -120,17 +107,23 @@ int nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id,
string[5] = 0x00;
string[6] = 0x01;
kdf(string, 7, key, 32, out, 32);
byte_array_t data = {.buf = string, .len = 7};
if (*out == NULL) {
*out = malloc(sizeof(uint8_t) * 32);
DevAssert(*out != NULL && "Memory exhausted");
}
kdf(key, data, 32, *out);
// in NR, we use the last 16 bytes, ignoring the first 16 ones
memcpy(*out, *out+16, 16);
memcpy(*out, *out + 16, 16);
return 0;
}
int nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star)
{
uint8_t *out;
uint8_t s[10];
uint8_t s[10] = {0};
/* FC */
s[0] = NR_FC_ALG_KEY_NG_RAN_STAR_DER;
......@@ -152,18 +145,17 @@ int nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t
s[8] = 0x00;
s[9] = 0x03;
kdf(s, 10, key, 32, &out, 32);
memcpy(key_ng_ran_star, out, 32);
free(out);
byte_array_t data = {.buf = s, .len = 10};
const uint32_t len_key = 32;
kdf(key, data, len_key, key_ng_ran_star);
return 0;
}
int derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB)
{
uint8_t *out;
uint8_t s[5];
uint8_t s[5] = {0};
/* FC is 0x1c (see 3gpp 33.401 annex A.15) */
s[0] = 0x1c;
......@@ -176,10 +168,8 @@ int derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB)
s[3] = 0x00;
s[4] = 0x02;
kdf(s, 5, keNB, 32, &out, 32);
memcpy(skgNB, out, 32);
free(out);
byte_array_t data = {.buf = s, .len = 5};
kdf(keNB, data, 32, skgNB);
return 0;
}
......@@ -19,16 +19,15 @@
* contact@openairinterface.org
*/
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
#include "common/utils/LOG/log.h"
#include "byte_array.h"
#include "openair3//SECU//aes_128_ctr.h"
#include "assertions.h"
#include "osa_defs.h"
......@@ -44,10 +43,13 @@ int stream_encrypt_eea0(stream_cipher_t *stream_cipher, uint8_t **out)
DevAssert(stream_cipher != NULL);
DevAssert(out != NULL);
LOG_D(OSA, "Entering stream_encrypt_eea0, bits length %u, bearer %u, "
"count %u, direction %s\n", stream_cipher->blength,
stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ?
"Downlink" : "Uplink");
LOG_D(OSA,
"Entering stream_encrypt_eea0, bits length %u, bearer %u, "
"count %u, direction %s\n",
stream_cipher->blength,
stream_cipher->bearer,
stream_cipher->count,
stream_cipher->direction == SECU_DIRECTION_DOWNLINK ? "Downlink" : "Uplink");
byte_length = (stream_cipher->blength + 7) >> 3;
......@@ -59,7 +61,7 @@ int stream_encrypt_eea0(stream_cipher_t *stream_cipher, uint8_t **out)
data = *out;
}
memcpy (data, stream_cipher->message, byte_length);
memcpy(data, stream_cipher->message, byte_length);
return 0;
}
......@@ -67,32 +69,32 @@ int stream_encrypt_eea0(stream_cipher_t *stream_cipher, uint8_t **out)
int stream_encrypt_eea1(stream_cipher_t *stream_cipher, uint8_t **out)
{
osa_snow_3g_context_t snow_3g_context;
int n ;
int i = 0;
uint32_t zero_bit = 0;
int n;
int i = 0;
uint32_t zero_bit = 0;
uint32_t *KS;
uint32_t K[4],IV[4];
uint32_t K[4], IV[4];
DevAssert(stream_cipher != NULL);
DevAssert(stream_cipher->key != NULL);
DevAssert(stream_cipher->key_length == 16);
DevAssert(out != NULL);
n = ( stream_cipher->blength + 31 ) / 32;
n = (stream_cipher->blength + 31) / 32;
zero_bit = stream_cipher->blength & 0x7;
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
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 + 3, stream_cipher->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*/
K[3] = hton_int32(K[3]);
K[2] = hton_int32(K[2]);
K[1] = hton_int32(K[1]);
......@@ -106,26 +108,25 @@ int stream_encrypt_eea1(stream_cipher_t *stream_cipher, uint8_t **out)
/* Run SNOW 3G algorithm to generate sequence of key stream bits KS*/
osa_snow3g_initialize(K, IV, &snow_3g_context);
KS = (uint32_t *)malloc(4*n);
osa_snow3g_generate_key_stream(n,(uint32_t*)KS, &snow_3g_context);
KS = (uint32_t *)malloc(4 * n);
osa_snow3g_generate_key_stream(n, (uint32_t *)KS, &snow_3g_context);
if (zero_bit > 0) {
KS[n - 1] = KS[n - 1] & (uint32_t)(0xFFFFFFFF << (8 - zero_bit));
}
for (i=0; i<n; i++) {
for (i = 0; i < n; i++) {
KS[i] = hton_int32(KS[i]);
}
/* Exclusive-OR the input data with keystream to generate the output bit
stream */
for (i=0; i<n*4; i++) {
stream_cipher->message[i] ^= *(((uint8_t*)KS)+i);
for (i = 0; i < n * 4; i++) {
stream_cipher->message[i] ^= *(((uint8_t *)KS) + i);
}
if (zero_bit > 0) {
int ceil_index = (stream_cipher->blength+7) >> 3;
int ceil_index = (stream_cipher->blength + 7) >> 3;
stream_cipher->message[ceil_index - 1] = stream_cipher->message[ceil_index - 1] & (uint8_t)(0xFF << (8 - zero_bit));
}
......@@ -136,91 +137,32 @@ int stream_encrypt_eea1(stream_cipher_t *stream_cipher, uint8_t **out)
int stream_encrypt_eea2(stream_cipher_t *stream_cipher, uint8_t **out)
{
uint8_t m[16];
uint32_t local_count;
void *ctx;
uint8_t *data = NULL;
uint32_t zero_bit = 0;
uint32_t byte_length;
DevAssert(stream_cipher != NULL);
DevAssert(out != NULL);
LOG_D(OSA, "Entering stream_encrypt_eea2, bits length %u, bearer %u, "
"count %u, direction %s\n", stream_cipher->blength,
stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ?
"Downlink" : "Uplink");
zero_bit = stream_cipher->blength & 0x7;
byte_length = stream_cipher->blength >> 3;
if (zero_bit > 0)
byte_length += 1;
ctx = malloc(nettle_aes128.context_size);
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);
if (*out == NULL) {
/* User provided output buffer */
data = malloc(byte_length);
*out = data;
} else {
data = *out;
}
local_count = hton_int32(stream_cipher->count);
memset(m, 0, sizeof(m));
memcpy(&m[0], &local_count, 4);
m[4] = ((stream_cipher->bearer & 0x1F) << 3) |
((stream_cipher->direction & 0x01) << 2);
/* Other bits are 0 */
#if defined(SECU_DEBUG)
{
int i;
char payload[6 * byte_length + 1];
int index = 0;
for (i = 0; i < byte_length; i++)
index += sprintf(&payload[index], "0x%02x ", stream_cipher->message[i]);
LOG_D(OSA, "Original message: %s\n", payload);
}
#endif
#if NETTLE_VERSION_MAJOR < 3
nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length,
stream_cipher->key);
#else
nettle_aes128.set_encrypt_key(ctx,
stream_cipher->key);
#endif
nettle_ctr_crypt(ctx, nettle_aes128.encrypt,
nettle_aes128.block_size, m,
byte_length, data, stream_cipher->message);
if (zero_bit > 0)
data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit));
free(ctx);
#if defined(SECU_DEBUG)
{
int i;
char payload[6 * byte_length + 1];
int index = 0;
for (i = 0; i < byte_length; i++)
index += sprintf(&payload[index], "0x%02x ", data[i]);
LOG_D(OSA, "Encrypted message: %s\n", payload);
*out = calloc(1, (stream_cipher->blength >> 3) + 1);
DevAssert(*out != NULL && "Memory exhausted");
}
#endif
aes_128_t p = {0};
memcpy(p.key, stream_cipher->key, stream_cipher->key_length);
p.type = AES_INITIALIZATION_VECTOR_16;
p.iv16.d.count = htonl(stream_cipher->count);
p.iv16.d.bearer = stream_cipher->bearer;
p.iv16.d.direction = stream_cipher->direction;
DevAssert((stream_cipher->blength & 0x07) == 0 && "Cipher length must be multiple of one octet");
const uint32_t byte_lenght = stream_cipher->blength >> 3;
// Precondition: out must have enough space, at least as much as the input
const size_t len_out = byte_lenght;
byte_array_t msg = {.buf = stream_cipher->message, .len =byte_lenght};
aes_128_ctr(&p, msg, len_out, *out);
return 0;
}
......
This diff is collapsed.
......@@ -544,7 +544,6 @@ Before compiling the core EPC, some packages should be installed on the platform
\item flex and bison
\item openssl-dev
\item asn1c (see section \ref{sec:asn1c})
\item libnettle (see section \ref{sec:libnettle})
\item freediameter (see section \ref{sec:freediameter}) and gnutls 3.1.0
(see section \ref{sec:gnutls})
\end{itemize}
......@@ -562,28 +561,6 @@ openssl-dev -y
\subsection{ASN1c}
\label{sec:asn1c}
\subsection{libnettle}
\label{sec:libnettle}
The nettle library is used by freediameter for certificate encryption and by core
EPC for key derivation.
\begin{lstlisting}
wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz
gunzip nettle-2.5.tar.gz
tar -xvf nettle-2.5.tar
cd nettle-2.5/
./configure --disable-openssl --enable-shared
make
make check
sudo make install
\end{lstlisting}
The commands provided above will download the required packages sources, configure
and install them on the system.
Note that any packages which is not in the Ubuntu repository is installed by default
in /usr/local instead of /usr.
This behaviour can be overriden at configuration time by providing --prefix=/usr to
the configuration script (configure).
\subsection{gnutls}
\label{sec:gnutls}
......
......@@ -23,6 +23,7 @@
#include <openair3/NAS/COMMON/NR_NAS_defs.h>
#include <openair3/SECU/secu_defs.h>
#include <openair3/SECU/kdf.h>
void servingNetworkName(uint8_t *msg, char * imsiStr, int nmc_size) {
//SNN-network-identifier in TS 24.501
......@@ -59,8 +60,12 @@ int resToresStar(uint8_t *msg, uicc_t* uicc) {
uint8_t ckik[sizeof(uicc->ck) +sizeof(uicc->ik)];
memcpy(ckik, uicc->ck, sizeof(uicc->ck));
memcpy(ckik+sizeof(uicc->ck),uicc->ik, sizeof(uicc->ik));
uint8_t out[32];
kdf(S, ptr-S, ckik, 32, out, sizeof(out));
uint8_t out[32] = {0};
assert(ptr-S == 32);
//kdf(S, ptr-S, ckik, 32, out, sizeof(out));
byte_array_t data = {.buf = ckik, .len = 32};
kdf(S, data, 32, out);
memcpy(msg, out+16, 16);
return 16;
}
......@@ -37,6 +37,7 @@
#include "nr_nas_msg_sim.h"
#include "aka_functions.h"
#include "secu_defs.h"
#include "kdf.h"
#include "PduSessionEstablishRequest.h"
#include "PduSessionEstablishmentAccept.h"
#include "intertask_interface.h"
......@@ -188,18 +189,20 @@ void transferRES(uint8_t ck[16], uint8_t ik[16], uint8_t *input, uint8_t rand[16
oldS[33] = 0x08;
uint8_t key[32];
uint8_t key[32] = {0};
memcpy(&key[0], ck, 16);
memcpy(&key[16], ik, 16); //KEY
uint8_t out[32];
kdf(key, 32, S, 31 + netNamesize, out, 32);
for (int i = 0; i < 16; i++)
output[i] = out[16 + i];
uint8_t out[32] = {0};
byte_array_t data = {.buf = S, .len = 31 + netNamesize};
kdf(key, data, 32, out);
memcpy(output, out + 16, 16);
}
void derive_kausf(uint8_t ck[16], uint8_t ik[16], uint8_t sqn[6], uint8_t kausf[32], uicc_t *uicc) {
uint8_t S[100]={0};
uint8_t key[32];
uint8_t key[32] = {0};
memcpy(&key[0], ck, 16);
memcpy(&key[16], ik, 16); //KEY
......@@ -213,7 +216,9 @@ void derive_kausf(uint8_t ck[16], uint8_t ik[16], uint8_t sqn[6], uint8_t kausf[
}
S[9 + netNamesize] = 0x00;
S[10 + netNamesize] = 0x06;
kdf(key, 32, S, 11 + netNamesize, kausf, 32);
byte_array_t data = {.buf = S, .len = 11 + netNamesize};
kdf(key, data, 32, kausf);
}
void derive_kseaf(uint8_t kausf[32], uint8_t kseaf[32], uicc_t *uicc) {
......@@ -223,12 +228,14 @@ void derive_kseaf(uint8_t kausf[32], uint8_t kseaf[32], uicc_t *uicc) {
int netNamesize = strlen((char*)S+1);
S[1 + netNamesize] = (uint8_t)((netNamesize & 0xff00) >> 8);
S[2 + netNamesize] = (uint8_t)(netNamesize & 0x00ff);
kdf(kausf, 32, S, 3 + netNamesize, kseaf, 32);
byte_array_t data = {.buf = S , .len = 3 + netNamesize};
kdf(kausf, data, 32, kseaf);
}
void derive_kamf(uint8_t *kseaf, uint8_t *kamf, uint16_t abba, uicc_t* uicc) {
int imsiLen = strlen(uicc->imsiStr);
uint8_t S[100];
uint8_t S[100] = {0};
S[0] = 0x6D; //FC = 0x6D
memcpy(&S[1], uicc->imsiStr, imsiLen );
S[1 + imsiLen] = (uint8_t)((imsiLen & 0xff00) >> 8);
......@@ -237,12 +244,14 @@ void derive_kamf(uint8_t *kseaf, uint8_t *kamf, uint16_t abba, uicc_t* uicc) {
S[4 + imsiLen] = (abba & 0xff00) >> 8;
S[5 + imsiLen] = 0x00;
S[6 + imsiLen] = 0x02;
kdf(kseaf, 32, S, 7 + imsiLen, kamf, 32);
byte_array_t data = {.buf = S, .len = 7 + imsiLen};
kdf(kseaf, data, 32, kamf);
}
//------------------------------------------------------------------------------
void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t kamf[32], uint8_t *knas_int) {
uint8_t S[20];
uint8_t S[20] = {0};
uint8_t out[32] = { 0 };
S[0] = 0x69; //FC
S[1] = (uint8_t)(nas_alg_type & 0xFF);
......@@ -251,19 +260,20 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t
S[4] = nas_alg_id;
S[5] = 0x00;
S[6] = 0x01;
kdf(kamf, 32, S, 7, out, 32);
for (int i = 0; i < 16; i++)
knas_int[i] = out[16 + i];
byte_array_t data = {.buf = S, .len = 7};
kdf(kamf, data, 32, out);
memcpy(knas_int, out+16, 16);
}
void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){
/* Compute the KDF input parameter
* S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01
*/
uint8_t input[32];
uint8_t input[32] = {0};
// uint16_t length = 4;
// int offset = 0;
uint8_t out[32] = { 0 };
LOG_TRACE(INFO, "%s with count= %d", __FUNCTION__, count);
memset(input, 0, 32);
......@@ -282,9 +292,9 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){
input[8] = 0;
input[9] = 1;
kdf(kamf, 32, input, 10, out, 32);
for (int i = 0; i < 32; i++)
kgnb[i] = out[i];
byte_array_t data = {.buf = input, .len = 10};
kdf(kamf, data, 32, kgnb);
printf("kgnb : ");
for(int pp=0;pp<32;pp++)
printf("%02x ",kgnb[pp]);
......
......@@ -67,6 +67,7 @@ Description Defines the authentication EMM procedure executed by the
#include "usim_api.h"
#include "secu_defs.h"
#include "kdf.h"
#include "Authentication.h"
#include "executables/lte-softmodem.h"
......@@ -982,14 +983,10 @@ static int _authentication_kasme(const OctetString *autn,
input_s[4],input_s[5],input_s[6],input_s[7],
input_s[8],input_s[9],input_s[10],input_s[11],
input_s[12],input_s[13]);
/* TODO !!! Compute the Kasme key */
// todo_hmac_256(key, input_s, kasme->value);
kdf(key,
ck->length + ik->length , /*key_length*/
input_s,
offset,
kasme->value,
kasme->length);
assert(ck->length + ik->length == 32);
byte_array_t data = {.len = offset, .buf = input_s};
kdf(key, data, kasme->length, kasme->value);
LOG_TRACE(INFO,"EMM-PROC KASME (l=%d)%s",
kasme->length,
......
......@@ -63,6 +63,7 @@ Description Defines the security mode control EMM procedure executed by the
# include "assertions.h"
#include "secu_defs.h"
#include "kdf.h"
#include "SecurityModeControl.h"
#if defined(NAS_BUILT_IN_UE)
......@@ -484,7 +485,9 @@ static int _security_kenb(const OctetString *kasme, OctetString *kenb,
input[5] = 0;
input[6] = 4;
kdf(kasme->value, 32, input, 7, kenb->value, 32);
byte_array_t data = {.len = 7, .buf = input};
kdf(kasme->value, data, 32, kenb->value);
kenb->length = 32;
return (RETURNok);
}
......@@ -536,8 +539,12 @@ static int _security_kdf(const OctetString *kasme, OctetString *key,
input[5] = 0x00;
input[6] = 0x01;
assert(kasme->length == 32);
byte_array_t data = {.len = 7, .buf=input};
/* Compute the derived key */
kdf(kasme->value, kasme->length, input, 7, output, 32);
kdf(kasme->value, data, 32, output);
memcpy(key->value, &output[31 - key->length + 1], key->length);
return (RETURNok);
}
......
......@@ -19,66 +19,70 @@
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdlib.h>
#ifndef AES_128_OAI_H
#define AES_128_OAI_H
#include <endian.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include "test_util.h"
// see 33.401 B.2.3 for the input to 128-EIA2
// (which is identical to 128-NIA2, see 33.501 D.3.1.3)
#include "secu_defs.h"
typedef struct {
uint32_t count;
uint8_t padding: 2;
uint8_t direction: 1;
uint8_t bearer: 5;
uint8_t pad_8;
uint16_t pad_16;
uint64_t pad_64;
} data_iv16_t;
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
typedef struct{
union{
data_iv16_t d;
uint8_t iv[16];
};
} iv16_t;
static void test_cipher_ctr(const struct nettle_cipher *cipher, const uint8_t *key,
unsigned key_length, const uint8_t *cleartext, unsigned length,
const uint8_t *ciphertext, const uint8_t *ictr)
{
void *ctx = malloc(cipher->context_size);
uint8_t *data = malloc(length);
uint8_t *ctr = malloc(cipher->block_size);
typedef struct {
uint32_t count;
uint8_t padding: 2;
uint8_t direction: 1;
uint8_t bearer: 5;
uint8_t pad_8;
uint16_t pad_16;
} data_iv8_t;
#if NETTLE_VERSION_MAJOR < 3
cipher->set_encrypt_key(ctx, key_length, key);
#else
cipher->set_encrypt_key(ctx, key);
#endif
typedef struct{
union{
data_iv8_t d;
uint8_t iv[8];
};
} iv8_t;
memcpy(ctr, ictr, cipher->block_size);
typedef enum{
AES_INITIALIZATION_VECTOR_8,
AES_INITIALIZATION_VECTOR_16,
ctr_crypt(ctx, cipher->encrypt,
cipher->block_size, ctr,
length, data, cleartext);
AES_INITIALIZATION_VECTOR_END,
} iv_e;
if (compare_buffer(data, length, ciphertext, length) != 0) {
fail("Fail: test_cipher_ctr");
}
#if __BYTE_ORDER == __BIG_ENDIAN
static_assert(0 != 0, "The struct iv_t needs little endianness");
#endif
// static_assert((16 == sizeof(iv_t)) , "Initialization Vector needs to have an AES_BLOCK_SIZE" );
free(ctx);
free(data);
free(ctr);
}
typedef struct {
uint8_t key[16];
iv_e type;
union{
iv8_t iv8;
iv16_t iv16;
};
} aes_128_t;
#endif
void doit (void)
{
/* From NIST spec 800-38a on AES modes,
*
* http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf
*
* F.5 CTR Example Vectors
*/
/* F.5.1 CTR-AES128.Encrypt */
test_cipher_ctr(&nettle_aes128,
HL("2b7e151628aed2a6abf7158809cf4f3c"),
HL("6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710"),
H("874d6191b620e3261bef6864990db6ce"
"9806f66b7970fdff8617187bb9fffdff"
"5ae4df3edbd5d35e5b4f09020db03eab"
"1e031dda2fbe03d1792170a0f3009cee"),
H("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "aes_128_cbc_cmac.h"
#include "common/utils/assertions.h"
#include <openssl/cmac.h>
#if OPENSSL_VERSION_MAJOR >= 3
// 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])
{
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;
}
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);
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);
}
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);
}
#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 {
DevAssert(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])
{
DevAssert(key != NULL);
cbc_cmac_ctx_t ctx = {.lib_ctx = NULL, .mac = NULL };
ctx.mac = CMAC_CTX_new();
DevAssert(ctx.mac != 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);
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);
//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
//reading data anew.
CMAC_Init(ctx->mac, NULL, 0, NULL, 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 {
DevAssert(0!=0 && "Unknwon Initialization vector");
}
CMAC_Update(ctx->mac, iv, sz_iv);
CMAC_Update(ctx->mac, msg.buf, msg.len);
size_t len_res = 0;
CMAC_Final(ctx->mac, 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);
}
#endif
......@@ -19,67 +19,30 @@
* contact@openairinterface.org
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "test_util.h"
#ifndef AES_128_CBC_CMAC_H
#define AES_128_CBC_CMAC_H
#include "secu_defs.h"
#include "aes_128.h"
#include "common/utils/ds/byte_array.h"
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
static
void test_uncipher_ctr(const struct nettle_cipher *cipher, const uint8_t *key,
unsigned key_length, const uint8_t *cipheredtext,
unsigned length, const uint8_t *cleartext, const uint8_t *ictr)
{
void *ctx = malloc(cipher->context_size);
uint8_t *data = malloc(length);
uint8_t *ctr = malloc(cipher->block_size);
#include <stdint.h>
#include <stdlib.h>
#if NETTLE_VERSION_MAJOR < 3
cipher->set_encrypt_key(ctx, key_length, key);
#else
cipher->set_encrypt_key(ctx, key);
#endif
typedef struct {
void* lib_ctx;
void* mac;
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]);
memcpy(ctr, ictr, cipher->block_size);
cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16]);
ctr_crypt(ctx, cipher->encrypt,
cipher->block_size, ctr,
length, data, cipheredtext);
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]);
if (compare_buffer(data, length, cleartext, length) != 0) {
fail("Fail: test_uncipher_ctr\n");
}
void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx);
free(ctx);
free(data);
free(ctr);
}
#endif
void doit (void)
{
/* From NIST spec 800-38a on AES modes,
*
* http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf
*
* F.5 CTR Example Vectors
*/
/* F.5.1 CTR-AES128.Encrypt */
test_uncipher_ctr(&nettle_aes128,
HL("2b7e151628aed2a6abf7158809cf4f3c"),
HL("6bc1bee22e409f96e93d7e117393172a"
"ae2d8a571e03ac9c9eb76fac45af8e51"
"30c81c46a35ce411e5fbc1191a0a52ef"
"f69f2445df4f9b17ad2b417be66c3710"),
H("874d6191b620e3261bef6864990db6ce"
"9806f66b7970fdff8617187bb9fffdff"
"5ae4df3edbd5d35e5b4f09020db03eab"
"1e031dda2fbe03d1792170a0f3009cee"),
H("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
// TS 133 401 pag. 88
#include "aes_128_ctr.h"
#include "common/utils/assertions.h"
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/evp.h>
void aes_128_ctr(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out])
{
DevAssert(k_iv != NULL);
DevAssert(sizeof(iv16_t) == AES_BLOCK_SIZE);
DevAssert(k_iv->type == AES_INITIALIZATION_VECTOR_16);
// Create and initialise the context
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
DevAssert(ctx != NULL);
// Set IV length if default 12 bytes (96 bits) is not appropriate
// int rc = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CTR_SET_IVLEN, 16, NULL))
// Initialise the encryption operation.
int rc = EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, k_iv->key, k_iv->iv16.iv);
DevAssert(rc == 1);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == AES_BLOCK_SIZE);
int len_ev = 0;
rc = EVP_EncryptUpdate(ctx, out, &len_ev, msg.buf, msg.len);
DevAssert(!(len_ev > len_out) && "Buffer overflow");
// Finalise the encryption. Normally ciphertext bytes may be written at
// this stage, but this does not occur in GCM mode
rc = EVP_EncryptFinal_ex(ctx, out + len_ev, &len_ev);
DevAssert(rc == 1);
// Get the tag
// rc == EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
EVP_CIPHER_CTX_free(ctx);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef AES_128_CTR_OAI_H
#define AES_128_CTR_OAI_H
#include "aes_128.h"
#include "common/utils/ds/byte_array.h"
#include <endian.h>
#include <stdint.h>
#include <stdlib.h>
void aes_128_ctr(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]);
#endif
......@@ -19,87 +19,18 @@
* contact@openairinterface.org
*/
#include "common/utils/assertions.h"
#include "openair3/SECU/sha_256_hmac.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <nettle/hmac.h>
#include "security_types.h"
#include "secu_defs.h"
#include "kdf.h"
void kdf(const uint8_t *key, uint16_t key_len, uint8_t *s, uint16_t s_len, uint8_t *out,
uint16_t out_len)
void kdf(const uint8_t key[32], byte_array_t data, size_t len, uint8_t out[len])
{
struct hmac_sha256_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
hmac_sha256_set_key(&ctx, key_len, key);
hmac_sha256_update(&ctx, s_len, s);
hmac_sha256_digest(&ctx, out_len, out);
}
#ifndef NAS_UE
int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB)
{
uint8_t s[7];
// FC
s[0] = FC_KENB;
// P0 = Uplink NAS count
s[1] = (nas_count & 0xff000000) >> 24;
s[2] = (nas_count & 0x00ff0000) >> 16;
s[3] = (nas_count & 0x0000ff00) >> 8;
s[4] = (nas_count & 0x000000ff);
// Length of NAS count
s[5] = 0x00;
s[6] = 0x04;
kdf(kasme, 32, s, 7, keNB, 32);
return 0;
// Do we still need kdf function?
sha_256_hmac(key, data, len, out);
}
#endif
int derive_keNB_star(
const uint8_t *kenb_32,
const uint16_t pci,
const uint32_t earfcn_dl,
const bool is_rel8_only,
uint8_t *kenb_star)
{
// see 33.401 section A.5 KeNB* derivation function
uint8_t s[10] = {0};
// FC = 0x13
s[0] = FC_KENB_STAR;
// P0 = PCI (target physical cell id)
s[1] = (pci & 0x0000ff00) >> 8;
s[2] = (pci & 0x000000ff);
// L0 = length of PCI (i.e. 0x00 0x02)
s[3] = 0x00;
s[4] = 0x02;
// P1 = EARFCN-DL (target physical cell downlink frequency)
if (is_rel8_only) {
s[5] = (earfcn_dl & 0x0000ff00) >> 8;
s[6] = (earfcn_dl & 0x000000ff);
s[7] = 0x00;
s[8] = 0x02;
kdf (kenb_32, 32, s, 9, kenb_star, 32);
} else {
s[5] = (earfcn_dl & 0x00ff0000) >> 16;
s[6] = (earfcn_dl & 0x0000ff00) >> 8;
s[7] = (earfcn_dl & 0x000000ff);
s[8] = 0x00;
s[9] = 0x03;
kdf (kenb_32, 32, s, 10, kenb_star, 32);
}
// L1 length of EARFCN-DL (i.e. L1 = 0x00 0x02 if EARFCN-DL is between 0 and 65535, and L1 = 0x00 0x03 if EARFCN-DL is between 65536 and 262143)
// NOTE: The length of EARFCN-DL cannot be generally set to 3 bytes for backward compatibility reasons: A Rel-8
// entity (UE or eNB) would always assume an input parameter length of 2 bytes for the EARFCN-DL. This
// would lead to different derived keys if another entity assumed an input parameter length of 3 bytes for the
// EARFCN-DL.
return 0;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef KEY_DERIVATION_FUNCTION_OSA_H
#define KEY_DERIVATION_FUNCTION_OSA_H
#include <stdint.h>
#include <stdlib.h>
#include "byte_array.h"
void kdf(const uint8_t key[32], byte_array_t data, size_t len, uint8_t out[len]);
#endif
......@@ -26,6 +26,7 @@
#include "security_types.h"
#include "secu_defs.h"
#include "kdf.h"
#define SECU_DEBUG 1
/*!
......@@ -79,7 +80,9 @@ int derive_key_nas(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id,
printf("\n");
#endif
kdf(kasme, 32, s, 7, out, 32);
//kdf(kasme, 32, s, 7, out, 32);
byte_array_t data = {.len = 7, .buf = s};
kdf(kasme, data, 32, out);
memcpy(knas, &out[31-16+1], 16);
......
......@@ -24,10 +24,6 @@
#include <stdint.h>
#include <string.h>
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
#include "assertions.h"
#include "conversions.h"
#include "secu_defs.h"
......
......@@ -19,84 +19,40 @@
* contact@openairinterface.org
*/
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
#include "aes_128_ctr.h"
#include "assertions.h"
#include "conversions.h"
#include "secu_defs.h"
// #define SECU_DEBUG
int nas_stream_encrypt_eea2(nas_stream_cipher_t *stream_cipher, uint8_t *out)
{
uint8_t m[16];
uint32_t local_count;
void *ctx;
uint8_t *data;
uint32_t zero_bit = 0;
uint32_t byte_length;
DevAssert(stream_cipher != NULL);
DevAssert(out != NULL);
zero_bit = stream_cipher->blength & 0x7;
byte_length = stream_cipher->blength >> 3;
if (zero_bit > 0)
byte_length += 1;
ctx = malloc(nettle_aes128.context_size);
data = malloc(byte_length);
local_count = hton_int32(stream_cipher->count);
memset(m, 0, sizeof(m));
memcpy(&m[0], &local_count, 4);
m[4] = ((stream_cipher->bearer & 0x1F) << 3) |
((stream_cipher->direction & 0x01) << 2);
/* Other bits are 0 */
#if defined(SECU_DEBUG)
{
int i;
printf("Blength: %u, Zero bits: %u\n", stream_cipher->blength, zero_bit);
for (i = 0; i < sizeof(m); i++)
printf("0x%02x ", m[i]);
printf("\n");
}
#endif
#if NETTLE_VERSION_MAJOR < 3
nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length,
stream_cipher->key);
#else
nettle_aes128.set_encrypt_key(ctx,
stream_cipher->key);
#endif
nettle_ctr_crypt(ctx, nettle_aes128.encrypt,
nettle_aes128.block_size, m,
byte_length, data, stream_cipher->message);
if (zero_bit > 0)
data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit));
memcpy(out, data, byte_length);
free(data);
free(ctx);
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);
p.type = AES_INITIALIZATION_VECTOR_16;
p.iv16.d.count = htonl(stream_cipher->count);
p.iv16.d.bearer = stream_cipher->bearer;
p.iv16.d.direction = stream_cipher->direction;
DevAssert((stream_cipher->blength & 0x07) == 0);
const uint32_t byte_lenght = stream_cipher->blength >> 3;
// Precondition: out must have enough space, at least as much as the input
const size_t len_out = byte_lenght;
byte_array_t msg = {.buf = stream_cipher->message, .len = byte_lenght};
aes_128_ctr(&p, msg, len_out, out);
return 0;
}
......@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
......@@ -26,15 +27,8 @@
#include "secu_defs.h"
#include <openssl/aes.h>
#include <openssl/cmac.h>
#include <openssl/evp.h>
// test
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <arpa/inet.h>
#include "aes_128_cbc_cmac.h"
#include "assertions.h"
#include "conversions.h"
......@@ -45,84 +39,28 @@
* @param[in] stream_cipher Structure containing various variables to setup encoding
* @param[out] out For EIA2 the output string is 32 bits long
*/
int nas_stream_encrypt_eia2(nas_stream_cipher_t *stream_cipher, uint8_t out[4])
{
uint8_t *m = NULL;
uint32_t local_count;
size_t size = 4;
uint8_t data[16];
CMAC_CTX *cmac_ctx = NULL;
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
uint32_t zero_bit = 0;
uint32_t m_length;
int ret;
DevAssert(stream_cipher != NULL);
DevAssert(stream_cipher->key != NULL);
DevAssert(stream_cipher->key_length > 0);
DevAssert(out != NULL);
memset(data, 0, 16);
zero_bit = stream_cipher->blength & 0x7;
m_length = stream_cipher->blength >> 3;
if (zero_bit > 0)
m_length += 1;
local_count = hton_int32(stream_cipher->count);
m = calloc(m_length + 8, sizeof(uint8_t));
memcpy(&m[0], &local_count, 4);
m[4] = ((stream_cipher->bearer & 0x1F) << 3) | ((stream_cipher->direction & 0x01) << 2);
memcpy(&m[8], stream_cipher->message, m_length);
#if defined(SECU_DEBUG)
{
int i;
printf("Byte length: %u, Zero bits: %u\nm: ", m_length + 8, zero_bit);
for (i = 0; i < m_length + 8; i++)
printf("%02x", m[i]);
printf("\nKey:");
for (i = 0; i < stream_cipher->key_length; i++)
printf("%02x", stream_cipher->key[i]);
printf("\nMessage:");
for (i = 0; i < m_length; i++)
printf("%02x", stream_cipher->message[i]);
printf("\n");
}
#endif
cmac_ctx = CMAC_CTX_new();
ret = CMAC_Init(cmac_ctx, stream_cipher->key, stream_cipher->key_length, cipher, NULL);
ret = CMAC_Update(cmac_ctx, m, m_length + 8);
(void)ret; /* avoid gcc warning "set but not used" */
CMAC_Final(cmac_ctx, data, &size);
CMAC_CTX_free(cmac_ctx);
#if defined(SECU_DEBUG)
{
int i;
printf("out: ");
for (i = 0; i < size; i++)
printf("%02x", data[i]);
printf("\n");
}
#endif
memcpy(out, data, 4);
free(m);
DevAssert(stream_cipher->message != NULL);
DevAssert(stream_cipher->bearer < 32);
DevAssert(stream_cipher->key_length == 16);
DevAssert((stream_cipher->blength & 0x7) == 0);
aes_128_t k_iv = {0};
memcpy(&k_iv.key, stream_cipher->key, sizeof(k_iv.key));
k_iv.type = AES_INITIALIZATION_VECTOR_8;
k_iv.iv8.d.bearer = stream_cipher->bearer;
k_iv.iv8.d.direction = stream_cipher->direction;
k_iv.iv8.d.count = htonl(stream_cipher->count);
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);
memcpy(out, result, 4);
return 0;
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "secu_defs.h"
#include "kdf.h"
#ifndef NAS_UE
int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB)
{
uint8_t s[7] = {0};
// FC
s[0] = FC_KENB;
// P0 = Uplink NAS count
s[1] = (nas_count & 0xff000000) >> 24;
s[2] = (nas_count & 0x00ff0000) >> 16;
s[3] = (nas_count & 0x0000ff00) >> 8;
s[4] = (nas_count & 0x000000ff);
// Length of NAS count
s[5] = 0x00;
s[6] = 0x04;
// kdf(kasme, 32, s, 7, keNB, 32);
byte_array_t data = {.buf = s, .len = 7};
kdf(kasme, data, 32, keNB);
return 0;
}
#endif
int derive_keNB_star(
const uint8_t *kenb_32,
const uint16_t pci,
const uint32_t earfcn_dl,
const bool is_rel8_only,
uint8_t *kenb_star)
{
// see 33.401 section A.5 KeNB* derivation function
uint8_t s[10] = {0};
byte_array_t data = {.buf = s};
// FC = 0x13
s[0] = FC_KENB_STAR;
// P0 = PCI (target physical cell id)
s[1] = (pci & 0x0000ff00) >> 8;
s[2] = (pci & 0x000000ff);
// L0 = length of PCI (i.e. 0x00 0x02)
s[3] = 0x00;
s[4] = 0x02;
// P1 = EARFCN-DL (target physical cell downlink frequency)
if (is_rel8_only) {
s[5] = (earfcn_dl & 0x0000ff00) >> 8;
s[6] = (earfcn_dl & 0x000000ff);
s[7] = 0x00;
s[8] = 0x02;
// kdf (kenb_32, 32, s, 9, kenb_star, 32);
data.len = 9;
} else {
s[5] = (earfcn_dl & 0x00ff0000) >> 16;
s[6] = (earfcn_dl & 0x0000ff00) >> 8;
s[7] = (earfcn_dl & 0x000000ff);
s[8] = 0x00;
s[9] = 0x03;
//kdf (kenb_32, 32, s, 10, kenb_star, 32);
data.len = 10;
}
kdf (kenb_32, data, 32, kenb_star);
// L1 length of EARFCN-DL (i.e. L1 = 0x00 0x02 if EARFCN-DL is between 0 and 65535, and L1 = 0x00 0x03 if EARFCN-DL is between 65536 and 262143)
// NOTE: The length of EARFCN-DL cannot be generally set to 3 bytes for backward compatibility reasons: A Rel-8
// entity (UE or eNB) would always assume an input parameter length of 2 bytes for the EARFCN-DL. This
// would lead to different derived keys if another entity assumed an input parameter length of 3 bytes for the
// EARFCN-DL.
return 0;
}
......@@ -24,6 +24,7 @@
#include "security_types.h"
#include <stdbool.h>
#include <stdint.h>
#define EIA0_ALG_ID 0x00
#define EIA1_128_ALG_ID 0x01
......@@ -36,13 +37,6 @@
#define SECU_DIRECTION_UPLINK 0
#define SECU_DIRECTION_DOWNLINK 1
void kdf(const uint8_t *key,
uint16_t key_len,
uint8_t *s,
uint16_t s_len,
uint8_t *out,
uint16_t out_len);
int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB);
int derive_keNB_star(const uint8_t *kenb_32, const uint16_t pci, const uint32_t earfcn_dl,
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "common/utils/assertions.h"
#include "sha_256_hmac.h"
#include <openssl/hmac.h>
#if OPENSSL_VERSION_MAJOR >= 3
// code for version 3.0 or greater
#include <openssl/core_names.h>
void sha_256_hmac(const uint8_t key[32], byte_array_t data, size_t len, uint8_t out[len])
{
DevAssert(key != NULL);
DevAssert(data.buf != NULL);
DevAssert(data.len != 0);
DevAssert(len != 0);
OSSL_LIB_CTX* library_context = OSSL_LIB_CTX_new();
DevAssert(library_context != NULL);
// A property query used for selecting the MAC implementation.
const char* propq = NULL;
// Fetch the HMAC implementation
EVP_MAC* mac = EVP_MAC_fetch(library_context, "HMAC", propq);
DevAssert(mac != NULL);
// Create a context for the HMAC operation
EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(mac);
DevAssert(mctx != NULL);
// The underlying digest to be used
OSSL_PARAM params[2] = {0};
char digest_name[] = "SHA2-256";
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, digest_name, sizeof(digest_name));
params[1] = OSSL_PARAM_construct_end();
// Initialise the HMAC operation
int rc = EVP_MAC_init(mctx, key, 32, params);
DevAssert(rc == 1);
// Make one or more calls to process the data to be authenticated
rc = EVP_MAC_update(mctx, data.buf, data.len);
DevAssert(rc == 1);
// Make one call to the final to get the MAC
rc = EVP_MAC_final(mctx, out, &len, len);
DevAssert(rc == 1);
// OpenSSL free functions will ignore NULL arguments
EVP_MAC_CTX_free(mctx);
EVP_MAC_free(mac);
OSSL_LIB_CTX_free(library_context);
}
#else
// code for 1.1.x or lower
void sha_256_hmac(const uint8_t key[32], byte_array_t data, size_t len, uint8_t out[len])
{
DevAssert(key != NULL);
DevAssert(data.buf != NULL);
DevAssert(data.len != 0);
DevAssert(len != 0);
HMAC_CTX* ctx = HMAC_CTX_new();
HMAC_Init_ex(ctx, key, 32, EVP_sha256(), NULL);
HMAC_Update(ctx, data.buf, data.len);
HMAC_Final(ctx, out, (uint32_t*)&len);
HMAC_CTX_free(ctx);
}
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef SHA_256_HMAC_OAI_H
#define SHA_256_HMAC_OAI_H
#include <stdint.h>
#include <stdlib.h>
#include "byte_array.h"
void sha_256_hmac(const uint8_t key[32], byte_array_t data, size_t len, uint8_t out[len]);
#endif
......@@ -43,8 +43,7 @@ if HAVE_CHECK
TESTS = \
test_kdf \
test_aes128_cmac_encrypt \
test_aes128_ctr_encrypt \
test_aes128_ctr_decrypt \
test_aes128_ctr \
test_secu_kenb \
test_secu_knas \
test_secu_knas_encrypt_eea1 \
......@@ -68,8 +67,7 @@ common_ldadd = $(top_builddir)/SECU/libsecu.la \
check_PROGRAMS = \
test_kdf \
test_aes128_cmac_encrypt \
test_aes128_ctr_encrypt \
test_aes128_ctr_decrypt \
test_aes128_ctr \
test_secu_kenb \
test_secu_knas \
test_secu_knas_encrypt_eea1 \
......
This diff is collapsed.
......@@ -14,14 +14,6 @@ DATE_REV := $(shell date '+%F %T')
NUM_CORES:=$(shell cat /proc/cpuinfo | grep processor | wc -l)
# Check for libraries and export cflags/linker variables
NETTLE_FOUND := $(shell if pkg-config --exists nettle; then echo "1" ; else echo "0"; fi)
ifeq ($(NETTLE_FOUND), 1)
NETTLE_LIBS := $(shell pkg-config --libs nettle)
#else
#@echo "package nettle not installed"
endif
OPENSSL_FOUND := $(shell if pkg-config --exists openssl; then echo "1" ; else echo "0"; fi)
ifeq ($(OPENSSL_FOUND), 1)
OPENSSL_LIBS := $(shell pkg-config --libs openssl)
......
......@@ -20,7 +20,7 @@ First, you must have all four openair SW directories, openair1, openair2, openai
- libpgm-5.1 and libpgm-5.1-dev for distributed simulation with reliable multicast transmport
- libxml2 and libxml2-dev
- libforms-bin libforms-dev
- nettle-dev nettle-bin openssl libssl-dev
- openssl libssl-dev
- libatlas-base-dev and libatlas-headers (for Ubuntu 11.04, libatlas-dev instead of libatlas-headers)
- asn1c and the LTE ASN1 files (for more information on how to install this and generate the required files see the README file in openair2/RRC/LITE/MESSAGES)
......
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