uint8_t *sqn_ms_derive(const uint8_t const opc[16], uint8_t *key, uint8_t *auts, uint8_t *rand_p)
{
  /* AUTS = Conc(SQN MS ) || MAC-S
   * Conc(SQN MS ) = SQN MS ^ f5* (RAND)
   * MAC-S = f1* (SQN MS || RAND || AMF)
   */
  uint8_t  ak[6];
  uint8_t *conc_sqn_ms;
  uint8_t *mac_s;
  uint8_t  mac_s_computed[MAC_S_LENGTH];
  uint8_t *sqn_ms;
  uint8_t  amf[2] = { 0, 0 };
  int i;

  conc_sqn_ms = auts;
  mac_s = &auts[6];

  sqn_ms = malloc(SQN_LENGTH_OCTEST);

  /*if (hss_config.valid_opc == 0) {
    SetOP(hss_config.operator_key);
  }*/

  /* Derive AK from key and rand */
  f5star(opc, key, rand_p, ak);

  for (i = 0; i < 6; i++) {
    sqn_ms[i] = ak[i] ^ conc_sqn_ms[i];
  }

  print_buffer("sqn_ms_derive() KEY    : ", key, 16);
  print_buffer("sqn_ms_derive() RAND   : ", rand_p, 16);
  print_buffer("sqn_ms_derive() AUTS   : ", auts, 14);
  print_buffer("sqn_ms_derive() AK     : ", ak, 6);
  print_buffer("sqn_ms_derive() SQN_MS : ", sqn_ms, 6);
  print_buffer("sqn_ms_derive() MAC_S  : ", mac_s, 8);

  f1star(opc, key, rand_p, sqn_ms, amf, mac_s_computed);

  print_buffer("MAC_S +: ", mac_s_computed, 8);

  if (memcmp(mac_s_computed, mac_s, 8) != 0) {
    fprintf(stderr, "Failed to verify computed SQN_MS\n");
    free(sqn_ms);
    return NULL;
  }

  return sqn_ms;
}
static
void do_f4f5star(uint8_t *key, uint8_t *rand, uint8_t *op, uint8_t *f4_exp,
                 uint8_t *f5star_exp)
{
    uint8_t res_f2[8];
    uint8_t res_f5[6];
    uint8_t res_f3[16];
    uint8_t res_f4[16];
    uint8_t res_f5star[6];

    SetOPc(op);

    f2345(key, rand, res_f2, res_f3, res_f4, res_f5);
    if (compare_buffer(res_f4, 16, f4_exp, 16) != 0) {
        fail("Fail: f4");
    }
    f5star(key, rand, res_f5star);
    if (compare_buffer(res_f5star, 6, f5star_exp, 6) != 0) {
        fail("Fail: f5star");
    }
}
/****************************************************************************
 **                                                                        **
 ** Name:        usim_api_authenticate()                                   **
 **                                                                        **
 ** Description: Performs mutual authentication of the USIM to the network,**
 **              checking whether authentication token AUTN can be accep-  **
 **              ted. If so, returns an authentication response RES and    **
 **              the ciphering and integrity keys.                         **
 **              In case of synch failure, returns a re-synchronization    **
 **              token AUTS.                                               **
 **                                                                        **
 **              3GPP TS 31.102, section 7.1.1.1                           **
 **                                                                        **
 **              Authentication and key generating function algorithms are **
 **              specified in 3GPP TS 35.206.                              **
 **                                                                        **
 ** Inputs:      rand_pP:          Random challenge number                    **
 **              autn_pP:          Authentication token                       **
 **                             AUTN = (SQN xor AK) || AMF || MAC          **
 **                                         48          16     64 bits     **
 **              Others:        Security key                               **
 **                                                                        **
 ** Outputs:     auts_pP:          Re-synchronization token                   **
 **              res_pP:           Authentication response                    **
 **              ck_pP:            Ciphering key                              **
 **              ik_pP             Integrity key                              **
 **                                                                        **
 **              Return:        RETURNerror, RETURNok                      **
 **              Others:        None                                       **
 **                                                                        **
 ***************************************************************************/
