/**
 *
 * \section COPYRIGHT
 *
 * Copyright 2014      Ben Wojtowicz
 *           2016-2020 Software Radio Systems Limited
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the distribution.
 *
 */

/*******************************************************************************
                              INCLUDES
*******************************************************************************/

#include "srsran/common/liblte_security.h"
#include "math.h"
#include "srsran/common/s3g.h"
#include "srsran/common/ssl.h"
#include "srsran/common/zuc.h"

#include <arpa/inet.h>

/*******************************************************************************
                              LOCAL FUNCTION PROTOTYPES
*******************************************************************************/

/*********************************************************************
    Name: zero_tailing_bits

    Description: Fill tailing bits with zeros.

    Document Reference: -
*********************************************************************/
void zero_tailing_bits(uint8* data, uint32 length_bits);

/*******************************************************************************
                              FUNCTIONS
*******************************************************************************/

/*********************************************************************
    Name: liblte_security_generate_k_asme

    Description: Generate the security key Kasme.

    Document Reference: 33.401 v10.0.0 Annex A.2
*********************************************************************/
LIBLTE_ERROR_ENUM
liblte_security_generate_k_asme(uint8* ck, uint8* ik, uint8* ak, uint8* sqn, uint16 mcc, uint16 mnc, uint8* k_asme)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint32            i;
  uint8             s[14];
  uint8             key[32];

  if (ck != NULL && ik != NULL && ak != NULL && sqn != NULL && k_asme != NULL) {
    // Construct S
    s[0] = 0x10;                                   // FC
    s[1] = (mcc & 0x00F0) | ((mcc & 0x0F00) >> 8); // First byte of P0
    if ((mnc & 0xFF00) == 0xFF00) {
      // 2-digit MNC
      s[2] = 0xF0 | (mcc & 0x000F);                         // Second byte of P0
      s[3] = ((mnc & 0x000F) << 4) | ((mnc & 0x00F0) >> 4); // Third byte of P0
    } else {
      // 3-digit MNC
      s[2] = ((mnc & 0x000F) << 4) | (mcc & 0x000F);   // Second byte of P0
      s[3] = ((mnc & 0x00F0)) | ((mnc & 0x0F00) >> 8); // Third byte of P0
    }
    s[4] = 0x00; // First byte of L0
    s[5] = 0x03; // Second byte of L0
    for (i = 0; i < 6; i++) {
      s[6 + i] = sqn[i] ^ ak[i]; // P1
    }
    s[12] = 0x00; // First byte of L1
    s[13] = 0x06; // Second byte of L1

    // Construct Key
    for (i = 0; i < 16; i++) {
      key[i]      = ck[i];
      key[16 + i] = ik[i];
    }

    // Derive Kasme
    sha256(key, 32, s, 14, k_asme, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_generate_k_enb

    Description: Generate the security key Kenb.

    Document Reference: 33.401 v10.0.0 Annex A.2
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8* k_asme, uint32 nas_count, uint8* k_enb)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_asme != NULL && k_enb != NULL) {
    // Construct S
    s[0] = 0x11;                     // FC
    s[1] = (nas_count >> 24) & 0xFF; // First byte of P0
    s[2] = (nas_count >> 16) & 0xFF; // Second byte of P0
    s[3] = (nas_count >> 8) & 0xFF;  // Third byte of P0
    s[4] = nas_count & 0xFF;         // Fourth byte of P0
    s[5] = 0x00;                     // First byte of L0
    s[6] = 0x04;                     // Second byte of L0

    // Derive Kenb
    sha256(k_asme, 32, s, 7, k_enb, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_generate_res_star(uint8_t*    ck,
                                                    uint8_t*    ik,
                                                    const char* serving_network_name,
                                                    uint8_t*    rand,
                                                    uint8_t*    res,
                                                    size_t      res_len,
                                                    uint8_t*    res_star)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8_t           key[32];
  uint8_t*          s;

  if (ck != NULL && ik != NULL && serving_network_name != NULL && rand != NULL && res != NULL && res_star != NULL) {
    // Construct S
    uint16_t ssn_length  = strlen(serving_network_name);
    uint16_t rand_length = 16;
    uint32_t s_len       = 1 + ssn_length + 2 + rand_length + 2 + res_len + 2;

    uint8_t output[32] = {};

    s = (uint8_t*)calloc(s_len, sizeof(uint8_t));
    if (s == nullptr) {
      return err;
    }

    uint32_t i = 0;
    s[i]       = 0x6B; // FC
    i++;

    // SSN
    memcpy(&s[i], serving_network_name, strlen(serving_network_name));
    i += ssn_length;
    uint16_t ssn_length_value = htons(ssn_length);
    memcpy(&s[i], &ssn_length_value, sizeof(ssn_length));
    i += sizeof(ssn_length_value);

    // RAND
    memcpy(&s[i], rand, rand_length);
    i += rand_length;
    uint16_t rand_length_value = htons(rand_length);
    memcpy(&s[i], &rand_length_value, sizeof(rand_length));
    i += sizeof(rand_length_value);

    // RES
    memcpy(&s[i], res, res_len);
    i += res_len;
    uint16_t res_length_value = htons(res_len);
    memcpy(&s[i], &res_length_value, sizeof(res_length_value));
    i += sizeof(res_length_value);

    // The input key Key shall be equal to the concatenation CK || IK of CK and IK.
    memcpy(key, ck, 16);
    memcpy(key + 16, ik, 16);

    // Derive output
    sha256(key, 32, s, s_len, output, 0);
    memcpy(res_star, output + 16, 16);

    free(s);
    err = LIBLTE_SUCCESS;
  }
  return (err);
}

/*********************************************************************
    Name: liblte_security_generate_k_enb_star

    Description: Generate the security key Kenb*.

    Document Reference: 33.401 v10.0.0 Annex A.5
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8* k_enb, uint32 pci, uint32_t earfcn, uint8* k_enb_star)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[9];

  if (k_enb_star != NULL && k_enb != NULL) {
    // Construct S
    s[0] = 0x13;                 // FC
    s[1] = (pci >> 8) & 0xFF;    // First byte of P0
    s[2] = pci & 0xFF;           // Second byte of P0
    s[3] = 0x00;                 // First byte of L0
    s[4] = 0x02;                 // Second byte of L0
    s[5] = (earfcn >> 8) & 0xFF; // First byte of P0
    s[6] = earfcn & 0xFF;        // Second byte of P0
    s[7] = 0x00;                 // First byte of L0
    s[8] = 0x02;                 // Second byte of L0

    // Derive Kenb
    sha256(k_enb, 32, s, 9, k_enb_star, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_generate_nh(uint8_t* k_asme, uint8_t* sync, uint8_t* nh)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[35];

  if (k_asme != NULL && sync != NULL && nh != NULL) {
    // Construct S
    s[0] = 0x12; // FC
    for (int i = 0; i < 32; i++) {
      s[1 + i] = sync[i];
    }
    s[33] = 0x00; // First byte of L0
    s[34] = 0x20, // Second byte of L0

        // Derive NH
        sha256(k_asme, 32, s, 35, nh, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_generate_k_nas

    Description: Generate the NAS security keys KNASenc and KNASint.

    Document Reference: 33.401 v10.0.0 Annex A.2
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8*                                      k_asme,
                                                 LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
                                                 LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
                                                 uint8*                                      k_nas_enc,
                                                 uint8*                                      k_nas_int)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_asme != NULL && k_nas_enc != NULL) {
    // Construct S for KNASenc
    s[0] = 0x15;       // FC
    s[1] = 0x01;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = enc_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KNASenc
    sha256(k_asme, 32, s, 7, k_nas_enc, 0);
  }

  if (k_asme != NULL && k_nas_int != NULL) {
    // Construct S for KNASint
    s[0] = 0x15;       // FC
    s[1] = 0x02;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = int_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KNASint
    sha256(k_asme, 32, s, 7, k_nas_int, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_generate_k_rrc

    Description: Generate the RRC security keys KRRCenc and KRRCint.

    Document Reference: 33.401 v10.0.0 Annex A.2
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_rrc(uint8*                                      k_enb,
                                                 LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
                                                 LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
                                                 uint8*                                      k_rrc_enc,
                                                 uint8*                                      k_rrc_int)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_enb != NULL && k_rrc_enc != NULL && k_rrc_int != NULL) {
    // Construct S for KRRCenc
    s[0] = 0x15;       // FC
    s[1] = 0x03;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = enc_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KRRCenc
    sha256(k_enb, 32, s, 7, k_rrc_enc, 0);

    // Construct S for KRRCint
    s[0] = 0x15;       // FC
    s[1] = 0x04;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = int_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KRRCint
    sha256(k_enb, 32, s, 7, k_rrc_int, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_generate_k_nr_rrc(uint8*                                      k_gnb,
                                                    LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
                                                    LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
                                                    uint8*                                      k_rrc_enc,
                                                    uint8*                                      k_rrc_int)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_gnb != NULL && k_rrc_enc != NULL && k_rrc_int != NULL) {
    // Construct S for KRRCenc
    s[0] = 0x69;       // FC
    s[1] = 0x03;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = enc_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KRRCenc
    sha256(k_gnb, 32, s, 7, k_rrc_enc, 0);

    // Construct S for KRRCint
    s[0] = 0x69;       // FC
    s[1] = 0x04;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = int_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KRRCint
    sha256(k_gnb, 32, s, 7, k_rrc_int, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_generate_k_nr_up(uint8*                                      k_gnb,
                                                   LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
                                                   LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
                                                   uint8*                                      k_up_enc,
                                                   uint8*                                      k_up_int)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_gnb != NULL && k_up_enc != NULL && k_up_int != NULL) {
    // Construct S for KUPenc
    s[0] = 0x69;       // FC
    s[1] = 0x05;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = enc_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KUPenc
    sha256(k_gnb, 32, s, 7, k_up_enc, 0);

    // Construct S for KUPint
    s[0] = 0x69;       // FC
    s[1] = 0x06;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = int_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KUPint
    sha256(k_gnb, 32, s, 7, k_up_int, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_generate_sk_gnb

    Description: Derivation of S-KeNB or S-KgNB for dual connectivity.

    Document Reference: 33.401 v10.0.0 Annex A.15
*********************************************************************/

LIBLTE_ERROR_ENUM liblte_security_generate_sk_gnb(uint8_t* k_enb, uint8_t* sk_gnb, uint16_t scg_counter)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[5];

  if (k_enb != NULL && sk_gnb != NULL) {
    // Construct S for sk_gnb
    s[0] = 0x1C;                      // FC
    s[1] = (scg_counter >> 8) & 0xFF; // first byte of P0
    s[2] = scg_counter & 0xFF;        // second byte of P0
    s[3] = 0x00;                      // First byte of L0
    s[4] = 0x02;                      // Second byte of L0

    // Derive sk_gnb
    sha256(k_enb, 32, s, 5, sk_gnb, 0);
    err = LIBLTE_SUCCESS;
  }

  return (err);
}
/*********************************************************************
    Name: liblte_security_generate_k_up

    Description: Generate the user plane security keys KUPenc and
                 KUPint.

    Document Reference: 33.401 v10.0.0 Annex A.2
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_generate_k_up(uint8*                                      k_enb,
                                                LIBLTE_SECURITY_CIPHERING_ALGORITHM_ID_ENUM enc_alg_id,
                                                LIBLTE_SECURITY_INTEGRITY_ALGORITHM_ID_ENUM int_alg_id,
                                                uint8*                                      k_up_enc,
                                                uint8*                                      k_up_int)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             s[7];

  if (k_enb != NULL && k_up_enc != NULL && k_up_int != NULL) {
    // Construct S for KUPenc
    s[0] = 0x15;       // FC
    s[1] = 0x05;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = enc_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KUPenc
    sha256(k_enb, 32, s, 7, k_up_enc, 0);

    // Construct S for KUPint
    s[0] = 0x15;       // FC
    s[1] = 0x06;       // P0
    s[2] = 0x00;       // First byte of L0
    s[3] = 0x01;       // Second byte of L0
    s[4] = int_alg_id; // P1
    s[5] = 0x00;       // First byte of L1
    s[6] = 0x01;       // Second byte of L1

    // Derive KUPint
    sha256(k_enb, 32, s, 7, k_up_int, 0);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_128_eia1(const uint8* key,
                                           uint32       count,
                                           uint8        bearer,
                                           uint8        direction,
                                           uint8*       msg,
                                           uint32       msg_len,
                                           uint8*       mac)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;

  if (key != NULL && msg != NULL && mac != NULL) {
    uint32_t msg_len_bits = 0;
    uint32_t i            = 0;
    uint8_t* m_ptr;

    msg_len_bits = msg_len * 8;
    m_ptr        = s3g_f9(key, count, bearer << 27, direction, msg, msg_len_bits);
    for (i = 0; i < 4; i++) {
      mac[i] = m_ptr[i];
    }
    err = LIBLTE_SUCCESS;
  }
  return (err);
}

/*********************************************************************
    Name: liblte_security_128_eia2

    Description: 128-bit integrity algorithm EIA2.

    Document Reference: 33.401 v10.0.0 Annex B.2.3
                        33.102 v10.0.0 Section 6.5.4
                        RFC4493
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_128_eia2(const uint8* key,
                                           uint32       count,
                                           uint8        bearer,
                                           uint8        direction,
                                           uint8*       msg,
                                           uint32       msg_len,
                                           uint8*       mac)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint8             M[msg_len + 8 + 16];
  aes_context       ctx;
  uint32            i;
  uint32            j;
  uint32            n;
  uint32            pad_bits;
  uint8             const_zero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  uint8             L[16];
  uint8             K1[16];
  uint8             K2[16];
  uint8             T[16];
  uint8             tmp[16];

  if (key != NULL && msg != NULL && mac != NULL) {
    // Subkey L generation
    aes_setkey_enc(&ctx, key, 128);
    aes_crypt_ecb(&ctx, AES_ENCRYPT, const_zero, L);

    // Subkey K1 generation
    for (i = 0; i < 15; i++) {
      K1[i] = (L[i] << 1) | ((L[i + 1] >> 7) & 0x01);
    }
    K1[15] = L[15] << 1;
    if (L[0] & 0x80) {
      K1[15] ^= 0x87;
    }

    // Subkey K2 generation
    for (i = 0; i < 15; i++) {
      K2[i] = (K1[i] << 1) | ((K1[i + 1] >> 7) & 0x01);
    }
    K2[15] = K1[15] << 1;
    if (K1[0] & 0x80) {
      K2[15] ^= 0x87;
    }

    // Construct M
    memset(M, 0, msg_len + 8 + 16);
    M[0] = (count >> 24) & 0xFF;
    M[1] = (count >> 16) & 0xFF;
    M[2] = (count >> 8) & 0xFF;
    M[3] = count & 0xFF;
    M[4] = (bearer << 3) | (direction << 2);
    for (i = 0; i < msg_len; i++) {
      M[8 + i] = msg[i];
    }

    // MAC generation
    n = (uint32)(ceilf((float)(msg_len + 8) / (float)(16)));
    for (i = 0; i < 16; i++) {
      T[i] = 0;
    }
    for (i = 0; i < n - 1; i++) {
      for (j = 0; j < 16; j++) {
        tmp[j] = T[j] ^ M[i * 16 + j];
      }
      aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
    }
    pad_bits = ((msg_len * 8) + 64) % 128;
    if (pad_bits == 0) {
      for (j = 0; j < 16; j++) {
        tmp[j] = T[j] ^ K1[j] ^ M[i * 16 + j];
      }
      aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
    } else {
      pad_bits = (128 - pad_bits) - 1;
      M[i * 16 + (15 - (pad_bits / 8))] |= 0x1 << (pad_bits % 8);
      for (j = 0; j < 16; j++) {
        tmp[j] = T[j] ^ K2[j] ^ M[i * 16 + j];
      }
      aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
    }

    for (i = 0; i < 4; i++) {
      mac[i] = T[i];
    }

    err = LIBLTE_SUCCESS;
  }

  return (err);
}
LIBLTE_ERROR_ENUM liblte_security_128_eia2(const uint8*           key,
                                           uint32                 count,
                                           uint8                  bearer,
                                           uint8                  direction,
                                           LIBLTE_BIT_MSG_STRUCT* msg,
                                           uint8*                 mac)
{
  if (!key || !msg || !mac) {
    return LIBLTE_ERROR_INVALID_INPUTS;
  }

  uint8       M[msg->N_bits * 8 + 8 + 16];
  aes_context ctx;
  uint32      i;
  uint32      j;
  uint32      n;
  uint32      pad_bits;
  uint8       const_zero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  uint8       L[16];
  uint8       K1[16];
  uint8       K2[16];
  uint8       T[16];
  uint8       tmp[16];

  // Subkey L generation
  aes_setkey_enc(&ctx, key, 128);
  aes_crypt_ecb(&ctx, AES_ENCRYPT, const_zero, L);

  // Subkey K1 generation
  for (i = 0; i < 15; i++) {
    K1[i] = (L[i] << 1) | ((L[i + 1] >> 7) & 0x01);
  }
  K1[15] = L[15] << 1;
  if (L[0] & 0x80) {
    K1[15] ^= 0x87;
  }

  // Subkey K2 generation
  for (i = 0; i < 15; i++) {
    K2[i] = (K1[i] << 1) | ((K1[i + 1] >> 7) & 0x01);
  }
  K2[15] = K1[15] << 1;
  if (K1[0] & 0x80) {
    K2[15] ^= 0x87;
  }

  // Construct M
  memset(M, 0, msg->N_bits * 8 + 8 + 16);
  M[0] = (count >> 24) & 0xFF;
  M[1] = (count >> 16) & 0xFF;
  M[2] = (count >> 8) & 0xFF;
  M[3] = count & 0xFF;
  M[4] = (bearer << 3) | (direction << 2);
  for (i = 0; i < msg->N_bits / 8; i++) {
    M[8 + i] = 0;
    for (j = 0; j < 8; j++) {
      M[8 + i] |= msg->msg[i * 8 + j] << (7 - j);
    }
  }
  if ((msg->N_bits % 8) != 0) {
    M[8 + i] = 0;
    for (j = 0; j < msg->N_bits % 8; j++) {
      M[8 + i] |= msg->msg[i * 8 + j] << (7 - j);
    }
  }

  // MAC generation
  n = (uint32)(ceilf((float)(msg->N_bits + 64) / (float)(128)));
  for (i = 0; i < 16; i++) {
    T[i] = 0;
  }
  for (i = 0; i < n - 1; i++) {
    for (j = 0; j < 16; j++) {
      tmp[j] = T[j] ^ M[i * 16 + j];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
  }
  pad_bits = (msg->N_bits + 64) % 128;
  if (pad_bits == 0) {
    for (j = 0; j < 16; j++) {
      tmp[j] = T[j] ^ K1[j] ^ M[i * 16 + j];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
  } else {
    pad_bits = (128 - pad_bits) - 1;
    M[i * 16 + (15 - (pad_bits / 8))] |= 0x1 << (pad_bits % 8);
    for (j = 0; j < 16; j++) {
      tmp[j] = T[j] ^ K2[j] ^ M[i * 16 + j];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, tmp, T);
  }

  for (i = 0; i < 4; i++) {
    mac[i] = T[i];
  }

  return LIBLTE_SUCCESS;
}

uint32_t GET_WORD(uint32_t* DATA, uint32_t i)
{
  uint32_t WORD, ti;
  ti = i % 32;
  if (ti == 0)
    WORD = DATA[i / 32];
  else
    WORD = (DATA[i / 32] << ti) | (DATA[i / 32 + 1] >> (32 - ti));
  return WORD;
}

uint8_t GET_BIT(uint8_t* DATA, uint32_t i)
{
  return (DATA[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
}

LIBLTE_ERROR_ENUM liblte_security_128_eia3(const uint8* key,
                                           uint32       count,
                                           uint8        bearer,
                                           uint8        direction,
                                           uint8*       msg,
                                           uint32       msg_len,
                                           uint8*       mac)

{
  LIBLTE_ERROR_ENUM err    = LIBLTE_ERROR_INVALID_INPUTS;
  uint8_t           iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  uint32* ks;
  uint32  msg_len_block_8, msg_len_block_32, m;

  if (key != NULL && msg != NULL && mac != NULL) {
    msg_len_block_8  = (msg_len + 7) / 8;
    msg_len_block_32 = (msg_len + 31) / 32;

    // Construct iv
    iv[0] = (count >> 24) & 0xFF;
    iv[1] = (count >> 16) & 0xFF;
    iv[2] = (count >> 8) & 0xFF;
    iv[3] = count & 0xFF;

    iv[4] = (bearer << 3) & 0xF8;
    iv[5] = iv[6] = iv[7] = 0;

    iv[8]  = ((count >> 24) & 0xFF) ^ ((direction & 1) << 7);
    iv[9]  = (count >> 16) & 0xFF;
    iv[10] = (count >> 8) & 0xFF;
    iv[11] = count & 0xFF;

    iv[12] = iv[4];
    iv[13] = iv[5];
    iv[14] = iv[6] ^ ((direction & 1) << 7);
    iv[15] = iv[7];

    zuc_state_t zuc_state;
    // Initialize keystream
    zuc_initialize(&zuc_state, key, iv);

    // Generate keystream
    int N = msg_len + 64;
    int L = (N + 31) / 32;

    ks = (uint32*)calloc(L, sizeof(uint32));

    zuc_generate_keystream(&zuc_state, L, ks);

    uint32_t T = 0;
    for (uint32_t i = 0; i < msg_len; i++) {
      if (GET_BIT(msg, i)) {
        T ^= GET_WORD(ks, i);
      }
    }

    T ^= GET_WORD(ks, msg_len);

    uint32_t mac_tmp = T ^ ks[L - 1];
    mac[0]           = (mac_tmp >> 24) & 0xFF;
    mac[1]           = (mac_tmp >> 16) & 0xFF;
    mac[2]           = (mac_tmp >> 8) & 0xFF;
    mac[3]           = mac_tmp & 0xFF;

    free(ks);
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_encryption_eea1

    Description: 128-bit encryption algorithm EEA1.

    Document Reference: 33.401 v13.1.0 Annex B.1.2
                        35.215 v13.0.0 References
                        Specification of the 3GPP Confidentiality and
                            Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* msg,
                                                  uint32 msg_len,
                                                  uint8* out)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  S3G_STATE         state, *state_ptr;
  uint32            k[]  = {0, 0, 0, 0};
  uint32            iv[] = {0, 0, 0, 0};
  uint32*           ks;
  int32             i;
  uint32            msg_len_block_8, msg_len_block_32, m;

  if (key != NULL && msg != NULL && out != NULL) {
    state_ptr        = &state;
    msg_len_block_8  = (msg_len + 7) / 8;
    msg_len_block_32 = (msg_len + 31) / 32;

    // Transform key
    for (i = 3; i >= 0; i--) {
      k[i] = (key[4 * (3 - i) + 0] << 24) | (key[4 * (3 - i) + 1] << 16) | (key[4 * (3 - i) + 2] << 8) |
             (key[4 * (3 - i) + 3]);
    }

    // Construct iv
    iv[3] = count;
    iv[2] = ((bearer & 0x1F) << 27) | ((direction & 0x01) << 26);
    iv[1] = iv[3];
    iv[0] = iv[2];

    // Initialize keystream
    s3g_initialize(state_ptr, k, iv);

    // Generate keystream

    ks = (uint32*)calloc(msg_len_block_32, sizeof(uint32));
    s3g_generate_keystream(state_ptr, msg_len_block_32, ks);

    // Generate output except last block
    for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
      out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF);
      out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF);
      out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF);
      out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF));
    }

    // Process last bytes
    for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
      out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF);
    }

    // Zero tailing bits
    zero_tailing_bits(out, msg_len);

    // Clean up
    free(ks);
    s3g_deinitialize(state_ptr);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_decryption_eea1

    Description: 128-bit decryption algorithm EEA1.

    Document Reference: 33.401 v13.1.0 Annex B.1.2
                        35.215 v13.0.0 References
                        Specification of the 3GPP Confidentiality and
                            Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* ct,
                                                  uint32 ct_len,
                                                  uint8* out)
{
  return liblte_security_encryption_eea1(key, count, bearer, direction, ct, ct_len, out);
}

/*********************************************************************
    Name: liblte_security_encryption_eea2

    Description: 128-bit encryption algorithm EEA2.

    Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* msg,
                                                  uint32 msg_len,
                                                  uint8* out)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  aes_context       ctx;
  unsigned char     stream_blk[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  unsigned char     nonce_cnt[16]  = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  int32             i;
  int               ret;
  size_t            nc_off = 0;

  if (key != NULL && msg != NULL && out != NULL) {
    ret = aes_setkey_enc(&ctx, key, 128);

    if (ret == 0) {
      // Construct nonce
      nonce_cnt[0] = (count >> 24) & 0xFF;
      nonce_cnt[1] = (count >> 16) & 0xFF;
      nonce_cnt[2] = (count >> 8) & 0xFF;
      nonce_cnt[3] = (count)&0xFF;
      nonce_cnt[4] = ((bearer & 0x1F) << 3) | ((direction & 0x01) << 2);

      // Encryption
      ret = aes_crypt_ctr(&ctx, (msg_len + 7) / 8, &nc_off, nonce_cnt, stream_blk, msg, out);
    }

    if (ret == 0) {
      // Zero tailing bits
      zero_tailing_bits(out, msg_len);
      err = LIBLTE_SUCCESS;
    }
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_decryption_eea2

    Description: 128-bit decryption algorithm EEA2.

    Document Reference: 33.401 v13.1.0 Annex B.1.3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* ct,
                                                  uint32 ct_len,
                                                  uint8* out)
{
  return liblte_security_encryption_eea2(key, count, bearer, direction, ct, ct_len, out);
}

/*********************************************************************
    Name: liblte_security_encryption_eea1

    Description: 128-bit encryption algorithm EEA1.

    Document Reference: 33.401 v13.1.0 Annex B.1.2
                        35.215 v13.0.0 References
                        Specification of the 3GPP Confidentiality and
                            Integrity Algorithms UEA2 & UIA2 D1 v2.1
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_encryption_eea3(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* msg,
                                                  uint32 msg_len,
                                                  uint8* out)
{
  LIBLTE_ERROR_ENUM err    = LIBLTE_ERROR_INVALID_INPUTS;
  uint8_t           iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  uint32* ks;
  int32   i;
  uint32  msg_len_block_8, msg_len_block_32, m;

  if (key != NULL && msg != NULL && out != NULL) {
    msg_len_block_8  = (msg_len + 7) / 8;
    msg_len_block_32 = (msg_len + 31) / 32;

    // Construct iv
    iv[0]  = (count >> 24) & 0xFF;
    iv[1]  = (count >> 16) & 0xFF;
    iv[2]  = (count >> 8) & 0xFF;
    iv[3]  = (count)&0xFF;
    iv[4]  = ((bearer & 0x1F) << 3) | ((direction & 0x01) << 2);
    iv[5]  = 0;
    iv[6]  = 0;
    iv[7]  = 0;
    iv[8]  = iv[0];
    iv[9]  = iv[1];
    iv[10] = iv[2];
    iv[11] = iv[3];
    iv[12] = iv[4];
    iv[13] = iv[5];
    iv[14] = iv[6];
    iv[15] = iv[7];

    zuc_state_t zuc_state;
    // Initialize keystream
    zuc_initialize(&zuc_state, key, iv);

    // Generate keystream

    ks = (uint32*)calloc(msg_len_block_32, sizeof(uint32));
    zuc_generate_keystream(&zuc_state, msg_len_block_32, ks);

    // Generate output except last block
    for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
      out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF);
      out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF);
      out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF);
      out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF));
    }

    // Process last bytes
    for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
      out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF);
    }

    // Zero tailing bits
    zero_tailing_bits(out, msg_len);

    // Clean up
    free(ks);
    // zuc_deinitialize(state_ptr);

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

LIBLTE_ERROR_ENUM liblte_security_decryption_eea3(uint8* key,
                                                  uint32 count,
                                                  uint8  bearer,
                                                  uint8  direction,
                                                  uint8* msg,
                                                  uint32 msg_len,
                                                  uint8* out)
{
  return liblte_security_encryption_eea3(key, count, bearer, direction, msg, msg_len, out);
}

/*********************************************************************
    Name: liblte_security_milenage_f1

    Description: Milenage security function F1.  Computes network
                 authentication code MAC-A from key K, random
                 challenge RAND, sequence number SQN, and
                 authentication management field AMF.

    Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f1(uint8* k, uint8* op_c, uint8* rand, uint8* sqn, uint8* amf, uint8* mac_a)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint32            i;
  aes_context       ctx;
  uint8             temp[16];
  uint8             in1[16];
  uint8             out1[16];
  uint8             input[16];

  if (k != NULL && op_c != NULL && rand != NULL && sqn != NULL && amf != NULL && mac_a != NULL) {
    // Initialize the round keys
    aes_setkey_enc(&ctx, k, 128);

    // Compute temp
    for (i = 0; i < 16; i++) {
      input[i] = rand[i] ^ op_c[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, temp);

    // Construct in1
    for (i = 0; i < 6; i++) {
      in1[i]     = sqn[i];
      in1[i + 8] = sqn[i];
    }
    for (i = 0; i < 2; i++) {
      in1[i + 6]  = amf[i];
      in1[i + 14] = amf[i];
    }

    // Compute out1
    for (i = 0; i < 16; i++) {
      input[(i + 8) % 16] = in1[i] ^ op_c[i];
    }
    for (i = 0; i < 16; i++) {
      input[i] ^= temp[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out1);
    for (i = 0; i < 16; i++) {
      out1[i] ^= op_c[i];
    }

    // Return MAC-A
    for (i = 0; i < 8; i++) {
      mac_a[i] = out1[i];
    }

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_milenage_f1_star

    Description: Milenage security function F1*.  Computes resynch
                 authentication code MAC-S from key K, random
                 challenge RAND, sequence number SQN, and
                 authentication management field AMF.

    Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM
liblte_security_milenage_f1_star(uint8* k, uint8* op_c, uint8* rand, uint8* sqn, uint8* amf, uint8* mac_s)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  aes_context       ctx;
  uint32            i;
  uint8             temp[16];
  uint8             in1[16];
  uint8             out1[16];
  uint8             input[16];

  if (k != NULL && op_c != NULL && rand != NULL && sqn != NULL && amf != NULL && mac_s != NULL) {
    // Initialize the round keys
    aes_setkey_enc(&ctx, k, 128);

    // Compute temp
    for (i = 0; i < 16; i++) {
      input[i] = rand[i] ^ op_c[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, temp);
    // Construct in1
    for (i = 0; i < 6; i++) {
      in1[i]     = sqn[i];
      in1[i + 8] = sqn[i];
    }
    for (i = 0; i < 2; i++) {
      in1[i + 6]  = amf[i];
      in1[i + 14] = amf[i];
    }

    // Compute out1
    for (i = 0; i < 16; i++) {
      input[(i + 8) % 16] = in1[i] ^ op_c[i];
    }
    for (i = 0; i < 16; i++) {
      input[i] ^= temp[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out1);
    for (i = 0; i < 16; i++) {
      out1[i] ^= op_c[i];
    }

    // Return MAC-S
    for (i = 0; i < 8; i++) {
      mac_s[i] = out1[i + 8];
    }

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_milenage_f2345

    Description: Milenage security functions F2, F3, F4, and F5.
                 Computes response RES, confidentiality key CK,
                 integrity key IK, and anonymity key AK from random
                 challenge RAND.

    Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM
liblte_security_milenage_f2345(uint8* k, uint8* op_c, uint8* rand, uint8* res, uint8* ck, uint8* ik, uint8* ak)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  uint32            i;
  uint8             temp[16];
  uint8             out[16];
  uint8             input[16];
  aes_context       ctx;

  if (k != NULL && op_c != NULL && rand != NULL && res != NULL && ck != NULL && ik != NULL && ak != NULL) {
    // Initialize the round keys
    aes_setkey_enc(&ctx, k, 128);
    // Compute temp
    for (i = 0; i < 16; i++) {
      input[i] = rand[i] ^ op_c[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, temp);
    // Compute out for RES and AK
    for (i = 0; i < 16; i++) {
      input[i] = temp[i] ^ op_c[i];
    }
    input[15] ^= 1;
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out);
    for (i = 0; i < 16; i++) {
      out[i] ^= op_c[i];
    }

    // Return RES
    for (i = 0; i < 8; i++) {
      res[i] = out[i + 8];
    }

    // Return AK
    for (i = 0; i < 6; i++) {
      ak[i] = out[i];
    }

    // Compute out for CK
    for (i = 0; i < 16; i++) {
      input[(i + 12) % 16] = temp[i] ^ op_c[i];
    }
    input[15] ^= 2;
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out);
    for (i = 0; i < 16; i++) {
      out[i] ^= op_c[i];
    }

    // Return CK
    for (i = 0; i < 16; i++) {
      ck[i] = out[i];
    }

    // Compute out for IK
    for (i = 0; i < 16; i++) {
      input[(i + 8) % 16] = temp[i] ^ op_c[i];
    }
    input[15] ^= 4;
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out);
    for (i = 0; i < 16; i++) {
      out[i] ^= op_c[i];
    }

    // Return IK
    for (i = 0; i < 16; i++) {
      ik[i] = out[i];
    }

    err = LIBLTE_SUCCESS;
  }

  return (err);
}

/*********************************************************************
    Name: liblte_security_milenage_f5_star

    Description: Milenage security function F5*.  Computes resynch
                 anonymity key AK from key K and random challenge
                 RAND.

    Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_security_milenage_f5_star(uint8* k, uint8* op_c, uint8* rand, uint8* ak)
{
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
  aes_context       ctx;
  uint32            i;
  uint8             temp[16];
  uint8             out[16];
  uint8             input[16];

  if (k != NULL && op_c != NULL && rand != NULL && ak != NULL) {
    // Initialize the round keys
    aes_setkey_enc(&ctx, k, 128);

    // Compute temp
    for (i = 0; i < 16; i++) {
      input[i] = rand[i] ^ op_c[i];
    }
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, temp);
    // Compute out
    for (i = 0; i < 16; i++) {
      input[(i + 4) % 16] = temp[i] ^ op_c[i];
    }
    input[15] ^= 8;
    aes_crypt_ecb(&ctx, AES_ENCRYPT, input, out);
    for (i = 0; i < 16; i++) {
      out[i] ^= op_c[i];
    }

    // Return AK
    for (i = 0; i < 6; i++) {
      ak[i] = out[i];
    }
    err = LIBLTE_SUCCESS;
  }
  return (err);
}

/*********************************************************************
    Name: liblte_compute_opc

    Description: Computes OPc from OP and K.

    Document Reference: 35.206 v10.0.0 Annex 3
*********************************************************************/

LIBLTE_ERROR_ENUM liblte_compute_opc(uint8* k, uint8* op, uint8* op_c)
{
  uint32            i;
  aes_context       ctx;
  LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;

  if (k != NULL && op != NULL && op_c != NULL) {
    aes_setkey_enc(&ctx, k, 128);
    aes_crypt_ecb(&ctx, AES_ENCRYPT, op, op_c);
    for (i = 0; i < 16; i++) {
      op_c[i] ^= op[i];
    }
    err = LIBLTE_SUCCESS;
  }
  return err;
}

/*********************************************************************
    Name: zero_tailing_bits

    Description: Fill tailing bits with zeros.

    Document Reference: -
*********************************************************************/
void zero_tailing_bits(uint8* data, uint32 length_bits)
{
  uint8 bits = (8 - (length_bits & 0x07)) & 0x07;
  data[(length_bits + 7) / 8 - 1] &= (uint8)(0xFF << bits);
}
