text: // g++ -fPIC -shared -o Client_Lib.so client.cpp
  
  #include <iostream>
  #include <string.h>
  #include "gmp.h"
  
  using namespace std;
  const char *hex_value[256] = {
      "00",
      "01",
      "02",
      "03",
      "04",
      "05",
      "06",
      "07",
      "08",
      "09",
      "0A",
      "0B",
      "0C",
      "0D",
      "0E",
      "0F",
      "10",
      "11",
      "12",
      "13",
      "14",
      "15",
      "16",
      "17",
      "18",
      "19",
      "1A",
      "1B",
      "1C",
      "1D",
      "1E",
      "1F",
      "20",
      "21",
      "22",
      "23",
      "24",
      "25",
      "26",
      "27",
      "28",
      "29",
      "2A",
      "2B",
      "2C",
      "2D",
      "2E",
      "2F",
      "30",
      "31",
      "32",
      "33",
      "34",
      "35",
      "36",
      "37",
      "38",
      "39",
      "3A",
      "3B",
      "3C",
      "3D",
      "3E",
      "3F",
      "40",
      "41",
      "42",
      "43",
      "44",
      "45",
      "46",
      "47",
      "48",
      "49",
      "4A",
      "4B",
      "4C",
      "4D",
      "4E",
      "4F",
      "50",
      "51",
      "52",
      "53",
      "54",
      "55",
      "56",
      "57",
      "58",
      "59",
      "5A",
      "5B",
      "5C",
      "5D",
      "5E",
      "5F",
      "60",
      "61",
      "62",
      "63",
      "64",
      "65",
      "66",
      "67",
      "68",
      "69",
      "6A",
      "6B",
      "6C",
      "6D",
      "6E",
      "6F",
      "70",
      "71",
      "72",
      "73",
      "74",
      "75",
      "76",
      "77",
      "78",
      "79",
      "7A",
      "7B",
      "7C",
      "7D",
      "7E",
      "7F",
      "80",
      "81",
      "82",
      "83",
      "84",
      "85",
      "86",
      "87",
      "88",
      "89",
      "8A",
      "8B",
      "8C",
      "8D",
      "8E",
      "8F",
      "90",
      "91",
      "92",
      "93",
      "94",
      "95",
      "96",
      "97",
      "98",
      "99",
      "9A",
      "9B",
      "9C",
      "9D",
      "9E",
      "9F",
      "A0",
      "A1",
      "A2",
      "A3",
      "A4",
      "A5",
      "A6",
      "A7",
      "A8",
      "A9",
      "AA",
      "AB",
      "AC",
      "AD",
      "AE",
      "AF",
      "B0",
      "B1",
      "B2",
      "B3",
      "B4",
      "B5",
      "B6",
      "B7",
      "B8",
      "B9",
      "BA",
      "BB",
      "BC",
      "BD",
      "BE",
      "BF",
      "C0",
      "C1",
      "C2",
      "C3",
      "C4",
      "C5",
      "C6",
      "C7",
      "C8",
      "C9",
      "CA",
      "CB",
      "CC",
      "CD",
      "CE",
      "CF",
      "D0",
      "D1",
      "D2",
      "D3",
      "D4",
      "D5",
      "D6",
      "D7",
      "D8",
      "D9",
      "DA",
      "DB",
      "DC",
      "DD",
      "DE",
      "DF",
      "E0",
      "E1",
      "E2",
      "E3",
      "E4",
      "E5",
      "E6",
      "E7",
      "E8",
      "E9",
      "EA",
      "EB",
      "EC",
      "ED",
      "EE",
      "EF",
      "F0",
      "F1",
      "F2",
      "F3",
      "F4",
      "F5",
      "F6",
      "F7",
      "F8",
      "F9",
      "FA",
      "FB",
      "FC",
      "FD",
      "FE",
      "FF",
  };
  unsigned char s_box[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};
  unsigned char mul2[256] =
      {
          0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
          0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
          0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
          0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
          0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
          0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
          0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
          0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
          0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
          0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
          0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
          0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
          0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
          0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
          0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
          0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5};
  unsigned char mul3[256] =
      {
          0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
          0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
          0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
          0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
          0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
          0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
          0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
          0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
          0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
          0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
          0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
          0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
          0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
          0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
          0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
          0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a};
  unsigned char rcon[256] = {
      0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
      0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
      0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
      0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
      0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
      0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
      0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
      0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
      0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
      0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
      0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
      0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
      0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
      0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
      0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
      0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
  void key_expansion_core(unsigned char *in, unsigned char i)
  {
      unsigned int *q = (unsigned int *)in;
      *q = (*q >> 8) | ((*q & 0xff) << 24);
      in[0] = s_box[in[0]];
      in[1] = s_box[in[1]];
      in[2] = s_box[in[2]];
      in[3] = s_box[in[3]];
      in[0] ^= rcon[i];
  }
  void key_expansion(unsigned char *input_key, unsigned char *expanded_key)
  {
      for (int i = 0; i < 16; i++)
          expanded_key[i] = input_key[i];
      int bytes_generated = 16;
      int rcon_iterations = 1;
      unsigned char temp[4];
      while (bytes_generated < 176)
      {
          for (int i = 0; i < 4; i++)
          {
              temp[i] = expanded_key[i + bytes_generated - 4];
          }
          if (bytes_generated % 16 == 0)
          {
              key_expansion_core(temp, rcon_iterations);
              rcon_iterations++;
          }
          for (unsigned char a = 0; a < 4; a++)
          {
              expanded_key[bytes_generated] = expanded_key[bytes_generated - 16] ^ temp[a];
              bytes_generated++;
          }
      }
  }
  void initial_round() {}
  void sub_bytes(unsigned char *state)
  {
      for (int i = 0; i < 16; i++)
      {
          state[i] = s_box[state[i]];
      }
  }
  void shift_rows(unsigned char *state)
  {
      unsigned char tmp[16];
      tmp[0] = state[0];
      tmp[1] = state[5];
      tmp[2] = state[10];
      tmp[3] = state[15];
  
      tmp[4] = state[4];
      tmp[5] = state[9];
      tmp[6] = state[14];
      tmp[7] = state[3];
  
      tmp[8] = state[8];
      tmp[9] = state[13];
      tmp[10] = state[2];
      tmp[11] = state[7];
  
      tmp[12] = state[12];
      tmp[13] = state[1];
      tmp[14] = state[6];
      tmp[15] = state[11];
  
      for (int i = 0; i < 16; i++)
      {
          state[i] = tmp[i];
      }
  }
  void mix_columns(unsigned char *state)
  {
      unsigned char tmp[16];
      tmp[0] = (unsigned char)(mul2[state[0]] ^ mul3[state[1]] ^ state[2] ^ state[3]);
      tmp[1] = (unsigned char)(state[0] ^ mul2[state[1]] ^ mul3[state[2]] ^ state[3]);
      tmp[2] = (unsigned char)(state[0] ^ state[1] ^ mul2[state[2]] ^ mul3[state[3]]);
      tmp[3] = (unsigned char)(mul3[state[0]] ^ state[1] ^ state[2] ^ mul2[state[3]]);
  
      tmp[4] = (unsigned char)(mul2[state[4]] ^ mul3[state[5]] ^ state[6] ^ state[7]);
      tmp[5] = (unsigned char)(state[4] ^ mul2[state[5]] ^ mul3[state[6]] ^ state[7]);
      tmp[6] = (unsigned char)(state[4] ^ state[5] ^ mul2[state[6]] ^ mul3[state[7]]);
      tmp[7] = (unsigned char)(mul3[state[4]] ^ state[5] ^ state[6] ^ mul2[state[7]]);
  
      tmp[8] = (unsigned char)(mul2[state[8]] ^ mul3[state[9]] ^ state[10] ^ state[11]);
      tmp[9] = (unsigned char)(state[8] ^ mul2[state[9]] ^ mul3[state[10]] ^ state[11]);
      tmp[10] = (unsigned char)(state[8] ^ state[9] ^ mul2[state[10]] ^ mul3[state[11]]);
      tmp[11] = (unsigned char)(mul3[state[8]] ^ state[9] ^ state[10] ^ mul2[state[11]]);
  
      tmp[12] = (unsigned char)(mul2[state[12]] ^ mul3[state[13]] ^ state[14] ^ state[15]);
      tmp[13] = (unsigned char)(state[12] ^ mul2[state[13]] ^ mul3[state[14]] ^ state[15]);
      tmp[14] = (unsigned char)(state[12] ^ state[13] ^ mul2[state[14]] ^ mul3[state[15]]);
      tmp[15] = (unsigned char)(mul3[state[12]] ^ state[13] ^ state[14] ^ mul2[state[15]]);
  
      for (int i = 0; i < 16; i++)
      {
          state[i] = tmp[i];
      }
  }
  void add_round_keys(unsigned char *state, unsigned char *round_key)
  {
      for (int i = 0; i < 16; i++)
      {
          state[i] ^= round_key[i];
      }
  }
  void AES_encrypt(unsigned char *message, unsigned char *expanded_key)
  {
      int nor = 9;
      unsigned char state[16];
      // unsigned char expanded_key[176];
      for (int i = 0; i < 16; i++)
          state[i] = message[i];
      // key_expansion(key, expanded_key);
      // add_round_keys(state, key);
      add_round_keys(state, expanded_key + 160);
      for (int i = 0; i < nor; i++)
      {
          sub_bytes(state);
          shift_rows(state);
          mix_columns(state);
          add_round_keys(state, expanded_key + (16 * (i + 1)));
      }
      /*The Final Round*/
      sub_bytes(state);
      shift_rows(state);
      add_round_keys(state, expanded_key + 160);
  
      for (int i = 0; i < 16; i++)
          message[i] = state[i];
  }
  void print_hex(unsigned char x)
  {
      if (x / 16 < 10)
          cout << (char)((x / 16) + '0');
      if (x / 16 >= 10)
          cout << (char)((x / 16 - 10) + 'A');
      if (x % 16 < 10)
          cout << (char)((x % 16) + '0');
      if (x % 16 >= 10)
          cout << (char)((x % 16 - 10) + 'A');
  }
  
  // Bên trên là thư viện tải về
  
  uint8_t *generateRandomBytes(int n)
  {
      uint8_t *key = new uint8_t[n];
      srand((int)time(0));
      for (int i = 1; i <= 100; i++)
      {
          rand();
      }
      for (int i = 0; i < n; i++)
      {
          key[i] = rand() % 256;
      }
      return key;
  }
  
  void createIV(unsigned char *IV, uint8_t *nonce, uint64_t ctr)
  {
      uint64_t temp = ctr;
      IV[15] = temp;
      temp = temp >> 8;
      IV[14] = temp;
      temp = temp >> 8;
      IV[13] = temp;
      temp = temp >> 8;
      IV[12] = temp;
      temp = temp >> 8;
      IV[11] = temp;
      temp = temp >> 8;
      IV[10] = temp;
      temp = temp >> 8;
      IV[9] = temp;
      temp = temp >> 8;
      IV[8] = temp;
      for (int i = 0; i < 8; i++)
      {
          IV[i] = nonce[i];
      }
      // for(int i = 0; i< 16; i++){
      // 	DecimalToBinary(IV[i]);
      // 	cout<<" ";
      // }
  }
  
  unsigned char *CTR_encrypt(char *inputFilePath, char *outputFilePath)
  {
      unsigned char *nonce = generateRandomBytes(8);
      unsigned char *IV = new unsigned char[16];
      uint64_t ctr = 0;
  
      unsigned char *key;
      key = generateRandomBytes(16);
      //read file
      FILE *fp = fopen(inputFilePath, "rb");
      fseek(fp, 0, SEEK_END);
      unsigned int n = ftell(fp);
      int paddingLength = 16 - n % 16;
      int totalLength = n + paddingLength;
      unsigned char *plainText = new unsigned char[totalLength];
      fseek(fp, 0, SEEK_SET);
      fread((unsigned char *)plainText, 1, totalLength, fp);
      fclose(fp);
      //padding
      for (int i = n; i < totalLength; i++)
      {
          plainText[i] = (unsigned char)paddingLength;
      }
      //expand key
      unsigned char *expanded_key = new unsigned char[176];
      key_expansion(key, expanded_key);
      //encrypt
      for (int i = 0; i < totalLength; i += 16)
      {
          createIV(IV, nonce, ctr);
          ctr += 1;
          AES_encrypt(IV, expanded_key);
          for (int j = 0; j < 16; j++)
          {
              plainText[i + j] ^= IV[j];
          }
      }
      //write file
      fp = fopen(outputFilePath, "wb");
      fwrite((unsigned char *)nonce, 1, 8, fp);
      fwrite((unsigned char *)plainText, 1, totalLength, fp);
      fclose(fp);
      delete[] plainText;
      delete[] expanded_key;
      delete[] IV;
      delete[] nonce;
      return key;
  }
  
  void CTR_decrypt(char *inputFilePath, char *outputFilePath, unsigned char *key)
  {
      //init
      unsigned char *IV = new unsigned char[16];
      unsigned char *nonce = new unsigned char[8];
      uint64_t ctr = 0;
      //read file
      FILE *fp = fopen(inputFilePath, "rb");
      fseek(fp, 0, SEEK_END);
      unsigned int n = ftell(fp);
      n = n - 8;
      unsigned char *cipherText = new unsigned char[n];
      fseek(fp, 0, SEEK_SET);
      fread((unsigned char *)nonce, 1, 8, fp);
      fread((unsigned char *)cipherText, 1, n, fp);
      fclose(fp);
      //expand key
      unsigned char *expanded_key = new unsigned char[176];
      key_expansion(key, expanded_key);
      //decrypt
      for (int i = 0; i < n; i += 16)
      {
          createIV(IV, nonce, ctr);
          ctr += 1;
          AES_encrypt(IV, expanded_key);
          for (int j = 0; j < 16; j++)
          {
              cipherText[i + j] ^= IV[j];
          }
      }
      //write file
      int paddingValue = (int)cipherText[n - 1];
      fp = fopen(outputFilePath, "wb");
      fwrite((unsigned char *)cipherText, 1, n - paddingValue, fp);
      fclose(fp);
      delete[] cipherText;
      delete[] key;
      delete[] expanded_key;
      delete[] IV;
      delete[] nonce;
  }
  
  
  char* unsignedchar2hex(unsigned char *str, int n)
  {
      int length = 2 * n;
      char *result = new char[length+1];
      result[length] = '\0';
      for (int i = 0; i < 16; i++)
      {
          int c_value = (int)str[i];
          *(result + 2*i) = hex_value[c_value][0];
          *(result + 2*i + 1) = hex_value[c_value][1];
      }
      return result;
  }
  
  unsigned char* hex2unsignedchar(char* hex, int n){
      unsigned char* result = new unsigned char[n/2+1];
      for(int i = 0; i < n/2; i++){
          char* hex_value = new char[3];
          hex_value[0] = hex[2*i];
          hex_value[1] = hex[2*i+1];
          hex_value[2] = '\0';
          mpz_t tmp;
          mpz_init_set_str(tmp, hex_value, 16);
          result[i] =(unsigned char) mpz_get_ui(tmp);
          mpz_clear(tmp);
      }
      result[n/2] = '\0';
      return result;
  }
  extern "C"
  {
      char *Encrypt_File(char *input, char *output)
      {
          unsigned char *key_uc = CTR_encrypt(input, output);
          return unsignedchar2hex(key_uc, 16);
      }
      void Decrypt_File(char *input, char *output, char *key_c)
      {
          unsigned char *key_uc = hex2unsignedchar(key_c, 32);
          CTR_decrypt(input, output, key_uc);
      }
  }
  
  