OSA SECU harmonization
This commit is contained in:
@@ -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.
|
||||
@@ -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__ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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};
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user