/*
 * Copyright (c) 2019 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "cipher.h"
#include "cipher_init.h"
#include "example_app.h"
#include "example_app_methods.h"
#include "run_cipher.h"
#include "utils.h"

int run_cipher(struct QSEECom_handle *app_handle)
{
  int error;

  struct example_app_req req;
  struct example_app_rsp rsp;

  struct cipher_req cipher_req;
  struct cipher_rsp cipher_rsp;

  struct cipher_rsp *cipher_result;

  /* This input could be gathered from the user in some way. */
  enum cipher_alg alg = CIPHER_ALG_AES_128;

  const char *msg = "mycustommessage";
  const uint32_t msg_len = strlen(msg);

  cipher_req_init(&cipher_req, CIPHER_MODE_ENCRYPT, alg, (const uint8_t *)msg, msg_len);

  example_app_req_cipher_init(&req, &cipher_req);
  example_app_rsp_cipher_init(&rsp, &cipher_rsp);

  printf("Encrypting msg '%s':\n", msg);

  error = QSEECom_send_cmd(app_handle, &req, sizeof(req), &rsp, sizeof(rsp));

  if (error != QSEECOM_SUCCESS) {
    goto out;
  }

  cipher_result = example_app_rsp_get_rsp_struct(&rsp);
  if (!cipher_result) {
    error = CIPHER_FAILURE;
    goto out;
  }

  if (cipher_result->status == CIPHER_FAILURE) {
    printf("Encryption failed - error: %d\n", cipher_result->status);
    error = CIPHER_FAILURE;
    goto out;
  }

  printf("Encrypted msg: ");
  print_hex(cipher_result->result, cipher_result->result_size);

  /* Decrypt the result */
  printf("Decrypting result:\n");

  bool was_padded = cipher_req.padded;

  cipher_req_init(
    &cipher_req, CIPHER_MODE_DECRYPT, alg, cipher_result->result, cipher_result->result_size);
  cipher_req.padded = was_padded;

  example_app_req_cipher_init(&req, &cipher_req);
  example_app_rsp_cipher_init(&rsp, &cipher_rsp);

  error = QSEECom_send_cmd(app_handle, &req, sizeof(req), &rsp, sizeof(rsp));

  if (error == QSEECOM_SUCCESS) {
    cipher_result = example_app_rsp_get_rsp_struct(&rsp);
    if (!cipher_result) {
      error = CIPHER_FAILURE;
      goto out;
    }

    if (cipher_result->status == CIPHER_SUCCESS) {
      printf("Decrypted msg: %.*s\n", cipher_result->result_size, cipher_result->result);
      if (cipher_result->result_size != msg_len) {
        printf("Decrypted result length different to expected\n");
        error = CIPHER_FAILURE;
        goto out;
      }
      if (memcmp(cipher_result->result, msg, msg_len) == 0) {
        printf("Decrypted result matches original message.\n");
      } else {
        printf("Decrypted result does not match original message.\n");
        error = CIPHER_FAILURE;
      }
    } else {
      error = CIPHER_FAILURE;
      printf("Decryption failed - error: %d\n", cipher_result->status);
    }
  }

out:
  return error ? CIPHER_FAILURE : CIPHER_SUCCESS;
}