int usim_api_authenticate(const OctetString* rand_pP, const OctetString* autn_pP,
                          OctetString* auts_pP, OctetString* res_pP,
                          OctetString* ck_pP, OctetString* ik_pP)
{
  LOG_FUNC_IN;

  int rc;
  int i;

  LOG_TRACE(DEBUG, "USIM-API  - rand :%s",dump_octet_string(rand_pP));
  LOG_TRACE(DEBUG, "USIM-API  - autn :%s",dump_octet_string(autn_pP));

  /* Compute the authentication response RES = f2K (RAND) */
  /* Compute the cipher key CK = f3K (RAND) */
  /* Compute the integrity key IK = f4K (RAND) */
  /* Compute the anonymity key AK = f5K (RAND) */
#define USIM_API_AK_SIZE 6
  u8 ak[USIM_API_AK_SIZE];
  f2345(_usim_api_k, rand_pP->value,
        res_pP->value, ck_pP->value, ik_pP->value, ak);
  LOG_TRACE(DEBUG, "USIM-API  - res(f2)  :%s",dump_octet_string(res_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ck(f3)   :%s",dump_octet_string(ck_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ik(f4)   :%s",dump_octet_string(ik_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ak(f5)   : %02X%02X%02X%02X%02X%02X",
            ak[0],ak[1],ak[2],ak[3],ak[4],ak[5]);

  /* Retrieve the sequence number SQN = (SQN ⊕ AK) ⊕ AK */
#define USIM_API_SQN_SIZE USIM_API_AK_SIZE
  u8 sqn[USIM_API_SQN_SIZE];

  for (i = 0; i < USIM_API_SQN_SIZE; i++) {
    sqn[i] = autn_pP->value[i] ^ ak[i];
  }

  LOG_TRACE(DEBUG, "USIM-API  - Retrieved SQN %02X%02X%02X%02X%02X%02X",
            sqn[0],sqn[1],sqn[2],sqn[3],sqn[4],sqn[5]);

  /* Compute XMAC = f1K (SQN || RAND || AMF) */
#define USIM_API_XMAC_SIZE 8
  u8 xmac[USIM_API_XMAC_SIZE];
  f1(_usim_api_k, rand_pP->value, sqn, &autn_pP->value[USIM_API_SQN_SIZE], xmac);
  LOG_TRACE(DEBUG,
            "USIM-API  - Computed XMAC %02X%02X%02X%02X%02X%02X%02X%02X",
            xmac[0],xmac[1],xmac[2],xmac[3],
            xmac[4],xmac[5],xmac[6],xmac[7]);

  /* Compare the XMAC with the MAC included in AUTN */
#define USIM_API_AMF_SIZE 2

  if ( memcmp(xmac, &autn_pP->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE],
              USIM_API_XMAC_SIZE) != 0 ) {
    LOG_TRACE(INFO,
              "USIM-API  - Comparing the XMAC with the MAC included in AUTN Failed");
    //LOG_FUNC_RETURN (RETURNerror);
  } else {
    LOG_TRACE(INFO,
              "USIM-API  - Comparing the XMAC with the MAC included in AUTN Succeeded");
  }

  /* Verify that the received sequence number SQN is in the correct range */
  rc = _usim_api_check_sqn(*(uint32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]);

  if (rc != RETURNok) {
    /* Synchronisation failure; compute the AUTS parameter */

    /* Concealed value of the counter SQNms in the USIM:
     * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */
    f5star(_usim_api_k, rand_pP->value, ak);

#define USIM_API_SQNMS_SIZE USIM_API_SQN_SIZE
    u8 sqn_ms[USIM_API_SQNMS_SIZE];
    memset(sqn_ms, 0, USIM_API_SQNMS_SIZE);
#define USIM_API_SQN_MS_SIZE  3

    for (i = 0; i < USIM_API_SQN_MS_SIZE; i++) {
#warning "LG:BUG HERE TODO"
      sqn_ms[USIM_API_SQNMS_SIZE - i] =
        ((uint8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQN_MS_SIZE - i];
    }

    u8 sqnms[USIM_API_SQNMS_SIZE];

    for (i = 0; i < USIM_API_SQNMS_SIZE; i++) {
      sqnms[i] = sqn_ms[i] ^ ak[i];
    }

    LOG_TRACE(DEBUG, "USIM-API  - SQNms %02X%02X%02X%02X%02X%02X",
              sqnms[0],sqnms[1],sqnms[2],sqnms[3],sqnms[4],sqnms[5]);

    /* Synchronisation message authentication code:
     * MACS = f1*K(SQNMS || RAND || AMF) */
#define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE
    u8 macs[USIM_API_MACS_SIZE];
    f1star(_usim_api_k, rand_pP->value, sqn_ms,
           &rand_pP->value[USIM_API_SQN_SIZE], macs);
    LOG_TRACE(DEBUG, "USIM-API  - MACS %02X%02X%02X%02X%02X%02X%02X%02X",
              macs[0],macs[1],macs[2],macs[3],
              macs[4],macs[5],macs[6],macs[7]);

    /* Synchronisation authentication token:
     * AUTS = Conc(SQNMS) || MACS */
    memcpy(&auts_pP->value[0], sqnms, USIM_API_SQNMS_SIZE);
    memcpy(&auts_pP->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE);
  }

  LOG_FUNC_RETURN (RETURNok);
}