/*
 * Licensed to Open Source Radio Access Network(OS-RAN) Alliance and OAI
 * Software Alliance under one or more contributor license agreements. The
 * initial OpenXG series projects are derided from OAI projects, the files from
 * OAI projects are all in compliance with OAI Public License, Version 1.1.
 * codes and files developed from OpenXG projects and from OS-RAN Alliance
 * are all under OS-RAN licenses; you may not use this file except in compliance
 * with the license.  You may get a copy of the license at:
 *	http://www.openxg.org.cn/?falu_69.html
 * For more information about OpenXG, please contact:
 * contact@openxg.org.cn
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>
#include "assertions.h"
#include "conversions.h"
#include "secu_defs.h"
#include "dynamic_memory_check.h"

int nas_stream_encrypt_nea2(
    nas_stream_cipher_t* const stream_cipher, uint8_t* const out) {
  uint8_t m[16];
  uint32_t local_count;
  void* ctx;
  uint8_t* data;
  uint32_t zero_bit = 0;
  uint32_t byte_length;

  DevAssert(stream_cipher != NULL);
  DevAssert(out != NULL);
  zero_bit    = stream_cipher->blength & 0x7;
  byte_length = stream_cipher->blength >> 3;

  if (zero_bit > 0) byte_length += 1;

  ctx         = malloc(nettle_aes128.context_size);
  data        = malloc(byte_length);
  local_count = hton_int32(stream_cipher->count);
  memset(m, 0, sizeof(m));
  memcpy(&m[0], &local_count, 4);
  m[4] = ((stream_cipher->bearer & 0x1F) << 3) |
         ((stream_cipher->direction & 0x01) << 2);
  /*
   * Other bits are 0
   */
  nettle_aes128.set_encrypt_key(ctx, stream_cipher->key);
  nettle_ctr_crypt(
      ctx, nettle_aes128.encrypt, nettle_aes128.block_size, m, byte_length,
      data, stream_cipher->message);

  if (zero_bit > 0)
    data[byte_length - 1] =
        data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit));

  memcpy(out, data, byte_length);
  free_wrapper((void**) &data);
  free_wrapper(&ctx);
  return 0;
}
