OSA SECU harmonization

This commit is contained in:
mir
2023-05-26 12:35:33 +02:00
committed by Robert Schmidt
parent 7c7d54e463
commit c9012298de
53 changed files with 832 additions and 1778 deletions
-18
View File
@@ -1,18 +0,0 @@
OAISIM Security Algorithms v0.1
Dependencies:
- openssl >= 1.0.1
Compilation:
When compiling oaisim, add SECU=1 to enable security features. The makefile will
check for required dependencies and disable this feature if not all dependencies
are met.
OSA is based on 3GPP TS 33.401.
Note that only EEA2 and EIA2 algorithms are supported, SNOW-3G is not implemented.
Currently the kenb used to derive kRRCint, kRRCenc and kUPenc is composed of the
UE_id. In the future this parameter can be either obtained by deriving KASME received
from core epc (in the S1AP initial context setup request)
or configurable via command line or XML file.
-138
View File
@@ -1,138 +0,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
*/
/*!
* \file secu_defs.h
* \brief Openair security algorithms functions implementing 3GPP TS 33.401
* \note HMAC computations are done by openssl library
* \author Sebastien ROUX
* \date 2013
* \version 0.1
* @ingroup security
*/
#ifndef __UTIL_OSA_OSA_DEFS__H__
#define __UTIL_OSA_OSA_DEFS__H__
#define EIA0_ALG_ID 0x00
#define EIA1_128_ALG_ID 0x01
#define EIA2_128_ALG_ID 0x02
#define EEA0_ALG_ID EIA0_ALG_ID
#define EEA1_128_ALG_ID EIA1_128_ALG_ID
#define EEA2_128_ALG_ID EIA2_128_ALG_ID
#define SECU_DIRECTION_UPLINK 0
#define SECU_DIRECTION_DOWNLINK 1
typedef enum {
NAS_ENC_ALG = 0x01,
NAS_INT_ALG = 0x02,
RRC_ENC_ALG = 0x03,
RRC_INT_ALG = 0x04,
UP_ENC_ALG = 0x05,
UP_INT_ALG = 0x06
} algorithm_type_dist_t;
//int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB);
int derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB);
int derive_key(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_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);
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);
//#define derive_key_nas_enc(aLGiD, kEY, kNAS) derive_key(NAS_ENC_ALG, aLGiD, kEY, kNAS)
//#define derive_key_nas_int(aLGiD, kEY, kNAS) derive_key(NAS_INT_ALG, aLGiD, kEY, kNAS)
#define derive_key_rrc_enc(aLGiD, kEY, kNAS) \
derive_key(RRC_ENC_ALG, aLGiD, kEY, kNAS)
#define derive_key_rrc_int(aLGiD, kEY, kNAS) \
derive_key(RRC_INT_ALG, aLGiD, kEY, kNAS)
#define derive_key_up_enc(aLGiD, kEY, kNAS) \
derive_key(UP_ENC_ALG, aLGiD, kEY, kNAS)
#define derive_key_up_int(aLGiD, kEY, kNAS) \
derive_key(UP_INT_ALG, aLGiD, kEY, kNAS)
// 5G SA
#define nr_derive_key_rrc_enc(aLGiD, kEY, kRRC) \
nr_derive_key(RRC_ENC_ALG, aLGiD, kEY, kRRC)
#define nr_derive_key_rrc_int(aLGiD, kEY, kRRC) \
nr_derive_key(RRC_INT_ALG, aLGiD, kEY, kRRC)
#define nr_derive_key_up_enc(aLGiD, kEY, kUP) \
nr_derive_key(UP_ENC_ALG, aLGiD, kEY, kUP)
#define nr_derive_key_up_int(aLGiD, kEY, kUP) \
nr_derive_key(UP_INT_ALG, aLGiD, kEY, kUP)
typedef struct {
uint8_t *key;
uint32_t key_length;
uint32_t count;
uint8_t bearer;
uint8_t direction;
uint8_t *message;
/* length in bits */
uint32_t blength;
} stream_cipher_t;
/*!
* @brief Encrypt/Decrypt a block of data based on the provided algorithm
* @param[in] algorithm Algorithm used to encrypt the data
* Possible values are:
* - EIA0_ALG_ID for NULL encryption
* - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now)
* - EIA2_128_ALG_ID for 128 bits AES LTE encryption
* @param[in] stream_cipher All parameters used to compute the encrypted block of data
* @param[out] out The encrypted block of data dynamically allocated
* @return 0 if everything OK, -1 if something failed
*/
int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out);
#define stream_decrypt stream_encrypt
int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4]);
/*!
* @brief Decrypt a block of data based on the provided algorithm
* @param[in] algorithm Algorithm used to encrypt the data
* Possible values are:
* - EIA0_ALG_ID for NULL encryption
* - EIA1_128_ALG_ID for SNOW-3G encryption (not avalaible right now)
* - EIA2_128_ALG_ID for 128 bits AES LTE encryption
* @param[in] stream_cipher All parameters used to compute the decrypted block of data
* @param[out] out The decrypted block of data dynamically allocated
* @return 0 if everything OK, -1 if something failed
*/
int stream_decrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out);
int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected);
#undef SECU_DEBUG
#endif /* __UTIL_OSA_OSA_DEFS__H__ */
-50
View File
@@ -1,50 +0,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 OSA_INTERNAL_H_
#define OSA_INTERNAL_H_
#define FC_KENB (0x11)
#define FC_NH (0x12)
#define FC_KENB_STAR (0x13)
/* 33401 #A.7 Algorithm for key derivation function.
* This FC should be used for:
* - NAS Encryption algorithm
* - NAS Integrity algorithm
* - RRC Encryption algorithm
* - RRC Integrity algorithm
* - User Plane Encryption algorithm
*/
#define FC_ALG_KEY_DER (0x15)
#define FC_KASME_TO_CK (0x16)
#define NR_FC_ALG_KEY_DER (0x69)
#define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70)
#ifndef hton_int32
# define hton_int32(x) \
(((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | \
((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24))
#endif
// #define SECU_DEBUG
#endif /* OSA_INTERNAL_H_ */
-175
View File
@@ -1,175 +0,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 "../../../openair3/SECU/kdf.h"
#include <stdint.h>
#include <string.h>
#include "osa_defs.h"
#include "osa_internal.h"
#include "common/utils/LOG/log.h"
/*!
* @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
* be found in 3GPP TS.33401 #A.7
* @param[in] alg_type Algorithm distinguisher
* @param[in] alg_id Algorithm identifier.
* Possible values are:
* - 0 for EIA0 algorithm (Null Integrity Protection algorithm)
* - 1 for 128-EIA1 SNOW 3G
* - 2 for 128-EIA2 AES
* @param[in] key The top key used to derive other subkeys
* @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)
{
uint8_t string[7] = {0};
/* FC */
string[0] = FC_ALG_KEY_DER;
/* P0 = algorithm type distinguisher */
string[1] = (uint8_t)(alg_type & 0xFF);
/* L0 = length(P0) = 1 */
string[2] = 0x00;
string[3] = 0x01;
/* P1 */
string[4] = alg_id;
/* L1 = length(P1) = 1 */
string[5] = 0x00;
string[6] = 0x01;
#if defined(SECU_DEBUG)
{
int i;
char payload[6 * sizeof(string) + 1];
int index = 0;
for (i = 0; i < sizeof(string); i++)
index += sprintf(&payload[index], "0x%02x ", string[i]);
LOG_D(OSA, "Key deriver input string: %s\n", payload);
}
#endif
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)
{
uint8_t string[7];
/* FC */
string[0] = NR_FC_ALG_KEY_DER;
/* P0 = algorithm type distinguisher */
string[1] = (uint8_t)(alg_type & 0xFF);
/* L0 = length(P0) = 1 */
string[2] = 0x00;
string[3] = 0x01;
/* P1 */
string[4] = alg_id;
/* L1 = length(P1) = 1 */
string[5] = 0x00;
string[6] = 0x01;
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);
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 s[10] = {0};
/* FC */
s[0] = NR_FC_ALG_KEY_NG_RAN_STAR_DER;
/* P0 = PCI */
s[1] = (pci & 0x0000ff00) >> 8;
s[2] = (pci & 0x000000ff);
/* L0 = length(P0) = 2 */
s[3] = 0x00;
s[4] = 0x02;
/* P1 = NR ARFCN */
s[5] = (nr_arfcn_dl & 0x00ff0000) >> 16;
s[6] = (nr_arfcn_dl & 0x0000ff00) >> 8;
s[7] = (nr_arfcn_dl & 0x000000ff);
/* L1 = length(P1) = 3 */
s[8] = 0x00;
s[9] = 0x03;
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 s[5] = {0};
/* FC is 0x1c (see 3gpp 33.401 annex A.15) */
s[0] = 0x1c;
/* put sk_counter */
s[1] = (sk_counter >> 8) & 0xff;
s[2] = sk_counter & 0xff;
/* put length of sk_counter (2) */
s[3] = 0x00;
s[4] = 0x02;
byte_array_t data = {.buf = s, .len = 5};
kdf(keNB, data, 32, skgNB);
return 0;
}
-55
View File
@@ -1,55 +0,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 <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};
-344
View File
@@ -1,344 +0,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 <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "osa_rijndael.h"
#include "osa_snow3g.h"
static uint8_t OSA_MULx(uint8_t V, uint8_t c);
static uint8_t OSA_MULxPOW(uint8_t V, uint8_t i, uint8_t c);
static uint32_t OSA_MULalpha(uint8_t c);
static uint32_t OSA_DIValpha(uint8_t c);
static uint32_t OSA_S1(uint32_t w);
static uint32_t OSA_S2(uint32_t w);
static void osa_snow3g_clock_LFSR_initialization_mode(uint32_t F, osa_snow_3g_context_t *s3g_ctx_pP);
static void osa_snow3g_clock_LFSR_key_stream_mode(osa_snow_3g_context_t *snow_3g_context_pP);
static uint32_t osa_snow3g_clock_fsm(osa_snow_3g_context_t *snow_3g_context_pP);
void osa_snow3g_initialize(uint32_t k[4], uint32_t IV[4], osa_snow_3g_context_t *snow_3g_context_pP);
void osa_snow3g_generate_key_stream(uint32_t n, uint32_t *ks, osa_snow_3g_context_t *snow_3g_context_pP);
/* OSA_MULx.
* Input V: an 8-bit input.
* Input c: an 8-bit input.
* Output : an 8-bit input.
* MULx maps 16 bits to 8 bits
*/
static uint8_t OSA_MULx(uint8_t V, uint8_t c)
{
//If the leftmost (i.e. the most significant) bit of V equals 1
if ( V & 0x80 )
return ( (V << 1) ^ c);
else
return ( V << 1);
}
/* OSA_MULxPOW.
* Input V: an 8-bit input.
* Input i: a positive integer.
* Input c: an 8-bit input.
* Output : an 8-bit output.
* MULxPOW maps 16 bits and a positive integer i to 8 bit.
*/
static uint8_t OSA_MULxPOW(uint8_t V, uint8_t i, uint8_t c)
{
if ( i == 0)
return V;
else
return OSA_MULx( OSA_MULxPOW( V, i-1, c ), c);
}
/* The function OSA_MULalpha.
* Input c: 8-bit input.
* Output : 32-bit output.
* maps 8 bits to 32 bits.
*/
static uint32_t OSA_MULalpha(uint8_t c)
{
return ( ( ((uint32_t)OSA_MULxPOW(c,23, 0xa9)) << 24 ) |
( ((uint32_t)OSA_MULxPOW(c, 245, 0xa9)) << 16 ) |
( ((uint32_t)OSA_MULxPOW(c, 48, 0xa9)) << 8 ) |
( ((uint32_t)OSA_MULxPOW(c, 239, 0xa9)) ) ) ;
}
/* The function DIV alpha.
* Input c: 8-bit input.
* Output : 32-bit output.
* maps 8 bits to 32 bit.
*/
static uint32_t OSA_DIValpha(uint8_t c)
{
return ( ( ((uint32_t)OSA_MULxPOW(c, 16, 0xa9)) << 24 ) |
( ((uint32_t)OSA_MULxPOW(c, 39, 0xa9)) << 16 ) |
( ((uint32_t)OSA_MULxPOW(c, 6, 0xa9)) << 8 ) |
( ((uint32_t)OSA_MULxPOW(c, 64, 0xa9)) ) ) ;
}
/* The 32x32-bit S-Box S1
* Input: a 32-bit input.
* Output: a 32-bit output of S1 box.
* The S-Box S1 maps a 32-bit input to a 32-bit output.
* w = w0 || w1 || w2 || w3 the 32-bit input with w0 the most and w3 the least significant byte.
* S1(w)= r0 || r1 || r2 || r3 with r0 the most and r3 the least significant byte.
*/
static uint32_t OSA_S1(uint32_t w)
{
uint8_t r0=0, r1=0, r2=0, r3=0;
uint8_t srw0 = OSA_SR[ (uint8_t)((w >> 24) & 0xff) ];
uint8_t srw1 = OSA_SR[ (uint8_t)((w >> 16) & 0xff) ];
uint8_t srw2 = OSA_SR[ (uint8_t)((w >> 8) & 0xff) ];
uint8_t srw3 = OSA_SR[ (uint8_t)((w) & 0xff) ];
r0 = ( ( OSA_MULx( srw0 , 0x1b) ) ^
( srw1 ) ^
( srw2 ) ^
( (OSA_MULx( srw3, 0x1b)) ^ srw3 )
);
r1 = ( ( ( OSA_MULx( srw0 , 0x1b) ) ^ srw0 ) ^
( OSA_MULx(srw1, 0x1b) ) ^
( srw2 ) ^
( srw3 )
);
r2 = ( ( srw0 ) ^
( ( OSA_MULx( srw1 , 0x1b) ) ^ srw1 ) ^
( OSA_MULx(srw2, 0x1b) ) ^
( srw3 )
);
r3 = ( ( srw0 ) ^
( srw1 ) ^
( ( OSA_MULx( srw2 , 0x1b) ) ^ srw2 ) ^
( OSA_MULx( srw3, 0x1b) )
);
return ( ( ((uint32_t)r0) << 24 ) | ( ((uint32_t)r1) << 16 ) | ( ((uint32_t)r2) << 8 ) | ( ((uint32_t)r3) ) );
}
/* The 32x32-bit S-Box S2
* Input: a 32-bit input.
* Output: a 32-bit output of S2 box.
* The S-Box S2 maps a 32-bit input to a 32-bit output.
* Let w = w0 || w1 || w2 || w3 the 32-bit input with w0 the most and w3 the least significant byte.
* Let S2(w)= r0 || r1 || r2 || r3 with r0 the most and r3 the least significant byte.
*/
static uint32_t OSA_S2(uint32_t w)
{
uint8_t r0=0, r1=0, r2=0, r3=0;
uint8_t sqw0 = OSA_SQ[ (uint8_t)((w >> 24) & 0xff) ];
uint8_t sqw1 = OSA_SQ[ (uint8_t)((w >> 16) & 0xff) ];
uint8_t sqw2 = OSA_SQ[ (uint8_t)((w >> 8) & 0xff) ];
uint8_t sqw3 = OSA_SQ[ (uint8_t)((w) & 0xff) ];
r0 = ( ( OSA_MULx( sqw0 , 0x69) ) ^
( sqw1 ) ^
( sqw2 ) ^
( (OSA_MULx( sqw3, 0x69)) ^ sqw3 )
);
r1 = ( ( ( OSA_MULx( sqw0 , 0x69) ) ^ sqw0 ) ^
( OSA_MULx(sqw1, 0x69) ) ^
( sqw2 ) ^
( sqw3 )
);
r2 = ( ( sqw0 ) ^
( ( OSA_MULx( sqw1 , 0x69) ) ^ sqw1 ) ^
( OSA_MULx(sqw2, 0x69) ) ^
( sqw3 )
);
r3 = ( ( sqw0 ) ^
( sqw1 ) ^
( ( OSA_MULx( sqw2 , 0x69) ) ^ sqw2 ) ^
( OSA_MULx( sqw3, 0x69) )
);
return ( ( ((uint32_t)r0) << 24 ) | ( ((uint32_t)r1) << 16 ) | ( ((uint32_t)r2) << 8 ) | ( ((uint32_t)r3) ) );
}
/* Clocking LFSR in initialization mode.
* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock.
* Input F: a 32-bit word comes from output of FSM.
* See section 3.4.4.
*/
static void osa_snow3g_clock_LFSR_initialization_mode(uint32_t F, osa_snow_3g_context_t *s3g_ctx_pP)
{
uint32_t v = ( ( (s3g_ctx_pP->LFSR_S0 << 8) & 0xffffff00 ) ^
( OSA_MULalpha( (uint8_t)((s3g_ctx_pP->LFSR_S0>>24) & 0xff) ) ) ^
( s3g_ctx_pP->LFSR_S2 ) ^
( (s3g_ctx_pP->LFSR_S11 >> 8) & 0x00ffffff ) ^
( OSA_DIValpha( (uint8_t)( ( s3g_ctx_pP->LFSR_S11) & 0xff ) ) ) ^
( F )
);
s3g_ctx_pP->LFSR_S0 = s3g_ctx_pP->LFSR_S1;
s3g_ctx_pP->LFSR_S1 = s3g_ctx_pP->LFSR_S2;
s3g_ctx_pP->LFSR_S2 = s3g_ctx_pP->LFSR_S3;
s3g_ctx_pP->LFSR_S3 = s3g_ctx_pP->LFSR_S4;
s3g_ctx_pP->LFSR_S4 = s3g_ctx_pP->LFSR_S5;
s3g_ctx_pP->LFSR_S5 = s3g_ctx_pP->LFSR_S6;
s3g_ctx_pP->LFSR_S6 = s3g_ctx_pP->LFSR_S7;
s3g_ctx_pP->LFSR_S7 = s3g_ctx_pP->LFSR_S8;
s3g_ctx_pP->LFSR_S8 = s3g_ctx_pP->LFSR_S9;
s3g_ctx_pP->LFSR_S9 = s3g_ctx_pP->LFSR_S10;
s3g_ctx_pP->LFSR_S10 = s3g_ctx_pP->LFSR_S11;
s3g_ctx_pP->LFSR_S11 = s3g_ctx_pP->LFSR_S12;
s3g_ctx_pP->LFSR_S12 = s3g_ctx_pP->LFSR_S13;
s3g_ctx_pP->LFSR_S13 = s3g_ctx_pP->LFSR_S14;
s3g_ctx_pP->LFSR_S14 = s3g_ctx_pP->LFSR_S15;
s3g_ctx_pP->LFSR_S15 = v;
}
/* Clocking LFSR in keystream mode.
* LFSR Registers S0 to S15 are updated as the LFSR receives a single clock.
* See section 3.4.5.
*/
static void osa_snow3g_clock_LFSR_key_stream_mode(osa_snow_3g_context_t *snow_3g_context_pP)
{
uint32_t v = ( ( (snow_3g_context_pP->LFSR_S0 << 8) & 0xffffff00 ) ^
( OSA_MULalpha( (uint8_t)((snow_3g_context_pP->LFSR_S0>>24) & 0xff) ) ) ^
( snow_3g_context_pP->LFSR_S2 ) ^
( (snow_3g_context_pP->LFSR_S11 >> 8) & 0x00ffffff ) ^
( OSA_DIValpha( (uint8_t)( ( snow_3g_context_pP->LFSR_S11) & 0xff ) ) )
);
snow_3g_context_pP->LFSR_S0 = snow_3g_context_pP->LFSR_S1;
snow_3g_context_pP->LFSR_S1 = snow_3g_context_pP->LFSR_S2;
snow_3g_context_pP->LFSR_S2 = snow_3g_context_pP->LFSR_S3;
snow_3g_context_pP->LFSR_S3 = snow_3g_context_pP->LFSR_S4;
snow_3g_context_pP->LFSR_S4 = snow_3g_context_pP->LFSR_S5;
snow_3g_context_pP->LFSR_S5 = snow_3g_context_pP->LFSR_S6;
snow_3g_context_pP->LFSR_S6 = snow_3g_context_pP->LFSR_S7;
snow_3g_context_pP->LFSR_S7 = snow_3g_context_pP->LFSR_S8;
snow_3g_context_pP->LFSR_S8 = snow_3g_context_pP->LFSR_S9;
snow_3g_context_pP->LFSR_S9 = snow_3g_context_pP->LFSR_S10;
snow_3g_context_pP->LFSR_S10 = snow_3g_context_pP->LFSR_S11;
snow_3g_context_pP->LFSR_S11 = snow_3g_context_pP->LFSR_S12;
snow_3g_context_pP->LFSR_S12 = snow_3g_context_pP->LFSR_S13;
snow_3g_context_pP->LFSR_S13 = snow_3g_context_pP->LFSR_S14;
snow_3g_context_pP->LFSR_S14 = snow_3g_context_pP->LFSR_S15;
snow_3g_context_pP->LFSR_S15 = v;
}
/* Clocking FSM.
* Produces a 32-bit word F.
* Updates FSM registers R1, R2, R3.
* See Section 3.4.6.
*/
static uint32_t osa_snow3g_clock_fsm(osa_snow_3g_context_t *snow_3g_context_pP)
{
uint32_t F = ( ( snow_3g_context_pP->LFSR_S15 + snow_3g_context_pP->FSM_R1 ) & 0xffffffff ) ^ snow_3g_context_pP->FSM_R2 ;
uint32_t r = ( snow_3g_context_pP->FSM_R2 + ( snow_3g_context_pP->FSM_R3 ^ snow_3g_context_pP->LFSR_S5 ) ) & 0xffffffff ;
snow_3g_context_pP->FSM_R3 = OSA_S2(snow_3g_context_pP->FSM_R2);
snow_3g_context_pP->FSM_R2 = OSA_S1(snow_3g_context_pP->FSM_R1);
snow_3g_context_pP->FSM_R1 = r;
return F;
}
/* Initialization.
* Input k[4]: Four 32-bit words making up 128-bit key.
* Input IV[4]: Four 32-bit words making 128-bit initialization variable.
* Output: All the LFSRs and FSM are initialized for key generation.
* See Section 4.1.
*/
void osa_snow3g_initialize(uint32_t k[4], uint32_t IV[4], osa_snow_3g_context_t *snow_3g_context_pP)
{
uint8_t i = 0;
uint32_t F = 0x0;
snow_3g_context_pP->LFSR_S15 = k[3] ^ IV[0];
snow_3g_context_pP->LFSR_S14 = k[2];
snow_3g_context_pP->LFSR_S13 = k[1];
snow_3g_context_pP->LFSR_S12 = k[0] ^ IV[1];
snow_3g_context_pP->LFSR_S11 = k[3] ^ 0xffffffff;
snow_3g_context_pP->LFSR_S10 = k[2] ^ 0xffffffff ^ IV[2];
snow_3g_context_pP->LFSR_S9 = k[1] ^ 0xffffffff ^ IV[3];
snow_3g_context_pP->LFSR_S8 = k[0] ^ 0xffffffff;
snow_3g_context_pP->LFSR_S7 = k[3];
snow_3g_context_pP->LFSR_S6 = k[2];
snow_3g_context_pP->LFSR_S5 = k[1];
snow_3g_context_pP->LFSR_S4 = k[0];
snow_3g_context_pP->LFSR_S3 = k[3] ^ 0xffffffff;
snow_3g_context_pP->LFSR_S2 = k[2] ^ 0xffffffff;
snow_3g_context_pP->LFSR_S1 = k[1] ^ 0xffffffff;
snow_3g_context_pP->LFSR_S0 = k[0] ^ 0xffffffff;
snow_3g_context_pP->FSM_R1 = 0x0;
snow_3g_context_pP->FSM_R2 = 0x0;
snow_3g_context_pP->FSM_R3 = 0x0;
for(i=0; i<32; i++) {
F = osa_snow3g_clock_fsm(snow_3g_context_pP);
osa_snow3g_clock_LFSR_initialization_mode(F, snow_3g_context_pP);
}
}
/* Generation of Keystream.
* input n: number of 32-bit words of keystream.
* input z: space for the generated keystream, assumes
* memory is allocated already.
* output: generated keystream which is filled in z
* See section 4.2.
*/
void osa_snow3g_generate_key_stream(uint32_t n, uint32_t *ks, osa_snow_3g_context_t *snow_3g_context_pP)
{
uint32_t t = 0;
uint32_t F = 0x0;
osa_snow3g_clock_fsm(snow_3g_context_pP); /* Clock FSM once. Discard the output. */
osa_snow3g_clock_LFSR_key_stream_mode(snow_3g_context_pP); /* Clock LFSR in keystream mode once. */
for ( t=0; t<n; t++) {
F = osa_snow3g_clock_fsm(snow_3g_context_pP); /* STEP 1 */
ks[t] = F ^ snow_3g_context_pP->LFSR_S0; /* STEP 2 */
/* Note that ks[t] corresponds to z_{t+1} in section 4.2*/
osa_snow3g_clock_LFSR_key_stream_mode(snow_3g_context_pP); /* STEP 3 */
}
}
-77
View File
@@ -1,77 +0,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
*/
/*! \file snow3g.h
* \brief
* \author Open source Adapted from Specification of the 3GPP Confidentiality and
* Integrity Algorithms UEA2 & UIA2. Document 2: SNOW 3G Specification
* \integrators Kharbach Othmane, GAUTHIER Lionel.
* \date 2014
* \version
* \note
* \bug
* \warning
*/
#ifndef OSA_SNOW3G_H_
#define OSA_SNOW3G_H_
typedef struct osa_snow_3g_context_s {
uint32_t LFSR_S0;
uint32_t LFSR_S1;
uint32_t LFSR_S2;
uint32_t LFSR_S3;
uint32_t LFSR_S4;
uint32_t LFSR_S5;
uint32_t LFSR_S6;
uint32_t LFSR_S7;
uint32_t LFSR_S8;
uint32_t LFSR_S9;
uint32_t LFSR_S10;
uint32_t LFSR_S11;
uint32_t LFSR_S12;
uint32_t LFSR_S13;
uint32_t LFSR_S14;
uint32_t LFSR_S15;
/* FSM : The Finite State Machine has three 32-bit registers R1, R2 and R3.
*/
uint32_t FSM_R1;
uint32_t FSM_R2;
uint32_t FSM_R3;
} osa_snow_3g_context_t;
/* Initialization.
* Input k[4]: Four 32-bit words making up 128-bit key.
* Input IV[4]: Four 32-bit words making 128-bit initialization variable.
* Output: All the LFSRs and FSM are initialized for key generation.
*/
void osa_snow3g_initialize(uint32_t k[4], uint32_t IV[4], osa_snow_3g_context_t *snow_3g_context_pP);
/* Generation of Keystream.
* input n: number of 32-bit words of keystream.
* input z: space for the generated keystream, assumes
* memory is allocated already.
* output: generated keystream which is filled in z
*/
void osa_snow3g_generate_key_stream(uint32_t n, uint32_t *z, osa_snow_3g_context_t *snow_3g_context_pP);
#endif
-181
View File
@@ -1,181 +0,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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.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"
#include "osa_snow3g.h"
#include "osa_internal.h"
int stream_encrypt_eea0(stream_cipher_t *stream_cipher, uint8_t **out)
{
uint8_t *data = NULL;
uint32_t byte_length;
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");
byte_length = (stream_cipher->blength + 7) >> 3;
if (*out == NULL) {
/* User did not provide output buffer */
data = malloc(byte_length);
*out = data;
} else {
data = *out;
}
memcpy(data, stream_cipher->message, byte_length);
return 0;
}
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;
uint32_t *KS;
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;
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*/
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. */
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];
IV[0] = IV[2];
/* 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);
if (zero_bit > 0) {
KS[n - 1] = KS[n - 1] & (uint32_t)(0xFFFFFFFF << (8 - zero_bit));
}
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);
}
if (zero_bit > 0) {
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));
}
free(KS);
*out = stream_cipher->message;
return 0;
}
int stream_encrypt_eea2(stream_cipher_t *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);
if (*out == NULL) {
*out = calloc(1, (stream_cipher->blength >> 3) + 1);
DevAssert(*out != NULL && "Memory exhausted");
}
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;
}
int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out)
{
if (algorithm == EEA0_ALG_ID) {
return stream_encrypt_eea0(stream_cipher, out);
} else if (algorithm == EEA1_128_ALG_ID) {
return stream_encrypt_eea1(stream_cipher, out);
} else if (algorithm == EEA2_128_ALG_ID) {
return stream_encrypt_eea2(stream_cipher, out);
}
LOG_E(OSA, "Provided encryption algorithm is currently not supported = %u\n", algorithm);
return -1;
}
-287
View File
@@ -1,287 +0,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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "assertions.h"
#include "common/utils/LOG/log.h"
#include "openair3/SECU/aes_128_cbc_cmac.h"
#include "osa_defs.h"
#include "osa_snow3g.h"
#include "osa_internal.h"
// see spec 3GPP Confidentiality and Integrity Algorithms UEA2&UIA2. Document 1: UEA2 and UIA2 Specification. Version 1.1
/* OSA_MUL64x.
* Input V: a 64-bit input.
* Input c: a 64-bit input.
* Output : a 64-bit output.
* A 64-bit memory is allocated which is to be freed by the calling
* function.
* See section 4.3.2 for details.
*/
uint64_t OSA_MUL64x(uint64_t V, uint64_t c)
{
if (V & 0x8000000000000000)
return (V << 1) ^ c;
else
return V << 1;
}
/* OSA_MUL64xPOW.
* Input V: a 64-bit input.
* Input i: a positive integer.
* Input c: a 64-bit input.
* Output : a 64-bit output.
* A 64-bit memory is allocated which is to be freed by the calling
function.
* See section 4.3.3 for details.
*/
uint64_t OSA_MUL64xPOW(uint64_t V, uint32_t i, uint64_t c)
{
if (i == 0)
return V;
else
return OSA_MUL64x(OSA_MUL64xPOW(V, i - 1, c), c);
}
/* OSA_MUL64.
* Input V: a 64-bit input.
* Input P: a 64-bit input.
* Input c: a 64-bit input.
* Output : a 64-bit output.
* A 64-bit memory is allocated which is to be freed by the calling
* function.
* See section 4.3.4 for details.
*/
uint64_t OSA_MUL64(uint64_t V, uint64_t P, uint64_t c)
{
uint64_t result = 0;
int i = 0;
for (i = 0; i < 64; i++) {
if ((P >> i) & 0x1)
result ^= OSA_MUL64xPOW(V, i, c);
}
return result;
}
/* osa_mask32bit.
* Input n: an integer in 1-32.
* Output : a 32 bit mask.
* Prepares a 32 bit mask with required number of 1 bits on the MSB side.
*/
uint32_t osa_mask32bit(int n)
{
uint32_t mask = 0x0;
if (n % 32 == 0)
return 0xffffffff;
while (n--)
mask = (mask >> 1) ^ 0x80000000;
return mask;
}
/*!
* @brief Create integrity cmac t for a given message.
* @param[in] stream_cipher Structure containing various variables to setup encoding
* @param[out] out For EIA2 the output string is 32 bits long
*/
int stream_compute_integrity_eia1(stream_cipher_t *stream_cipher, uint8_t out[4])
{
osa_snow_3g_context_t snow_3g_context;
uint32_t K[4], IV[4], z[5];
int i = 0, D;
uint32_t MAC_I = 0;
uint64_t EVAL;
uint64_t V;
uint64_t P;
uint64_t Q;
uint64_t c;
uint64_t M_D_2;
int rem_bits;
uint32_t mask = 0;
uint32_t *message;
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
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]);
K[0] = hton_int32(K[0]);
/* Prepare the Initialization Vector (IV) for SNOW3G initialization as in
section 4.4. */
IV[3] = (uint32_t)stream_cipher->count;
IV[2] = ((((uint32_t)stream_cipher->bearer) & 0x0000001F) << 27);
IV[1] = (uint32_t)(stream_cipher->count) ^ ((uint32_t)(stream_cipher->direction) << 31);
IV[0] = ((((uint32_t)stream_cipher->bearer) & 0x0000001F) << 27) ^ ((uint32_t)(stream_cipher->direction & 0x00000001) << 15);
// printf ("K:\n");
// hexprint(K, 16);
// printf ("K[0]:%08X\n",K[0]);
// printf ("K[1]:%08X\n",K[1]);
// printf ("K[2]:%08X\n",K[2]);
// printf ("K[3]:%08X\n",K[3]);
// printf ("IV:\n");
// hexprint(IV, 16);
// printf ("IV[0]:%08X\n",IV[0]);
// printf ("IV[1]:%08X\n",IV[1]);
// printf ("IV[2]:%08X\n",IV[2]);
// printf ("IV[3]:%08X\n",IV[3]);
z[0] = z[1] = z[2] = z[3] = z[4] = 0;
/* Run SNOW 3G to produce 5 keystream words z_1, z_2, z_3, z_4 and z_5. */
osa_snow3g_initialize(K, IV, &snow_3g_context);
osa_snow3g_generate_key_stream(5, z, &snow_3g_context);
// printf ("z[0]:%08X\n",z[0]);
// printf ("z[1]:%08X\n",z[1]);
// printf ("z[2]:%08X\n",z[2]);
// printf ("z[3]:%08X\n",z[3]);
// printf ("z[4]:%08X\n",z[4]);
P = ((uint64_t)z[0] << 32) | (uint64_t)z[1];
Q = ((uint64_t)z[2] << 32) | (uint64_t)z[3];
// printf ("P:%16lX\n",P);
// printf ("Q:%16lX\n",Q);
/* Calculation */
D = ceil(stream_cipher->blength / 64.0) + 1;
// printf ("D:%d\n",D);
EVAL = 0;
c = 0x1b;
/* for 0 <= i <= D-3 */
for (i = 0; i < D - 2; i++) {
V = EVAL ^ ((uint64_t)hton_int32(message[2 * i]) << 32 | (uint64_t)hton_int32(message[2 * i + 1]));
EVAL = OSA_MUL64(V, P, c);
// printf ("Mi: %16X %16X\tEVAL: %16lX\n",hton_int32(message[2*i]),hton_int32(message[2*i+1]), EVAL);
}
/* for D-2 */
rem_bits = stream_cipher->blength % 64;
if (rem_bits == 0)
rem_bits = 64;
mask = osa_mask32bit(rem_bits % 32);
if (rem_bits > 32) {
M_D_2 = ((uint64_t)hton_int32(message[2 * (D - 2)]) << 32) | (uint64_t)(hton_int32(message[2 * (D - 2) + 1]) & mask);
} else {
M_D_2 = ((uint64_t)hton_int32(message[2 * (D - 2)]) & mask) << 32;
}
V = EVAL ^ M_D_2;
EVAL = OSA_MUL64(V, P, c);
/* for D-1 */
EVAL ^= stream_cipher->blength;
/* Multiply by Q */
EVAL = OSA_MUL64(EVAL, Q, c);
MAC_I = (uint32_t)(EVAL >> 32) ^ z[4];
// printf ("MAC_I:%16X\n",MAC_I);
MAC_I = hton_int32(MAC_I);
memcpy(out, &MAC_I, 4);
return 0;
}
int stream_compute_integrity_eia2(stream_cipher_t *stream_cipher, uint8_t out[4])
{
DevAssert(stream_cipher != NULL);
;
DevAssert((stream_cipher->blength & 0x7) == 0);
DevAssert(stream_cipher->key_length == 16 && "k_iv.key and stream_cipher mismatch");
DevAssert(stream_cipher->bearer < 32);
DevAssert(stream_cipher->direction < 2);
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);
const size_t m_length = stream_cipher->blength >> 3;
uint8_t result[16] = {0};
byte_array_t msg = {.len = m_length, .buf = stream_cipher->message };
aes_128_cbc_cmac(&k_iv, msg, sizeof(result), result);
memcpy(out, result, 4);
return 0;
}
int stream_compute_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t out[4])
{
if (algorithm == EIA1_128_ALG_ID) {
LOG_D(OSA, "EIA1 algorithm applied for integrity\n");
return stream_compute_integrity_eia1(stream_cipher, out);
} else if (algorithm == EIA2_128_ALG_ID) {
LOG_D(OSA, "EIA2 algorithm applied for integrity\n");
return stream_compute_integrity_eia2(stream_cipher, out);
}
LOG_E(OSA, "Provided integrity algorithm is currently not supported = %u\n", algorithm);
return -1;
}
int stream_check_integrity(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t *expected)
{
uint8_t result[4];
if (algorithm != EIA0_ALG_ID) {
if (stream_compute_integrity(algorithm, stream_cipher, result) != 0) {
return -1;
}
if (memcmp(result, expected, 4) != 0) {
LOG_E(OSA,
"Mismatch found in integrity for algorithm %u,\n"
"\tgot %02x.%02x.%02x.%02x, expecting %02x.%02x.%02x.%02x\n",
algorithm,
result[0],
result[1],
result[2],
result[3],
expected[0],
expected[1],
expected[2],
expected[3]);
return -1;
}
}
/* Integrity verification succeeded */
return 0;
}