diff --git a/Android.mk b/Android.mk
index fe6de43..9b1ba3c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,6 +76,13 @@ LOCAL_CFLAGS += -DCFG_PKCS11_TA
 LOCAL_SHARED_LIBRARIES += libckteec
 endif
 
+ifeq ($(CFG_REGRESSION_NXP),y)
+srcs += regression_nxp/crypto/cipher.c
+ifeq ($(CFG_WITH_STATS),y)
+srcs += regression_nxp/crypto/cipher_memleak.c
+endif
+endif
+
 define my-embed-file
 $(TARGET_OUT_HEADERS)/$(1).h: $(LOCAL_PATH)/$(2)
 	@echo '  GEN     $$@'
diff --git a/Makefile b/Makefile
index 5c2f11f..f09ef39 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,9 @@ export q
 CROSS_COMPILE_HOST ?= $(CROSS_COMPILE)
 CROSS_COMPILE_TA ?= $(CROSS_COMPILE)
 
+# If CFG_TEE_PLUGIN_LOAD_PATH is not specified
+CFG_TEE_PLUGIN_LOAD_PATH ?= usr/lib/tee-supplicant/plugins
+
 .PHONY: all
 ifneq ($(wildcard $(TA_DEV_KIT_DIR)/host_include/conf.mk),)
 all: xtest ta test_plugin
diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt
index 320d336..1f19543 100644
--- a/host/xtest/CMakeLists.txt
+++ b/host/xtest/CMakeLists.txt
@@ -115,6 +115,10 @@ endif()
 if (CFG_CRYPTO_SE05X)
 	add_compile_options(-DCFG_CRYPTO_SE05X)
 endif()
+if (CFG_REGRESSION_NXP)
+	list (APPEND SRC regression_nxp/crypto/cipher.c)
+	list (APPEND SRC regression_nxp/peripherals/i2c.c)
+endif()
 
 ################################################################################
 # Built binary
diff --git a/host/xtest/Makefile b/host/xtest/Makefile
index af45f5e..eb75ae9 100644
--- a/host/xtest/Makefile
+++ b/host/xtest/Makefile
@@ -33,6 +33,9 @@ define cc-bits
 $(if $(filter arm, $(1)),32,$(if $(filter aarch64, $(1)),64,unknown-arch))
 endef
 
+CFG_REGRESSION_NXP ?= y
+CFG_PKCS11_TA ?= y
+
 # OpenSSL is used by:
 # - GP tests series 8500
 # - Mbed TLS test 8103
@@ -81,7 +84,8 @@ srcs +=	adbg/src/adbg_case.c \
 	xtest_helpers.c \
 	xtest_main.c \
 	xtest_test.c \
-	xtest_uuid_helpers.c
+	xtest_uuid_helpers.c \
+	crypto_perf.c
 
 ifeq ($(CFG_SECURE_PARTITION)-$(CFG_SPMC_TESTS),y-y)
 srcs += ffa_spmc_1000.c
@@ -99,6 +103,19 @@ ifeq ($(CFG_PKCS11_TA),y)
 srcs += pkcs11_1000.c
 endif
 
+ifeq ($(CFG_REGRESSION_NXP),y)
+CFLAGS += -DCFG_REGRESSION_NXP
+srcs += regression_nxp/crypto/cipher.c
+srcs += regression_nxp/peripherals/i2c.c
+ifeq ($(CFG_WITH_STATS),y)
+srcs += regression_nxp/crypto/cipher_memleak.c
+endif
+srcs += regression_nxp/dek_blob/dek_blob.c
+srcs += regression_nxp/ocotp/ocotp.c
+srcs += regression_nxp/digprog/digprog.c
+srcs += regression_nxp/crypto/mp_signature.c
+endif
+
 objs 	:= $(patsubst %.c,$(out-dir)/xtest/%.o, $(srcs))
 
 ifeq ($(CFG_PKCS11_TA),y)
@@ -137,6 +154,8 @@ CFLAGS += -I../../ta/tpm_log_test/include
 CFLAGS += -I../../ta/large/include
 CFLAGS += -I../../ta/supp_plugin/include
 CFLAGS += -I../../ta/bti_test/include
+CFLAGS += -I../../ta/crypto_perf/include
+CFLAGS += -I../../ta/mp_sign/include
 
 TA_DIR ?= /lib/optee_armtz
 CFLAGS += -DTA_DIR=\"$(TA_DIR)\"
@@ -172,6 +191,13 @@ xtest: $(objs)
 
 $(out-dir)/xtest/%.o: $(CURDIR)/%.c
 	$(q)mkdir -p $(out-dir)/xtest/adbg/src
+ifdef CFG_REGRESSION_NXP
+	$(q)mkdir -p $(out-dir)/xtest/regression_nxp/crypto
+	$(q)mkdir -p $(out-dir)/xtest/regression_nxp/peripherals
+	$(q)mkdir -p $(out-dir)/xtest/regression_nxp/dek_blob
+	$(q)mkdir -p $(out-dir)/xtest/regression_nxp/ocotp
+	$(q)mkdir -p $(out-dir)/xtest/regression_nxp/digprog
+endif
 	@echo '  CC      $<'
 	$(q)$(CC) $(CFLAGS) -c $< -o $@
 
@@ -238,3 +264,7 @@ clean:
 	$(q)$(foreach obj,$(objs), rm -f $(obj))
 	$(q)rm -f $(cleanfiles)
 	$(call rm-build-dirs,adbg/src adbg)
+ifdef CFG_REGRESSION_NXP
+	$(call rm-build-dirs,regression_nxp/dek_blob)
+	$(call rm-build-dirs,regression_nxp/crypto regression_nxp/peripherals regression_nxp)
+endif
diff --git a/host/xtest/crypto_common.h b/host/xtest/crypto_common.h
index 9117c90..3e7aa13 100644
--- a/host/xtest/crypto_common.h
+++ b/host/xtest/crypto_common.h
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * Copyright (c) 2015, Linaro Limited
+ * Copyright 2018 NXP
+ *
  * All rights reserved.
  */
 
@@ -49,6 +51,8 @@ void sha_perf_run_test(int algo, size_t size, unsigned int n,
 				unsigned int l, int random_in, int offset,
 				int warmup, int verbosity);
 
+int crypto_perf_runner_cmd_parser(int argc, char *argv[]);
+
 #ifdef CFG_SECURE_DATA_PATH
 int sdp_basic_runner_cmd_parser(int argc, char *argv[]);
 #endif
diff --git a/host/xtest/crypto_perf.c b/host/xtest/crypto_perf.c
new file mode 100644
index 0000000..a0b39a9
--- /dev/null
+++ b/host/xtest/crypto_perf.c
@@ -0,0 +1,1600 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018-2022 NXP
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <math.h>
+#include <util.h>
+#include <unistd.h>
+
+#include <tee_client_api.h>
+#include <utee_defines.h>
+
+#include "crypto_common.h"
+#include "ta_crypto_perf_test.h"
+
+/*
+ * Default values
+ */
+#define DEFAULT_KEY_SIZE	128
+#define DEFAULT_LOOP		1000
+#define DEFAULT_BUFFER_SIZE	1024
+
+#define ERROR_BAD_TEST_MASK		(-1100)
+#define ERROR_BAD_TEST_GENERIC	(ERROR_BAD_TEST_MASK | 1)
+#define ERROR_BAD_TEST_SC_INPUT (ERROR_BAD_TEST_MASK | 2)
+#define ERROR_BAD_TEST_C_INPUT  (ERROR_BAD_TEST_MASK | 3)
+#define ERROR_BAD_TEST_DIGEST   (ERROR_BAD_TEST_MASK | 4)
+
+#define ERROR_GET_CAPS			(-1001)
+#define ERROR_OPEN_TA_CTX		(-1002)
+#define ERROR_OPEN_TA_SESSION	(-1003)
+#define ERROR_ALLOCATE_SHM		(-1004)
+#define ERROR_READ_RANDOM_FILE	(-1005)
+#define ERROR_TA_PREP_ALGO		(-1006)
+#define ERROR_TA_CMD_PROCESS	(-1007)
+#define ERROR_TA_FREE_ALGO		(-1008)
+
+//#define COLLECT_DATA
+#ifdef COLLECT_DATA
+static FILE * dataFile;
+#define PRINT_DATA(idx, t)	fprintf(dataFile, "%d:%llu\n", idx, t)
+#define OPEN_DATA(name)		(dataFile = fopen(name, "a"))
+#define CLOSE_DATA do { \
+		fflush(dataFile); \
+		fsync(fileno(dataFile)); \
+		fclose(dataFile); \
+	} while (0)
+
+#else
+#define PRINT_DATA(idx, t)
+#define OPEN_DATA(name)
+#define CLOSE_DATA
+#endif
+
+/* Local function prototypes */
+struct test_param;
+static int free_algo(const struct test_param *test, TEEC_Operation *op);
+
+/*
+ * Hash Algo Names
+ */
+static const char * const hash_name[] = {
+	NULL, "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512"};
+/*
+ * TEE client stuff
+ */
+
+static TEEC_Context ctx  = { 0 };
+static TEEC_Session sess = { 0 };
+
+static const char * const str_sizes[] = { "MB", "KB", "B" };
+static const uint32_t KB = 1024;
+static const uint32_t MB = 1024 * 1024;
+static char           HeadP1Empty[100];
+
+/*
+ * Local Data
+ */
+static struct ta_caps ta_caps;
+static char *name_alg_list;
+
+struct test_param {
+	char     alg[40];
+	uint8_t  verbose;
+	uint8_t	 in_place;
+	uint8_t	 in_random;
+	uint16_t keysize;
+	uint32_t loop;
+	uint32_t bufsize;
+	bool generate;
+};
+
+static void setdefault_param(struct test_param *test)
+{
+	memset(test->alg, 0, sizeof(test->alg));
+	test->verbose   = 0;
+	test->in_place  = 0;
+	test->in_random = 0;
+	test->keysize   = DEFAULT_KEY_SIZE;
+	test->loop      = DEFAULT_LOOP;
+	test->bufsize   = DEFAULT_BUFFER_SIZE;
+	test->generate = false;
+}
+
+/*
+ * Statistics
+ *
+ * We want to compute min, max, mean and standard deviation of processing time
+ */
+
+struct statistics {
+	int n;
+	double m;
+	double M2;
+	double min;
+	double max;
+	int initialized;
+	size_t data_size;
+};
+
+/* Take new sample into account (Knuth/Welford algorithm) */
+static void update_stats(struct statistics *s, uint64_t t)
+{
+	double x = (double)t;
+	double delta = x - s->m;
+
+	s->n++;
+	s->m += delta/s->n;
+	s->M2 += delta*(x - s->m);
+	if (!s->initialized) {
+		s->min = s->max = x;
+		s->initialized = 1;
+	} else {
+		if (s->min > x)
+			s->min = x;
+		if (s->max < x)
+			s->max = x;
+	}
+
+	PRINT_DATA(s->n, t);
+}
+
+static void get_current_time(struct timespec *ts)
+{
+	if (clock_gettime(CLOCK_MONOTONIC, ts) < 0) {
+		perror("clock_gettime");
+		exit(1);
+	}
+}
+
+static uint64_t timespec_to_ns(struct timespec *ts)
+{
+	return ((uint64_t)ts->tv_sec * 1000000000) + ts->tv_nsec;
+}
+
+static uint64_t timespec_diff_ns(struct timespec *start, struct timespec *end)
+{
+	return timespec_to_ns(end) - timespec_to_ns(start);
+}
+
+static double stddev(struct statistics *s)
+{
+	if (s->n < 2)
+		return NAN;
+	return sqrt(s->M2 / s->n);
+}
+
+static double mb_per_sec(size_t size, double usec)
+{
+	return (1000000 / usec) * ((double)size / MB);
+}
+
+static int check_res(TEEC_Result res, const char *errmsg)
+{
+	if (res != TEEC_SUCCESS) {
+		fprintf(stderr, "%s: 0x%08x\n", errmsg, res);
+		return (-1);
+	}
+	return 0;
+}
+
+/* Print Log file */
+static char *size_to_str(uint32_t size, char *str)
+{
+	uint8_t  idx;
+	uint32_t mul = MB;
+
+	for (idx = 0; idx < ARRAY_SIZE(str_sizes); idx++, mul /= KB) {
+		if (size < mul)
+			continue;
+
+		if ((size % mul) == 0)
+			sprintf(str, "%d %s", (size / mul), str_sizes[idx]);
+		else
+			sprintf(str, "%.1f %s", ((float)size / mul),
+				str_sizes[idx]);
+		return str;
+	}
+
+	sprintf(str, "0 B");
+	return str;
+}
+
+static uint32_t strsize_to_bytes(char *str)
+{
+	float size = atof(str);
+	char     unit;
+
+	/* Check unit if specified */
+	unit = str[strlen(str) - 1];
+
+	switch (unit) {
+	case 'b':
+	case 'B':
+		/* Bytes */
+		break;
+
+	case 'K':
+	case 'k':
+		/* KBytes */
+		size *= KB;
+		break;
+
+	case 'M':
+	case 'm':
+		/* MBytes */
+		size *= MB;
+		break;
+
+	default:
+		break;
+	}
+
+	if ((uint32_t)size == 0)
+		return (uint32_t)(-1);
+
+	return size;
+}
+
+static void print_log_header(FILE *log)
+{
+	char HeadPart1[100];
+
+	if (log == NULL)
+		return;
+
+	sprintf(HeadPart1,  " %-28s | Key | Loop | Rand | I=O ",
+			"Algorithm Name");
+	sprintf(HeadP1Empty, "%28c |     |      |      |     ", ' ');
+	fprintf(log, "%s", HeadPart1);
+	fprintf(log, "| Op  |   Size   |  min (μs)  |  max (μs)  |");
+	fprintf(log, "  mean (μs) | stddev(μs) |  MiB/s\n");
+
+}
+
+static void print_log_test(FILE *log, struct test_param *test)
+{
+	if (log == NULL)
+		return;
+
+	fprintf(log, "%-29s |", test->alg);
+	fprintf(log, "%4d |%5d |", test->keysize, test->loop);
+
+	if (test->in_random)
+		fprintf(log, "%5s |", "Yes");
+	else
+		fprintf(log, "%5s |", "No");
+
+	if (test->in_place)
+		fprintf(log, "%4s |", "Yes");
+	else
+		fprintf(log, "%4s |", "No");
+}
+
+static void print_log_result(FILE *log, uint8_t reverse, bool generate,
+			     struct statistics *stats_enc,
+			     struct statistics *stats_dec, double t_prep)
+{
+	char tmp[20];
+
+	if (log == NULL)
+		return;
+
+	fprintf(log, " Pre |");
+	fprintf(log, "%9c | ", ' ');
+	fprintf(log, "%10g\n", t_prep);
+
+	if (generate)
+		fprintf(log, " %s| Gen |", HeadP1Empty);
+	else
+		fprintf(log, " %s| Enc |", HeadP1Empty);
+
+	fprintf(log, "%9s | ", size_to_str(stats_enc->data_size, tmp));
+	fprintf(log, "%10g | %10g | %10g | %10g | %10g\n",
+		(stats_enc->min / 1000),
+		(stats_enc->max / 1000),
+		(stats_enc->m / 1000),
+		(stddev(stats_enc) / 1000),
+		mb_per_sec(stats_enc->data_size, stats_enc->m / 1000));
+
+	if (reverse) {
+		fprintf(log, " %s| Dec |", HeadP1Empty);
+		fprintf(log, "%9s | ", size_to_str(stats_dec->data_size, tmp));
+		fprintf(log, "%10g | %10g | %10g | %10g | %10g\n",
+		(stats_dec->min / 1000),
+		(stats_dec->max / 1000),
+		(stats_dec->m / 1000),
+		(stddev(stats_dec) / 1000),
+		mb_per_sec(stats_dec->data_size, stats_dec->m / 1000));
+
+	}
+}
+
+
+/* TA Open/close */
+static int open_ta(void)
+{
+	TEEC_Result res;
+	TEEC_UUID uuid = TA_CRYPTO_PERF_TEST_UUID;
+	uint32_t err_origin;
+
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (check_res(res, "TEEC_InitializeContext") != 0)
+		return ERROR_OPEN_TA_CTX;
+
+	res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
+			       NULL, &err_origin);
+	if (check_res(res, "TEEC_OpenSession") != 0)
+		return ERROR_OPEN_TA_SESSION;
+
+	return 0;
+}
+
+static void close_ta(int ret)
+{
+	if (ret == ERROR_BAD_TEST_GENERIC)
+		return;
+
+	free(name_alg_list);
+
+	if (ret != ERROR_OPEN_TA_SESSION)
+		TEEC_CloseSession(&sess);
+
+	if (ret != ERROR_OPEN_TA_CTX)
+		TEEC_FinalizeContext(&ctx);
+}
+
+static ssize_t read_random(void *in, size_t size)
+{
+	FILE *rndfile = NULL;
+	size_t readsize;
+
+	rndfile = fopen("/dev/urandom", "r");
+	if (!rndfile) {
+		fprintf(stderr, "Open file [/dev/urandom] error\n");
+		return 1;
+	}
+
+	readsize = fread(in, size, 1, rndfile);
+	if (readsize != 1) {
+		fprintf(stderr, "Can't read file [/dev/urandom]\n");
+		fclose(rndfile);
+		return 1;
+	}
+
+	fclose(rndfile);
+
+	return 0;
+}
+
+/* TA Get Caps */
+static int getcaps_ta(void)
+{
+	uint32_t       ret_origin;
+	TEEC_Result    res;
+	TEEC_Operation op = {0};
+
+	/* Check if Algorithms name already read */
+	if (name_alg_list)
+		return 0;
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
+					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+	op.params[0].tmpref.buffer = &ta_caps;
+	op.params[0].tmpref.size   = sizeof(struct ta_caps);
+
+	res = TEEC_InvokeCommand(&sess, TA_CRYPTO_PERF_CMD_GET_CAPS,
+			&op, &ret_origin);
+
+	if (res != TEEC_SUCCESS) {
+		fprintf(stderr, "Get TA capabilities failed (0x%X)\n", res);
+		return ERROR_GET_CAPS;
+	}
+
+	/* Allocate Memories to store the name of the algorithm */
+	name_alg_list = malloc(ta_caps.sizeof_alg_list);
+
+	if (!name_alg_list) {
+		fprintf(stderr, "Can't allocate memory for algorithms name\n");
+		return ERROR_GET_CAPS;
+	}
+
+	/* Get the name list from TA */
+	op.params[0].tmpref.buffer = name_alg_list;
+	op.params[0].tmpref.size   = ta_caps.sizeof_alg_list;
+
+	res = TEEC_InvokeCommand(&sess, TA_CRYPTO_PERF_CMD_GET_LIST_ALG,
+			&op, &ret_origin);
+
+	if (res != TEEC_SUCCESS) {
+		fprintf(stderr, "Get TA Algorithms name failed (0x%X)\n", res);
+		return ERROR_GET_CAPS;
+	}
+
+	return 0;
+}
+
+static void uppercase(char *out, char *in)
+{
+	do {
+		*out = toupper(*in);
+		in++;
+		out++;
+	} while (*in != '\0');
+}
+
+static size_t hash_size(uint8_t algo)
+{
+	switch (algo) {
+	case TEE_MAIN_ALGO_MD5:
+		return TEE_MD5_HASH_SIZE;
+
+	case TEE_MAIN_ALGO_SHA1:
+		return TEE_SHA1_HASH_SIZE;
+
+	case TEE_MAIN_ALGO_SHA224:
+		return TEE_SHA224_HASH_SIZE;
+
+	case TEE_MAIN_ALGO_SHA256:
+		return TEE_SHA256_HASH_SIZE;
+
+	case TEE_MAIN_ALGO_SHA384:
+		return TEE_SHA384_HASH_SIZE;
+
+	case TEE_MAIN_ALGO_SHA512:
+		return TEE_SHA512_HASH_SIZE;
+
+	default:
+		return 0;
+	}
+}
+
+static int cipher_size(uint32_t algo, uint32_t size)
+{
+	if (size < TEE_AES_BLOCK_SIZE)
+		return ERROR_BAD_TEST_C_INPUT;
+
+	/* Check if input size is valid */
+	switch (TEE_ALG_GET_MAIN_ALG(algo)) {
+	case TEE_MAIN_ALGO_AES:
+		if (size % TEE_AES_BLOCK_SIZE)
+			return ERROR_BAD_TEST_C_INPUT;
+		break;
+
+	case TEE_MAIN_ALGO_DES:
+	case TEE_MAIN_ALGO_DES3:
+		if (size % TEE_DES_BLOCK_SIZE)
+			return ERROR_BAD_TEST_C_INPUT;
+		break;
+
+	default:
+		return ERROR_BAD_TEST_C_INPUT;
+	}
+
+	return size;
+}
+
+static int asymcipher_sizes(uint32_t algo, struct test_param *test)
+{
+	int outSize;
+
+	/*
+	 * Check if input size is valid
+	 * return output size if input size is valid
+	 * otherwise return negative error
+	 */
+	switch (algo) {
+	case TEE_ALG_RSAES_PKCS1_V1_5:
+		/*
+		 * Input size in bytes (mLen) <= keysize in bytes (k) - 11
+		 * mLen <= (k - 11)
+		 */
+		if ((int)test->bufsize > (int)((test->keysize / 8) - 11))
+			return ERROR_BAD_TEST_SC_INPUT;
+
+		/* Output size is keysize in bytes (k) */
+		outSize = (test->keysize / 8);
+		break;
+
+	default:
+		/* Check input size */
+		if (algo & BIT(16)) {
+			/* Use MGF */
+			/* Input size in bytes (mLen) <= keysize in bytes (k)
+			 *       - (2 * hash length (hLen)) - 2
+			 * mLen <= (k - 2hLen - 2)
+			 */
+			int hLen;
+			int mLenMax;
+
+			hLen = hash_size(TEE_ALG_GET_INTERNAL_HASH(algo));
+			mLenMax = (int)((test->keysize / 8) - (2 * hLen) - 2);
+
+			if ((int)test->bufsize > mLenMax)
+				return ERROR_BAD_TEST_SC_INPUT;
+		}
+		/* Else output size is keysize in bytes (k) */
+		outSize = (test->keysize / 8);
+		break;
+	}
+
+	return outSize;
+}
+
+/* Verify Test command */
+static int check_test(struct test_param *test)
+{
+	int     ret;
+	bool    found = false;
+	uint8_t idx;
+	char    *list;
+	int		verbosity = test->verbose;
+
+	ret = getcaps_ta();
+	if (ret != 0) {
+		verbose("Can not get TA Capabalities\n");
+		return ret;
+	}
+
+	/* Check if Algorithm name is correct */
+	list = name_alg_list;
+	for (idx = 0; idx < ta_caps.nb_algo; idx++) {
+		if (!(strcmp(list, test->alg))) {
+			/* Algorithm name is correct */
+			found = true;
+			break;
+		}
+		list += strlen(list) + sizeof(char);
+	}
+
+	if (!found) {
+		vverbose("Algo name [%s] not supported\n", test->alg);
+		return ERROR_BAD_TEST_GENERIC;
+	}
+
+	/* Check other parameters */
+	if (test->keysize == 0) {
+		vverbose("Algo name [%s]: key size [%d] not supported\n",
+		test->alg, test->keysize);
+		return ERROR_BAD_TEST_GENERIC;
+	}
+
+	if (test->loop < 2) {
+		vverbose(
+		"Algo name [%s]: number of iteration [%d] not supported\n",
+		test->alg, test->loop);
+		return ERROR_BAD_TEST_GENERIC;
+	}
+
+	if (!test->generate && test->bufsize == 0) {
+		vverbose("Algo name [%s]: bufsize [%d] not supported\n",
+			 test->alg, test->bufsize);
+		return ERROR_BAD_TEST_GENERIC;
+	}
+
+	return 0;
+}
+
+/* Extract Test command */
+static int extract_test(struct test_param *test, char *cmdline,
+				uint32_t linenum, int verbosity)
+{
+	char *elem;
+
+	verbose("\nExtract test [%s]\n", cmdline);
+	setdefault_param(test);
+
+	test->verbose = verbosity;
+
+	elem = strtok(cmdline, " ");
+
+	/* First element in the cmdline is algorithm name */
+	uppercase(test->alg, elem);
+	elem = strtok(NULL, " ");
+
+	while (elem != NULL) {
+		if (!strcmp(elem, "-k")) {
+			elem = strtok(NULL, " ");
+			if (!elem) {
+				vverbose(
+				"Test %s at line #%d bad key option\n",
+				test->alg, linenum);
+				return ERROR_BAD_TEST_GENERIC;
+			}
+			test->keysize = atoi(elem);
+		} else if (!strcmp(elem, "-i")) {
+			test->in_place = 1;
+		} else if (!strcmp(elem, "-n")) {
+			elem = strtok(NULL, " ");
+			if (!elem) {
+				vverbose(
+				"Test %s at line #%d bad loop option\n",
+				test->alg, linenum);
+				return ERROR_BAD_TEST_GENERIC;
+			}
+			test->loop = atoi(elem);
+		} else if (!strcmp(elem, "-r")) {
+			test->in_random = 1;
+		} else if (!strcmp(elem, "-s")) {
+			elem = strtok(NULL, " ");
+			if (!elem) {
+				vverbose(
+				"Test %s at line #%d bad buffer size option\n",
+				test->alg, linenum);
+				return ERROR_BAD_TEST_GENERIC;
+			}
+			test->bufsize = strsize_to_bytes(elem);
+			if (test->bufsize == (uint32_t)(-1))
+				return ERROR_BAD_TEST_GENERIC;
+		} else if (!strcmp(elem, "-g")) {
+			test->generate = true;
+		}
+
+		if (elem)
+			elem = strtok(NULL, " ");
+	}
+
+	return 0;
+}
+
+static int asym_digest(const struct test_param *test, uint32_t alg_id,
+		       TEEC_SharedMemory *in_shm, size_t *inSize)
+{
+	/*
+	 * Function hash input buffer (in_shm) of length inSize
+	 * Result of the hash is copied in the in_shm buffer and inSize
+	 * is updated with the new size to be used after
+	 */
+	TEEC_SharedMemory out_shm;
+	TEEC_Operation    op = {0};
+	TEEC_Result       res;
+
+	int      ret = 0;
+	uint32_t hash_id;
+	size_t   outSize;
+	uint32_t ret_origin;
+	int verbosity = test->verbose;
+
+	/* Allocate the output buffer function of the hash resulting */
+	if (TEE_ALG_GET_MAIN_ALG(alg_id) == TEE_MAIN_ALGO_ECDSA)
+		hash_id = TEE_ALG_GET_MAIN_ALG(TEE_ALG_SHA1);
+	else
+		hash_id = TEE_ALG_GET_DIGEST_HASH(alg_id);
+
+	outSize = hash_size(hash_id);
+
+	verbose("Asymmetric Digest %s input buffer\n", hash_name[hash_id]);
+
+	if (outSize == 0) {
+		vverbose("Unable to get hash size of hash id %d\n", hash_id);
+		return ERROR_BAD_TEST_DIGEST;
+	}
+
+	out_shm.flags  = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+	out_shm.buffer = NULL;
+	out_shm.size   = outSize;
+
+	res = TEEC_AllocateSharedMemory(&ctx, &out_shm);
+
+	if (check_res(res,
+		"TEEC_AllocateSharedMemory Asymmetric digest out_shm") != 0)
+		return ERROR_ALLOCATE_SHM;
+
+	/* Prepare Hash algorithm */
+	op.paramTypes = TEEC_PARAM_TYPES(
+		TEEC_MEMREF_TEMP_INPUT,
+		TEEC_VALUE_INPUT,
+		TEEC_VALUE_OUTPUT,
+		TEEC_NONE);
+	op.params[0].tmpref.buffer = (char *)hash_name[hash_id];
+	op.params[0].tmpref.size   = strlen(hash_name[hash_id]);
+
+	op.params[1].value.a = 0; /* Not used */
+
+	res = TEEC_InvokeCommand(&sess, TA_CRYPTO_PERF_CMD_PREPARE_ALG,
+							&op, &ret_origin);
+
+	if (check_res(res,
+	"TEEC_InvokeCommand Asymmetric digest prepare algorithm") != 0) {
+		ret = ERROR_TA_PREP_ALGO;
+		goto asym_digest_exit;
+	}
+
+	/* Execute Hash algorithm */
+	op.paramTypes = TEEC_PARAM_TYPES(
+		TEEC_MEMREF_PARTIAL_INPUT,
+		TEEC_MEMREF_PARTIAL_INOUT,
+		TEEC_VALUE_INPUT,
+		TEEC_NONE);
+	op.params[0].memref.parent = in_shm;
+	op.params[0].memref.offset = 0;
+	op.params[0].memref.size   = *inSize;
+	op.params[1].memref.parent = &out_shm;
+	op.params[1].memref.offset = 0;
+	op.params[1].memref.size   = outSize;
+
+	/*
+	 * First direction
+	 */
+	op.params[2].value.a = TEE_ALG_HASH_ALGO(hash_id);
+	op.params[2].value.b = 0;
+
+	res = TEEC_InvokeCommand(&sess, TA_CRYPTO_PERF_CMD_PROCESS,
+							&op, &ret_origin);
+
+	if (check_res(res,
+		"TEEC_InvokeCommand Asymmetric digest Process") != 0) {
+		if (res == TEE_ERROR_SHORT_BUFFER)
+			fprintf(stderr, "Expected output size %zu\n",
+					op.params[1].memref.size);
+		ret = ERROR_TA_CMD_PROCESS;
+		goto asym_digest_exit;
+	}
+
+	/* Copy hash result to input buffer and update the size */
+	if (*inSize < outSize) {
+		/* Input buffer was not enough big */
+		TEEC_ReleaseSharedMemory(in_shm);
+		in_shm->size = outSize;
+		res = TEEC_AllocateSharedMemory(&ctx, in_shm);
+
+		if (check_res(res,
+		"TEEC_AllocateSharedMemory Asymmetric digest in_shm") != 0) {
+			ret = ERROR_ALLOCATE_SHM;
+			goto asym_digest_exit;
+		}
+	}
+
+	memcpy(in_shm->buffer, out_shm.buffer, outSize);
+	*inSize = outSize;
+
+	verbose("Asymmetric Digest Done size: %zu\n", outSize);
+asym_digest_exit:
+	free_algo(test, &op);
+	TEEC_ReleaseSharedMemory(&out_shm);
+	return ret;
+}
+
+static int prepare_algo(const struct test_param *test, uint8_t *reverse,
+			uint32_t *alg_id, uint64_t *t_prepare)
+{
+	TEEC_Operation op = {0};
+	TEEC_Result    res;
+	uint32_t       ret_origin;
+	struct timespec t0, t1;
+	uint32_t command = TA_CRYPTO_PERF_CMD_PREPARE_ALG;
+
+	op.paramTypes = TEEC_PARAM_TYPES(
+		TEEC_MEMREF_TEMP_INPUT,
+		TEEC_VALUE_INPUT,
+		TEEC_VALUE_OUTPUT,
+		TEEC_NONE);
+	op.params[0].tmpref.buffer = (void *)test->alg;
+	op.params[0].tmpref.size   = strlen(test->alg);
+
+	op.params[1].value.a = test->keysize;
+	op.params[1].value.b = test->bufsize;
+
+	if (test->generate)
+		command = TA_CRYPTO_PERF_CMD_PREPARE_GEN;
+
+	get_current_time(&t0);
+	res = TEEC_InvokeCommand(&sess, command, &op, &ret_origin);
+
+	get_current_time(&t1);
+
+	*t_prepare = timespec_diff_ns(&t0, &t1);
+
+	*alg_id  = op.params[2].value.a; // Algorithm ID
+	*reverse = op.params[2].value.b; // If 1, reverse operation supported
+
+	if (check_res(res, "TEEC_InvokeCommand prepare algorithm") != 0)
+		return ERROR_TA_PREP_ALGO;
+
+	return 0;
+}
+
+static int free_algo(const struct test_param *test, TEEC_Operation *op)
+{
+	TEEC_Result res;
+	uint32_t ret_origin;
+	uint32_t command = TA_CRYPTO_PERF_CMD_FREE_ALG;
+
+	if (test->generate)
+		command = TA_CRYPTO_PERF_CMD_FREE_GEN;
+
+	res = TEEC_InvokeCommand(&sess, command, op, &ret_origin);
+
+	if (check_res(res, "TEEC_InvokeCommand free algorithm") != 0)
+		return ERROR_TA_FREE_ALGO;
+
+	return 0;
+}
+
+static int run_algo(const struct test_param *test, TEEC_Operation *op,
+		    struct statistics *stats, uint32_t cmd)
+{
+	TEEC_Result res;
+	uint32_t ret_origin;
+	struct timespec t0, t1;
+	int      ret;
+	uint32_t loop;
+	uint64_t diff_t;
+	int verbosity = test->verbose;
+
+	loop = test->loop;
+
+	while (loop-- > 0) {
+		get_current_time(&t0);
+
+		res = TEEC_InvokeCommand(&sess, cmd, op, &ret_origin);
+
+		if (check_res(res, "TEEC_InvokeCommand Process") != 0) {
+			ret = ERROR_TA_CMD_PROCESS;
+			goto run_algo_exit;
+		}
+
+		get_current_time(&t1);
+
+		diff_t = timespec_diff_ns(&t0, &t1);
+		update_stats(stats, diff_t);
+
+		if ((loop % (test->loop / 10)) == 0)
+			vverbose(".");
+	}
+
+	vverbose("\n");
+
+	ret = free_algo(test, op);
+
+run_algo_exit:
+	return ret;
+}
+
+/* Execute Tests */
+static int run_test(struct test_param *test, FILE *log)
+{
+	TEEC_SharedMemory in_shm, out_shm;
+	TEEC_Operation    op = {0};
+	TEEC_Result       res;
+	struct statistics stats_enc, stats_dec;
+	uint64_t t_prepare  = 0;
+	uint8_t  reverse    = 0; /* Reverse operation */
+	uint32_t alg_id;
+	int      ret;
+	size_t   inSize    = test->bufsize;
+	size_t   outSize   = test->bufsize;
+	int      verbosity = test->verbose;
+
+	memset(&stats_enc, 0, sizeof(stats_enc));
+	memset(&stats_dec, 0, sizeof(stats_dec));
+	ret = check_test(test);
+	if (ret != 0) {
+		verbose("Test not executed because of bad parameters\n");
+		goto run_test_exit;
+	}
+
+	/* Prepare algorithm (e.g. Keys, working buffer, ...) */
+	ret = prepare_algo(test, &reverse, &alg_id, &t_prepare);
+	if (ret != 0)
+		goto run_test_exit;
+
+	if (test->generate) {
+		verbose("\nTest Generation %s\n", test->alg);
+		verbose("Keysize:   %d\n", test->keysize);
+		verbose("Loop:      %d\n", test->loop);
+
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+						 TEEC_NONE, TEEC_NONE);
+
+		op.params[0].value.a = test->keysize;
+
+		ret = run_algo(test, &op, &stats_enc,
+			       TA_CRYPTO_PERF_CMD_GENERATE);
+		if (ret != 0)
+			goto run_test_exit;
+
+		goto run_test_end;
+	}
+
+	if (TEE_ALG_GET_CLASS(alg_id) == TEE_OPERATION_KEY_DERIVATION)
+		inSize = test->keysize / 8;
+
+
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_CIPHER:
+		ret = cipher_size(alg_id, test->bufsize);
+		if (ret < 0)
+			goto run_test_exit;
+
+		if (TEE_ALG_GET_CHAIN_MODE(alg_id) == TEE_CHAIN_MODE_XTS) {
+			if (ret == TEE_AES_BLOCK_SIZE) {
+				/* This is just for the final */
+				ret *= 2;
+			}
+		}
+
+		if (TEE_ALG_GET_CHAIN_MODE(alg_id) == TEE_CHAIN_MODE_CTS) {
+			if (ret <= (int)(TEE_AES_BLOCK_SIZE * 2)) {
+				/* This is just for the final */
+				ret += (2 * TEE_AES_BLOCK_SIZE);
+			}
+		}
+
+		outSize = ret;
+		break;
+
+	case TEE_OPERATION_DIGEST:
+		/* Digest operation */
+		/* Define Output size */
+		outSize = hash_size(TEE_ALG_GET_MAIN_ALG(alg_id));
+
+		if (test->in_place) {
+			verbose(
+			"Digest operation doesn't support test in place\n");
+			test->in_place = 0;
+		}
+
+		if (outSize == 0) {
+			ret = ERROR_BAD_TEST_DIGEST;
+			goto run_test_exit;
+		}
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_CIPHER:
+		/* Asymmetric Cipher operation */
+		/* Check Input size and return Output size */
+		ret = asymcipher_sizes(alg_id, test);
+
+		if (ret < 0)
+			goto run_test_exit;
+
+		if (test->in_place) {
+			verbose(
+		"Symmetric Cipher operation doesn't support test in place\n");
+			test->in_place = 0;
+		}
+
+		outSize = ret;
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		/* Asymmetric Digest operation */
+		/*
+		 * For this operation, the input message must be digest and
+		 * this is the digest which is signed/verified
+		 */
+		if (test->in_place) {
+			verbose(
+			"Symmetric Digest doesn't support test in place\n");
+			test->in_place = 0;
+		}
+		/* Force the outSize to be 512 */
+		outSize = 512;
+		break;
+
+	case TEE_OPERATION_KEY_DERIVATION:
+		/* Key Derivation operation */
+		outSize = ROUNDUP(test->keysize / 8, 8);
+		break;
+
+	case TEE_OPERATION_AE:
+		if (test->in_place) {
+			verbose(
+			"Authenticated Enc doesn't support test in place\n");
+			test->in_place = 0;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	/* Allocate shared memory */
+	in_shm.flags  = TEEC_MEM_INPUT;
+	in_shm.buffer = NULL;
+	in_shm.size   = MAX(inSize, outSize);
+
+	if (test->in_place) {
+		/* Use same buffer for input and output */
+		in_shm.flags |= TEEC_MEM_OUTPUT;
+	}
+
+	res = TEEC_AllocateSharedMemory(&ctx, &in_shm);
+	if (check_res(res, "TEEC_AllocateSharedMemory in_shm") != 0) {
+		ret = ERROR_ALLOCATE_SHM;
+		goto run_test_exit;
+	}
+
+	if (test->in_random) {
+		ret = read_random(in_shm.buffer, in_shm.size);
+		if (ret) {
+			ret = ERROR_READ_RANDOM_FILE;
+			goto run_test_exit;
+		}
+	} else {
+		memset(in_shm.buffer, 0, in_shm.size);
+	}
+
+	out_shm.flags  = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+	out_shm.buffer = NULL;
+	/*
+	 * Allocate a out buffer size with the max size
+	 * between input size (in case of revert operation)
+	 * and expected output size of the first direction
+	 */
+	out_shm.size = (inSize > outSize) ? inSize : outSize;
+
+	if (!(test->in_place)) {
+		res = TEEC_AllocateSharedMemory(&ctx, &out_shm);
+		if (check_res(res, "TEEC_AllocateSharedMemory out_shm") != 0) {
+			ret = ERROR_ALLOCATE_SHM;
+			goto run_test_exit;
+		}
+	}
+
+	op.paramTypes = TEEC_PARAM_TYPES(
+		TEEC_MEMREF_PARTIAL_INPUT,
+		TEEC_MEMREF_PARTIAL_INOUT,
+		TEEC_VALUE_INPUT,
+		TEEC_NONE);
+
+	op.params[0].memref.parent = &in_shm;
+	op.params[0].memref.offset = 0;
+	op.params[0].memref.size   = inSize;
+	op.params[1].memref.parent = (test->in_place) ? &in_shm : &out_shm;
+	op.params[1].memref.offset = 0;
+	op.params[1].memref.size   = outSize;
+
+	/*
+	 * First direction
+	 */
+	op.params[2].value.a = alg_id;
+	op.params[2].value.b = 0;
+
+
+	/*
+	 * Check if an operation must be done before doing the requested
+	 * operation.
+	 */
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		/*
+		 * Input buffer must be digest and this is the hash
+		 * resulting which is signed/verified
+		 */
+		ret = asym_digest(test, alg_id, &in_shm, &inSize);
+		if (ret != 0)
+			goto run_test_exit;
+		/*
+		 * Correct the input buffer in the operation struct
+		 */
+		op.params[0].memref.parent = &in_shm;
+		op.params[0].memref.size   = inSize;
+		break;
+
+	default:
+		break;
+	}
+
+	verbose("\nTest Encryption %s\n", test->alg);
+	verbose("In place:  %d\n", test->in_place);
+	verbose("In Random: %d\n", test->in_random);
+	verbose("Keysize:   %d\n", test->keysize);
+	verbose("Loop:      %d\n", test->loop);
+	verbose("Size In:   %zu\n", inSize);
+	if (!(test->in_place))
+		verbose("Size Out:  %zu\n", outSize);
+
+	OPEN_DATA(test->alg);
+
+	stats_enc.data_size = inSize;
+
+	ret = run_algo(test, &op, &stats_enc, TA_CRYPTO_PERF_CMD_PROCESS);
+
+	if (ret != 0)
+		goto run_test_exit;
+
+	if (!reverse)
+		goto run_test_end;
+
+	/*
+	 * Other direction
+	 */
+	op.params[2].value.b = 1;
+
+	/*
+	 * Check algo to prepare revert operation
+	 */
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		/*
+		 * For Asymmetric signature, the output generated
+		 * becomes an input for the verify operation
+		 */
+		outSize = inSize + op.params[1].memref.size;
+		verbose("\nTest Decryption %s\n", test->alg);
+		verbose("In place:  %d\n", test->in_place);
+		verbose("In Random: %d\n", test->in_random);
+		verbose("Keysize:   %d\n", test->keysize);
+		verbose("Loop:      %d\n", test->loop);
+		verbose("Size In:   %zu\n", outSize);
+
+		break;
+
+	default:
+		if (TEE_ALG_GET_CHAIN_MODE(alg_id) == TEE_CHAIN_MODE_XTS) {
+			if (inSize == TEE_AES_BLOCK_SIZE) {
+				/* This is just for the final */
+				outSize = TEE_AES_BLOCK_SIZE;
+				inSize *= 2;
+			}
+		}
+
+		if (TEE_ALG_GET_CHAIN_MODE(alg_id) == TEE_CHAIN_MODE_CTS) {
+			if (inSize <= (TEE_AES_BLOCK_SIZE * 2)) {
+				/* This is just for the final */
+				outSize = inSize;
+				inSize += (2 * TEE_AES_BLOCK_SIZE);
+			}
+		}
+
+		/* Revert in and out parameters */
+		op.params[0].memref.size   = outSize;
+		op.params[1].memref.size   = inSize;
+
+		/*
+		 * If not using same buffer for input and output,
+		 * copy out to in for reverse operation
+		 */
+		if (!(test->in_place))
+			memcpy(in_shm.buffer, out_shm.buffer, outSize);
+
+		verbose("\nTest Decryption %s\n", test->alg);
+		verbose("In place:  %d\n", test->in_place);
+		verbose("In Random: %d\n", test->in_random);
+		verbose("Keysize:   %d\n", test->keysize);
+		verbose("Loop:      %d\n", test->loop);
+		verbose("Size In:   %zu\n", outSize);
+		if (!(test->in_place))
+			verbose("Size Out:  %zu\n", inSize);
+		break;
+	}
+
+	stats_dec.data_size = outSize;
+	ret = run_algo(test, &op, &stats_dec, TA_CRYPTO_PERF_CMD_PROCESS);
+
+	if (ret != 0)
+		goto run_test_exit;
+
+run_test_end:
+	ret = 0;
+	fprintf(stderr, "\nTest Result for %s\n", test->alg);
+	fprintf(stderr, "** Preparation (Key Generation) **\n");
+	fprintf(stderr, "time=%gμs\n", (double)(t_prepare) / 1000);
+	if (test->generate)
+		fprintf(stderr, "** Key generation **\n");
+	else
+		fprintf(stderr, "** Encryption direction **\n");
+	fprintf(stderr,
+		"min=%gμs max=%gμs mean=%gμs stddev=%gμs (%g MiB/s)\n",
+		(stats_enc.min / 1000),
+		(stats_enc.max / 1000),
+		(stats_enc.m / 1000),
+		(stddev(&stats_enc) / 1000),
+		mb_per_sec(stats_enc.data_size, stats_enc.m / 1000));
+
+	if (reverse) {
+		fprintf(stderr, "** Decryption direction **\n");
+		fprintf(stderr,
+		"min=%gμs max=%gμs mean=%gμs stddev=%gμs (%g MiB/s)\n",
+		(stats_dec.min / 1000),
+		(stats_dec.max / 1000),
+		(stats_dec.m / 1000),
+		(stddev(&stats_dec) / 1000),
+		mb_per_sec(stats_dec.data_size, stats_dec.m / 1000));
+	}
+	fprintf(stderr, "\n");
+
+	print_log_result(log, reverse, test->generate, &stats_enc, &stats_dec,
+			 ((double)(t_prepare) / 1000));
+
+run_test_exit:
+	if (log)
+		if (ret != 0)
+			fprintf(log, "Execution error 0x%08X\n", ret);
+
+	CLOSE_DATA;
+
+	TEEC_ReleaseSharedMemory(&in_shm);
+	TEEC_ReleaseSharedMemory(&out_shm);
+	return ret;
+
+}
+
+static int execute_single(struct test_param *test)
+{
+	int ret;
+
+	ret = open_ta();
+
+	if (ret == 0)
+		ret = run_test(test, NULL);
+
+	return ret;
+}
+
+static int execute_list(char *inFilename, char *logFilename, int verbosity)
+{
+	FILE     *infile = NULL;
+	FILE     *logfile = NULL;
+	uint32_t linenum = 0;
+	int      ret = 0;
+	char     *cmd = NULL;
+	size_t   len = 0;
+	ssize_t  read;
+	struct test_param test;
+
+	if (logFilename[0])
+		verbose("** Execute test file [%s] and log to [%s] **\n\n",
+				inFilename, logFilename);
+	else
+		verbose("** Execute test file [%s] **\n\n", inFilename);
+
+	infile = fopen(inFilename, "r");
+
+	if (!infile) {
+		fprintf(stderr, "Open file [%s] error\n", inFilename);
+		ret = ERROR_BAD_TEST_GENERIC;
+		goto execute_list_exit;
+	}
+
+	/* if log file defined, open it in append mode */
+	if (logFilename[0]) {
+		logfile = fopen(logFilename, "a");
+
+		if (!logfile) {
+			fprintf(stderr, "Open log file [%s] error\n",
+				logFilename);
+			ret = ERROR_BAD_TEST_GENERIC;
+			goto execute_list_exit;
+		}
+	}
+
+	ret = open_ta();
+	if (ret != 0)
+		goto execute_list_exit;
+
+	print_log_header(logfile);
+
+	/* Read file */
+	while ((read = getline(&cmd, &len, infile)) != -1) {
+		if (read > 0)
+			cmd[read - 1] = '\0';
+
+		if ((read != 0) && (strlen(cmd) != 0)) {
+			/* Replace "\n" by '\0' */
+			cmd[read - 1] = '\0';
+			if (extract_test(&test, cmd, linenum, verbosity) == 0) {
+				/* Log test */
+				print_log_test(logfile, &test);
+
+				/* Execute the test */
+				ret = run_test(&test, logfile);
+				if (ret & ERROR_BAD_TEST_MASK)
+					verbose(
+					"Wrong test definition at line #%d\n\n",
+					linenum);
+				else if (ret < 0)
+					verbose(
+				"Test @line #%d execution error %0xX\n\n",
+				linenum, ret);
+			} else {
+				verbose(
+			"Test not executed because of bad parameters\n");
+				verbose(
+			"Wrong test definition at line #%d\n\n", linenum);
+			}
+		}
+
+		linenum++;
+	}
+
+	ret = 0;
+
+	free(cmd);
+
+execute_list_exit:
+	if (infile)
+		fclose(infile);
+	if (logfile) {
+		fflush(logfile);
+		fsync(fileno(logfile));
+		fclose(logfile);
+	}
+
+	return ret;
+}
+
+/* Helpers */
+static void cipher_usage(void)
+{
+	fprintf(stderr, "\nNB: Cipher operation:\n");
+	fprintf(stderr, "Key size:\n");
+	fprintf(stderr, "  -AES_xxx: 128, 192 or 256 bits\n");
+	fprintf(stderr, "  -DES_xxx: 64 bits\n");
+	fprintf(stderr, "  -DES3_xxx: 128 or 192 bits\n");
+	fprintf(stderr, "Buffer size:\n");
+	fprintf(stderr,
+	"  - AES_xxx:  minimum is %ld bytes and must be a multiple of %ld\n",
+	TEE_AES_BLOCK_SIZE, TEE_AES_BLOCK_SIZE);
+	fprintf(stderr,
+	"  - DES_xxx:  minimum is %ld bytes and must be a multiple of %ld\n",
+	TEE_AES_BLOCK_SIZE, TEE_DES_BLOCK_SIZE);
+	fprintf(stderr,
+	"  - DES3_xxx: minimum is %ld bytes and must be a multiple of %ld\n",
+	TEE_AES_BLOCK_SIZE, TEE_DES_BLOCK_SIZE);
+}
+
+static void asymcipher_usage(void)
+{
+	fprintf(stderr,
+	"\nNB: Buffer size for Asymmetric Cipher operation:\n");
+	fprintf(stderr,
+	"  - RSAES_PKCS1_V1_5:             mLen <= k - 11\n");
+	fprintf(stderr,
+	"  - RSAES_PKCS1_OAEP_MGF1_SHAxxx: mLen <= k - 2 * hLen - 2\n");
+	fprintf(stderr, "Where mLen = Buffer size in bytes\n");
+	fprintf(stderr, "      k    = keysize in bytes\n");
+	fprintf(stderr, "      hLen = hash length in bytes\n");
+}
+
+static void digest_usage(void)
+{
+	fprintf(stderr,
+	"\nNB: key size for algorithm with Digest operation:\n");
+	fprintf(stderr,
+	"  - with a hash MD5 to SHA256:    minimum size is 512\n");
+	fprintf(stderr,
+	"  - with a hash SHA384 to SHA512: minimum size is 1024\n");
+	fprintf(stderr,
+	"  - ECDSA_PXXX:                   key size is XXX\n");
+}
+
+static void mac_usage(void)
+{
+	fprintf(stderr, "\nNB: key size for MAC operation:\n");
+	fprintf(stderr, "  - AES:    size is 128, 192 or 256\n");
+	fprintf(stderr, "  - DES:    size is 64\n");
+	fprintf(stderr, "  - DES3:   size is 128 or 192\n");
+	fprintf(stderr, "  - MD5:    size is 64 to 512\n");
+	fprintf(stderr, "  - SHA1:   size is 80 to 512\n");
+	fprintf(stderr, "  - SHA224: size is 112 to 512\n");
+	fprintf(stderr, "  - SHA256: size is 192 to 1024\n");
+	fprintf(stderr, "  - SHA384: size is 256 to 1024\n");
+	fprintf(stderr, "  - SHA512: size is 256 to 1024\n");
+}
+
+static void keyderive_usage(void)
+{
+	fprintf(stderr, "\nNB: key size for Key Derivation operation:\n");
+	fprintf(stderr, "  - DH:         size is 256 to 2048\n");
+	fprintf(stderr, "  - ECDSA_PXXX: key size is XXX\n");
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "Crypto performance testing tool for OP-TEE\n\n");
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, "\t%s -h\n", progname);
+	fprintf(stderr, "\t%s -infile test_file [-log log_file] [-v level]\n",
+	progname);
+	fprintf(stderr,
+		"\t%s -alg alg_name [-g] [-i] [-n loops] [-r] [-s bufsize] [-v level]\n",
+		progname);
+	fprintf(stderr, "\t%s -alglist\n", progname);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "\t-h        Print this help and exit\n");
+	fprintf(stderr,
+	"  Below options are used to execute all performance tests defined\n");
+	fprintf(stderr, "  in the input file.\n");
+	fprintf(stderr,
+	"\t-infile   Input file defining the list of tests to be run\n");
+	fprintf(stderr, "\t-log      Log result file\n");
+	fprintf(stderr,
+	"  Below options are used to execute a single performance test\n");
+	fprintf(stderr,
+	"\t-alg      Algorithm name (use option -alglist to get list)\n");
+	fprintf(stderr,
+	"\t-k        Key size in bits [%d]\n", DEFAULT_KEY_SIZE);
+	fprintf(stderr, "\t-g        Generate key\n");
+	fprintf(stderr, "\t-i        Use same buffer for input and output\n");
+	fprintf(stderr,
+	"\t-n        Number of iterations (2 minimum) [%d]\n", DEFAULT_LOOP);
+	fprintf(stderr,
+	"\t-r        Initialize input data with random\n");
+	fprintf(stderr,
+	"\t-s        Buffer size if no unit in bytes [%d]\n",
+	DEFAULT_BUFFER_SIZE);
+	fprintf(stderr,
+	"\t          Unit can be M for MBytes, K for KBytes\n");
+	fprintf(stderr, "\t          E.g -s 1M define a size of 1 MBytes\n");
+	fprintf(stderr, "\t-v        Verbose level (1 or 2)\n");
+	fprintf(stderr, "\t-alglist  List all Algorithms' name available\n");
+	mac_usage();
+	cipher_usage();
+	asymcipher_usage();
+	digest_usage();
+	keyderive_usage();
+	fprintf(stderr, "\n");
+}
+
+static int usage_alg_list(void)
+{
+	uint8_t idx;
+	char    *list;
+	int		ret;
+
+	ret = open_ta();
+	if (ret != 0)
+		return ret;
+
+	/* Print all algorithms name */
+	ret =  getcaps_ta();
+	if (ret != 0)
+		return ret;
+
+	list = name_alg_list;
+	fprintf(stderr, "List of Algorithms' name supported\n");
+
+	for (idx = 0; idx < ta_caps.nb_algo; idx++) {
+		fprintf(stderr, "\t%s\n", list);
+		list += strlen(list) + sizeof(char);
+	}
+
+	return 0;
+}
+
+int crypto_perf_runner_cmd_parser(int argc, char *argv[])
+{
+	int  ret;
+	int  idx;
+	int  verbosity = 0;
+	char inputfile[256] = {0};
+	char logfile[256] = {0};
+	size_t  len;
+	struct test_param test_param;
+
+	/* If there is no parameter */
+	if (argc < 2) {
+		usage(argv[0]);
+		return 0;
+	}
+
+	/* Parse command line to find if helpers or list of tests */
+	for (idx = 1; idx < argc; idx++) {
+		if (!strcmp(argv[idx], "-h")) {
+			usage(argv[0]);
+			return 0;
+		}
+		if (!strcmp(argv[idx], "-alglist")) {
+			ret = usage_alg_list();
+			goto exit_err;
+		}
+		if (!strcmp(argv[idx], "-infile")) {
+			len = strlen(argv[idx + 1]);
+			if ((idx + 1) == argc)
+				goto help;
+
+			if (len > sizeof(inputfile)) {
+				fprintf(stderr,
+			"Input file name too long, must be %zu caracters max\n",
+			sizeof(inputfile));
+				usage(argv[0]);
+				return 1;
+			}
+
+			memcpy(inputfile, argv[idx + 1], len);
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-log")) {
+			if ((idx + 1) == argc)
+				goto help;
+
+			len = strlen(argv[idx + 1]);
+			if (len > sizeof(logfile)) {
+				fprintf(stderr,
+			"Input file name too long, must be %zu caracters max\n",
+			sizeof(logfile));
+				usage(argv[0]);
+				return 1;
+			}
+
+			memcpy(logfile, argv[idx + 1], len);
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-v")) {
+			if ((idx + 1) == argc)
+				goto help;
+			verbosity = atoi(argv[idx + 1]);
+			idx += 1; /* Next parameter */
+		}
+	}
+
+	/* Check if there is a list of test */
+	if (inputfile[0]) {
+		ret = execute_list(inputfile, logfile, verbosity);
+		goto exit_err;
+	}
+
+	setdefault_param(&test_param);
+
+	/* Parse command line to find single test parameter */
+	for (idx = 1; idx < argc; idx++) {
+		if (!strcmp(argv[idx], "-alg")) {
+			if ((idx + 1) == argc)
+				goto help;
+
+			len = strlen(argv[idx + 1]);
+			if (len > sizeof(test_param.alg)) {
+				fprintf(stderr, "Algorithm name too long\n");
+				goto help;
+			}
+
+			/* Copy and convert string to upper case */
+			uppercase(test_param.alg, argv[idx + 1]);
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-k")) {
+			if ((idx + 1) == argc)
+				goto help;
+
+			test_param.keysize = atoi(argv[idx + 1]);
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-i")) {
+			test_param.in_place = 1;
+		} else if (!strcmp(argv[idx], "-n")) {
+			if ((idx + 1) == argc)
+				goto help;
+
+			test_param.loop = atoi(argv[idx + 1]);
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-r")) {
+			test_param.in_random = 1;
+		} else if (!strcmp(argv[idx], "-s")) {
+			if ((idx + 1) == argc)
+				goto help;
+
+			test_param.bufsize = strsize_to_bytes(argv[idx + 1]);
+			if (test_param.bufsize == (uint32_t)(-1))
+				goto help;
+
+			idx += 1; /* Next parameter */
+		} else if (!strcmp(argv[idx], "-g")) {
+			test_param.generate = true;
+		}
+	}
+
+	test_param.verbose = verbosity;
+	ret = execute_single(&test_param);
+	if (ret & ERROR_BAD_TEST_MASK)
+		goto print_usage;
+	else
+		verbose("Test execution returned 0x%08X\n\n", ret);
+
+	goto exit_err;
+
+help:
+	ret = ERROR_BAD_TEST_GENERIC;
+
+print_usage:
+	usage(argv[0]);
+
+exit_err:
+	close_ta(ret);
+	return ret;
+}
diff --git a/host/xtest/regression_nxp/crypto/cipher.c b/host/xtest/regression_nxp/crypto/cipher.c
new file mode 100644
index 0000000..76601b4
--- /dev/null
+++ b/host/xtest/regression_nxp/crypto/cipher.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nxp_crypto_test_vectors.h"
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+
+#include <ta_crypt.h>
+#include <utee_defines.h>
+#include <util.h>
+
+static TEEC_Result ta_crypt_cipher_init(ADBG_Case_t *c, TEEC_Session *s,
+					TEE_OperationHandle oph, const void *iv,
+					size_t iv_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	if (iv) {
+		op.params[1].tmpref.buffer = (void *)iv;
+		op.params[1].tmpref.size = iv_len;
+
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						 TEEC_MEMREF_TEMP_INPUT,
+						 TEEC_NONE, TEEC_NONE);
+	} else {
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+						 TEEC_NONE, TEEC_NONE);
+	}
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_INIT, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_cipher_update(ADBG_Case_t *c, TEEC_Session *s,
+					  TEE_OperationHandle oph,
+					  const void *src, size_t src_len,
+					  void *dst, size_t *dst_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)src;
+	op.params[1].tmpref.size = src_len;
+
+	op.params[2].tmpref.buffer = dst;
+	op.params[2].tmpref.size = *dst_len;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_UPDATE, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	if (res == TEEC_SUCCESS)
+		*dst_len = op.params[2].tmpref.size;
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_cipher_final(ADBG_Case_t *c, TEEC_Session *s,
+					 TEE_OperationHandle oph,
+					 const void *src, size_t src_len,
+					 void *dst, size_t *dst_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)src;
+	op.params[1].tmpref.size = src_len;
+
+	op.params[2].tmpref.buffer = (void *)dst;
+	op.params[2].tmpref.size = *dst_len;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_DO_FINAL, &op,
+				 &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	if (res == TEEC_SUCCESS)
+		*dst_len = op.params[2].tmpref.size;
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_cmd_generate_key(ADBG_Case_t *c, TEEC_Session *s,
+					     TEE_ObjectHandle o,
+					     uint32_t key_size)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+	uint8_t *buf = NULL;
+	size_t blen = 0;
+
+	assert((uintptr_t)o <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)o;
+	op.params[0].value.b = key_size;
+
+	op.params[1].tmpref.buffer = buf;
+	op.params[1].tmpref.size = blen;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_GENERATE_KEY, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	free(buf);
+	return res;
+}
+
+static void nxp_crypto_001(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+	uint32_t ret_orig = 0;
+
+	size_t inc = 0;
+	size_t off = 0;
+	size_t out_size = 0;
+	uint32_t key_size = 128;
+	uint8_t *msg = NULL;
+	uint8_t *cipher = NULL;
+	uint8_t *de_msg = NULL;
+
+#define SIZE_CTR_MSG 240
+
+	cipher = calloc(1, SIZE_CTR_MSG);
+	if (!ADBG_EXPECT_NOT_NULL(c, cipher))
+		goto out_free;
+
+	msg = calloc(1, SIZE_CTR_MSG);
+	if (!ADBG_EXPECT_NOT_NULL(c, msg))
+		goto out_free;
+
+	de_msg = calloc(1, SIZE_CTR_MSG);
+	if (!ADBG_EXPECT_NOT_NULL(c, de_msg))
+		goto out_free;
+
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out_free;
+
+	/* Generate a 128 bits AES key */
+	res = ta_crypt_cmd_allocate_transient_object(c, &session, TEE_TYPE_AES,
+						     key_size, &key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_generate_key(c, &session, key_handle, key_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	for (inc = 1; inc <= SIZE_CTR_MSG; ++inc) {
+		/* Fill message with 'a' */
+		memset(msg, 'a', SIZE_CTR_MSG);
+
+		/* Fill cipher with 'U' */
+		memset(cipher, 'U', SIZE_CTR_MSG);
+
+		/* Fill decrypted message with 'U' */
+		memset(de_msg, 'U', SIZE_CTR_MSG);
+
+		/*
+		 * 1st. Encryption
+		 */
+		res = ta_crypt_cmd_allocate_operation(c, &session, &op,
+						      TEE_ALG_AES_CTR,
+						      TEE_MODE_ENCRYPT,
+						      key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_cmd_set_operation_key(c, &session, op,
+						     key_handle);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_cipher_init(c, &session, op, ciph_data_128_iv,
+					   ARRAY_SIZE(ciph_data_128_iv));
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		for (off = 0; off < (SIZE_CTR_MSG - inc); off += inc) {
+			out_size = inc;
+			res = ta_crypt_cipher_update(c, &session, op, &msg[off],
+						     inc, &cipher[off],
+						     &out_size);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+				Do_ADBG_Log("Encrypt incremental %zu", inc);
+				goto out;
+			}
+		}
+
+		out_size = SIZE_CTR_MSG - off;
+		res = ta_crypt_cipher_final(c, &session, op, &msg[off],
+					    SIZE_CTR_MSG - off, &cipher[off],
+					    &out_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+			Do_ADBG_Log("Final Encrypt incremental %zu", inc);
+			goto out;
+		}
+
+		res = ta_crypt_cmd_free_operation(c, &session, op);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		/*
+		 * 2nd. Encryption
+		 */
+		res = ta_crypt_cmd_allocate_operation(c, &session, &op,
+						      TEE_ALG_AES_CTR,
+						      TEE_MODE_DECRYPT,
+						      key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_cmd_set_operation_key(c, &session, op,
+						     key_handle);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_cipher_init(c, &session, op, ciph_data_128_iv,
+					   ARRAY_SIZE(ciph_data_128_iv));
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		for (off = 0; off < (SIZE_CTR_MSG - inc); off += inc) {
+			out_size = inc;
+
+			res = ta_crypt_cipher_update(c, &session, op,
+						     &cipher[off], inc,
+						     &de_msg[off], &out_size);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+				Do_ADBG_Log("Decrypt incremental %zu", inc);
+				goto out;
+			}
+		}
+
+		out_size = SIZE_CTR_MSG - off;
+		res = ta_crypt_cipher_final(c, &session, op, &cipher[off],
+					    SIZE_CTR_MSG - off, &de_msg[off],
+					    &out_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+			Do_ADBG_Log("Final Decrypt incremental %zu", inc);
+			goto out;
+		}
+
+		res = ta_crypt_cmd_free_operation(c, &session, op);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		/* Compare original message with decrypted message */
+		(void)ADBG_EXPECT_BUFFER(c, msg, SIZE_CTR_MSG, de_msg,
+					 SIZE_CTR_MSG);
+	}
+
+	res = ta_crypt_cmd_free_transient_object(c, &session, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+out:
+	TEEC_CloseSession(&session);
+
+out_free:
+	if (cipher)
+		free(cipher);
+	if (msg)
+		free(msg);
+	if (de_msg)
+		free(de_msg);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0001, nxp_crypto_001,
+		 "Test TEE cipher AES CTR operation byte incremental in/out");
+
+static void nxp_crypto_002(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+	TEE_Attribute key_attr = {};
+	uint32_t ret_orig = 0;
+
+	size_t off = 0;
+	size_t out_size = 0;
+	uint8_t *de_msg = NULL;
+	uint32_t key_size = 0;
+	size_t msg_size = ARRAY_SIZE(ciph_data_ref2);
+
+	de_msg = calloc(1, msg_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, de_msg))
+		goto out_free;
+
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out_free;
+
+	key_attr.attributeID = TEE_ATTR_SECRET_VALUE;
+	key_attr.content.ref.buffer = (void *)ciph_data_key2;
+	key_attr.content.ref.length = ARRAY_SIZE(ciph_data_key2);
+
+	key_size = key_attr.content.ref.length * 8;
+
+	res = ta_crypt_cmd_allocate_transient_object(c, &session, TEE_TYPE_AES,
+						     key_size, &key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_populate_transient_object(c, &session, key_handle,
+						     &key_attr, 1);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_allocate_operation(c, &session, &op, TEE_ALG_AES_CTR,
+					      TEE_MODE_DECRYPT, key_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_set_operation_key(c, &session, op, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cipher_init(c, &session, op, ciph_data_iv2,
+				   ARRAY_SIZE(ciph_data_iv2));
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	for (off = 0; off < msg_size; off++) {
+		out_size = 1;
+		res = ta_crypt_cipher_update(c, &session, op,
+					     &ciph_data_out2[off], 1,
+					     &de_msg[off], &out_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, out_size, ==, 1))
+			goto out;
+	}
+
+	res = ta_crypt_cmd_free_operation(c, &session, op);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/* Compare original message with decrypted message */
+	(void)ADBG_EXPECT_BUFFER(c, ciph_data_ref2, msg_size, de_msg, msg_size);
+
+	res = ta_crypt_cmd_free_transient_object(c, &session, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+out:
+	TEEC_CloseSession(&session);
+
+out_free:
+	if (de_msg)
+		free(de_msg);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0002, nxp_crypto_002,
+		 "Test TEE cipher AES CTR decrypt byte per byte");
+
+#define BIG_BUFFER_SIZE 133120
+
+static void nxp_crypto_003(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+	TEE_Attribute key_attr = {};
+	size_t key_size = 0;
+	size_t out_size = 0;
+	uint32_t ret_orig = 0;
+
+	uint8_t *big_input = NULL;
+	uint8_t *big_output = NULL;
+	uint8_t *dec_input = NULL;
+	size_t len_data_ref = ARRAY_SIZE(ciph_data_ref);
+
+	unsigned int i = 0;
+	unsigned int nb_blocks = BIG_BUFFER_SIZE / len_data_ref;
+	size_t data_left = BIG_BUFFER_SIZE % len_data_ref;
+	size_t offset = 0;
+
+	big_input = calloc(1, BIG_BUFFER_SIZE);
+	if (!ADBG_EXPECT_NOT_NULL(c, big_input))
+		goto out_free;
+
+	big_output = calloc(1, BIG_BUFFER_SIZE);
+	if (!ADBG_EXPECT_NOT_NULL(c, big_output))
+		goto out_free;
+
+	dec_input = calloc(1, BIG_BUFFER_SIZE);
+	if (!ADBG_EXPECT_NOT_NULL(c, dec_input))
+		goto out_free;
+
+	Do_ADBG_Log("Allocated big Input buffer @%p - %d bytes", big_input,
+		    BIG_BUFFER_SIZE);
+	Do_ADBG_Log("Allocated big Output buffer @%p - %d bytes", big_output,
+		    BIG_BUFFER_SIZE);
+	Do_ADBG_Log("Allocated big Decrypt buffer @%p - %d bytes", dec_input,
+		    BIG_BUFFER_SIZE);
+
+	/* Were copying the data: first the full blocks then the remainder */
+	for (i = 0; i < nb_blocks; i++){
+		memcpy(big_input + offset, ciph_data_ref, len_data_ref);
+		offset += len_data_ref;
+	}
+	if (data_left)
+		memcpy(big_input + offset, ciph_data_ref, data_left);
+
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out_free;
+
+	key_attr.attributeID = TEE_ATTR_SECRET_VALUE;
+	key_attr.content.ref.buffer = (void *)ciph_data_aes_key;
+	key_attr.content.ref.length = ARRAY_SIZE(ciph_data_aes_key);
+
+	key_size = key_attr.content.ref.length * 8;
+
+	res = ta_crypt_cmd_allocate_operation(c, &session, &op, TEE_ALG_AES_CTR,
+					      TEE_MODE_ENCRYPT, key_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_allocate_transient_object(c, &session, TEE_TYPE_AES,
+						     key_size, &key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_populate_transient_object(c, &session, key_handle,
+						     &key_attr, 1);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_set_operation_key(c, &session, op, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cipher_init(c, &session, op, ciph_data_128_iv,
+				   ARRAY_SIZE(ciph_data_128_iv));
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	out_size = BIG_BUFFER_SIZE;
+	memset(big_output, 0x55, out_size);
+	res = ta_crypt_cipher_final(c, &session, op, big_input, BIG_BUFFER_SIZE,
+				    big_output, &out_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_free_operation(c, &session, op);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/*
+	 * Decrypt output cipher generated and verify it with the input
+	 * buffer.
+	 */
+	res = ta_crypt_cmd_allocate_operation(c, &session, &op, TEE_ALG_AES_CTR,
+					      TEE_MODE_DECRYPT, key_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_set_operation_key(c, &session, op, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cipher_init(c, &session, op, ciph_data_128_iv,
+				   ARRAY_SIZE(ciph_data_128_iv));
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	out_size = BIG_BUFFER_SIZE;
+	memset(dec_input, 0x55, out_size);
+	res = ta_crypt_cipher_final(c, &session, op, big_output,
+				    BIG_BUFFER_SIZE, dec_input, &out_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_free_operation(c, &session, op);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	(void)ADBG_EXPECT_BUFFER(c, big_input, BIG_BUFFER_SIZE, dec_input,
+				 out_size);
+
+out:
+	if (key_handle != TEE_HANDLE_NULL) {
+		res = ta_crypt_cmd_free_transient_object(c, &session,
+							 key_handle);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+	}
+
+	TEEC_CloseSession(&session);
+
+out_free:
+	if (big_input)
+		free(big_input);
+
+	if (big_output)
+		free(big_output);
+
+	if (dec_input)
+		free(dec_input);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0003, nxp_crypto_003,
+		 "Test TEE cipher operations with big buffers");
+
+static void nxp_crypto_004(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+	TEE_Attribute key_attr = {};
+	uint32_t ret_orig = 0;
+
+	size_t out_size = 0;
+	uint8_t *de_msg = NULL;
+	uint32_t key_size = 0;
+	size_t msg_size = ARRAY_SIZE(ciph_data_ref3);
+
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		return;
+
+	de_msg = malloc(msg_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, de_msg))
+		goto out;
+	memcpy(de_msg, ciph_data_ref3, msg_size);
+
+	key_attr.attributeID = TEE_ATTR_SECRET_VALUE;
+	key_attr.content.ref.buffer = (void *)ciph_data_key3;
+	key_attr.content.ref.length = ARRAY_SIZE(ciph_data_key3);
+
+	key_size = key_attr.content.ref.length * 8;
+
+	res = ta_crypt_cmd_allocate_transient_object(c, &session, TEE_TYPE_AES,
+						     key_size, &key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_populate_transient_object(c, &session, key_handle,
+						     &key_attr, 1);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_allocate_operation(c, &session, &op, TEE_ALG_AES_CTR,
+					      TEE_MODE_DECRYPT, key_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_set_operation_key(c, &session, op, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cipher_init(c, &session, op, ciph_data_iv3,
+				   ARRAY_SIZE(ciph_data_iv3));
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	out_size = msg_size;
+	res = ta_crypt_cipher_update(c, &session, op, de_msg, msg_size, de_msg,
+				     &out_size);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	res = ta_crypt_cmd_free_operation(c, &session, op);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/* Compare original message with decrypted message */
+	(void)ADBG_EXPECT_BUFFER(c, ciph_data_out3, msg_size, de_msg, out_size);
+
+	res = ta_crypt_cmd_free_transient_object(c, &session, key_handle);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+out:
+	TEEC_CloseSession(&session);
+	free(de_msg);
+}
+ADBG_CASE_DEFINE(regression_nxp, 0004, nxp_crypto_004,
+		 "Test TEE AES CTR cipher in place operation");
diff --git a/host/xtest/regression_nxp/crypto/cipher_memleak.c b/host/xtest/regression_nxp/crypto/cipher_memleak.c
new file mode 100644
index 0000000..463b2e4
--- /dev/null
+++ b/host/xtest/regression_nxp/crypto/cipher_memleak.c
@@ -0,0 +1,994 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2020 NXP
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nxp_crypto_test_vectors.h"
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+
+#include <ta_crypt.h>
+#include <utee_defines.h>
+#include <util.h>
+
+#define STATS_UUID                                                             \
+	{                                                                      \
+		0xd96a5b40, 0xe2c7, 0xb1af,                                    \
+		{                                                              \
+			0x87, 0x94, 0x10, 0x02, 0xa5, 0xd5, 0xc6, 0x1b         \
+		}                                                              \
+	}
+
+#define STATS_CMD_ALLOC_STATS 1
+
+#define TEE_ALLOCATOR_DESC_LENGTH 32
+struct memstats {
+	char desc[TEE_ALLOCATOR_DESC_LENGTH];
+	uint32_t allocated;		  /* Bytes currently allocated */
+	uint32_t max_allocated;		  /* Tracks max value of allocated */
+	uint32_t size;			  /* Total size for this allocator */
+	uint32_t num_alloc_fail;	  /* Number of failed alloc requests */
+	uint32_t biggest_alloc_fail;	  /* Size of biggest failed alloc */
+	uint32_t biggest_alloc_fail_used; /* Alloc bytes when above occurred */
+};
+
+struct memstats_test {
+	size_t number;
+	size_t diff_ta_crypt;
+	struct memstats *start;
+	struct memstats *end;
+};
+
+static TEEC_Result open_ta_memstats(TEEC_Session *sess)
+{
+	TEEC_UUID uuid = STATS_UUID;
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	uint32_t ret_orig = 0;
+
+	res = xtest_teec_open_session(sess, &uuid, NULL, &ret_orig);
+	if (res != TEEC_SUCCESS)
+		Do_ADBG_Log("Memory statistique PTA not loaded");
+
+	return res;
+}
+
+static void close_ta_memstats(TEEC_Session *sess, struct memstats_test *stats)
+{
+	if (stats->start)
+		free(stats->start);
+	if (stats->end)
+		free(stats->end);
+
+	TEEC_CloseSession(sess);
+}
+
+static TEEC_Result memstat_start(ADBG_Case_t *c, TEEC_Session *sess,
+				 struct memstats_test *stats)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = {};
+	struct memstats *mstats = NULL;
+	size_t stats_size_bytes = 0;
+	size_t n = 0;
+	uint32_t ret_orig = 0;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	/* Get the Heap Pool */
+	op.params[0].value.a = 1;
+
+	res = TEEC_InvokeCommand(sess, STATS_CMD_ALLOC_STATS, &op, &ret_orig);
+	if (!ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_SHORT_BUFFER, res))
+		goto end;
+
+	stats_size_bytes = op.params[1].tmpref.size;
+	if (!ADBG_EXPECT_TRUE(c, !(stats_size_bytes % sizeof(*stats->start))))
+		goto end;
+
+	stats->start = calloc(1, stats_size_bytes);
+	if (!ADBG_EXPECT_NOT_NULL(c, stats->start))
+		goto end;
+
+	stats->end = calloc(1, stats_size_bytes);
+	if (!ADBG_EXPECT_NOT_NULL(c, stats->end))
+		goto end;
+
+	mstats = stats->start;
+	op.params[1].tmpref.buffer = mstats;
+	op.params[1].tmpref.size = stats_size_bytes;
+	res = TEEC_InvokeCommand(sess, STATS_CMD_ALLOC_STATS, &op, &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto end;
+
+	if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, op.params[1].tmpref.size, ==,
+					  stats_size_bytes))
+		goto end;
+
+	stats->number = stats_size_bytes / sizeof(*stats->start);
+
+	for (n = 0; n < stats->number; n++) {
+		printf("\n");
+		printf("===============================================\n");
+		printf("Pool: %*s\n",
+		       (int)strnlen(mstats[n].desc, sizeof(mstats[n].desc)),
+		       mstats[n].desc);
+		printf("Bytes allocated:                       %" PRId32 "\n",
+		       mstats[n].allocated);
+		printf("Max bytes allocated:                   %" PRId32 "\n",
+		       mstats[n].max_allocated);
+		printf("Size of pool:                          %" PRId32 "\n",
+		       mstats[n].size);
+		printf("Number of failed allocations:          %" PRId32 "\n",
+		       mstats[n].num_alloc_fail);
+		printf("Size of larges allocation failure:     %" PRId32 "\n",
+		       mstats[n].biggest_alloc_fail);
+		printf("Total bytes allocated at that failure: %" PRId32 "\n",
+		       mstats[n].biggest_alloc_fail_used);
+		printf("===============================================\n");
+	}
+
+end:
+	return res;
+}
+
+static TEEC_Result memstat_diff_ta_user(ADBG_Case_t *c, TEEC_Session *sess,
+					struct memstats_test *stats)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = {};
+	struct memstats *mstats = NULL;
+	uint32_t ret_orig = 0;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	mstats = stats->end;
+
+	/* Get the Heap Pool */
+	op.params[0].value.a = 1;
+
+	op.params[1].tmpref.buffer = mstats;
+	op.params[1].tmpref.size = stats->number * sizeof(*stats->end);
+	res = TEEC_InvokeCommand(sess, STATS_CMD_ALLOC_STATS, &op, &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto end;
+
+	stats->diff_ta_crypt = mstats[0].allocated - stats->start[0].allocated;
+end:
+	return res;
+}
+
+static TEEC_Result memstat_end(ADBG_Case_t *c, TEEC_Session *sess,
+			       struct memstats_test *stats)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = {};
+	struct memstats *mstats = NULL;
+	size_t n = 0;
+	uint32_t ret_orig = 0;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	mstats = stats->end;
+
+	/* Get the Heap Pool */
+	op.params[0].value.a = 1;
+
+	op.params[1].tmpref.buffer = mstats;
+	op.params[1].tmpref.size = stats->number * sizeof(*stats->end);
+	res = TEEC_InvokeCommand(sess, STATS_CMD_ALLOC_STATS, &op, &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto end;
+
+	/* Remove the TA Crypto global data not freed from the heap */
+	mstats[0].allocated -= stats->diff_ta_crypt;
+	for (n = 0; n < stats->number; n++) {
+		printf("\n");
+		printf("===============================================\n");
+		printf("Pool: %*s\n",
+		       (int)strnlen(mstats[n].desc, sizeof(mstats[n].desc)),
+		       mstats[n].desc);
+		printf("Bytes allocated:                       %" PRId32 "\n",
+		       mstats[n].allocated);
+		printf("Max bytes allocated:                   %" PRId32 "\n",
+		       mstats[n].max_allocated);
+		printf("Size of pool:                          %" PRId32 "\n",
+		       mstats[n].size);
+		printf("Number of failed allocations:          %" PRId32 "\n",
+		       mstats[n].num_alloc_fail);
+		printf("Size of larges allocation failure:     %" PRId32 "\n",
+		       mstats[n].biggest_alloc_fail);
+		printf("Total bytes allocated at that failure: %" PRId32 "\n",
+		       mstats[n].biggest_alloc_fail_used);
+		printf("===============================================\n");
+	}
+
+	if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, stats->start[0].allocated, ==,
+					  stats->end[0].allocated))
+		goto end;
+
+end:
+	return res;
+}
+
+static TEEC_Result ta_crypt_cipher_init(ADBG_Case_t *c, TEEC_Session *s,
+					TEE_OperationHandle oph, const void *iv,
+					size_t iv_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	if (iv) {
+		op.params[1].tmpref.buffer = (void *)iv;
+		op.params[1].tmpref.size = iv_len;
+
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						 TEEC_MEMREF_TEMP_INPUT,
+						 TEEC_NONE, TEEC_NONE);
+	} else {
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+						 TEEC_NONE, TEEC_NONE);
+	}
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_INIT, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_cipher_update(ADBG_Case_t *c, TEEC_Session *s,
+					  TEE_OperationHandle oph,
+					  const void *src, size_t src_len,
+					  void *dst, size_t *dst_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)src;
+	op.params[1].tmpref.size = src_len;
+
+	op.params[2].tmpref.buffer = dst;
+	op.params[2].tmpref.size = *dst_len;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_UPDATE, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	if (res == TEEC_SUCCESS)
+		*dst_len = op.params[2].tmpref.size;
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_cipher_final(ADBG_Case_t *c, TEEC_Session *s,
+					 TEE_OperationHandle oph,
+					 const void *src, size_t src_len,
+					 void *dst, size_t *dst_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)src;
+	op.params[1].tmpref.size = src_len;
+
+	op.params[2].tmpref.buffer = (void *)dst;
+	op.params[2].tmpref.size = *dst_len;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_CIPHER_DO_FINAL, &op,
+				 &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	if (res == TEEC_SUCCESS)
+		*dst_len = op.params[2].tmpref.size;
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_mac_init(ADBG_Case_t *c, TEEC_Session *s,
+				     TEE_OperationHandle oph, const void *iv,
+				     size_t iv_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	if (iv) {
+		op.params[1].tmpref.buffer = (void *)iv;
+		op.params[1].tmpref.size = iv_len;
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						 TEEC_MEMREF_TEMP_INPUT,
+						 TEEC_NONE, TEEC_NONE);
+	} else {
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+						 TEEC_NONE, TEEC_NONE);
+	}
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_MAC_INIT, &op, &ret_orig);
+
+	if (res) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_mac_update(ADBG_Case_t *c, TEEC_Session *s,
+				       TEE_OperationHandle oph,
+				       const void *chunk, size_t chunk_size)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)chunk;
+	op.params[1].tmpref.size = chunk_size;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_MAC_UPDATE, &op, &ret_orig);
+
+	if (res) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_mac_final_compute(ADBG_Case_t *c, TEEC_Session *s,
+					      TEE_OperationHandle oph,
+					      const void *chunk,
+					      size_t chunk_len, void *hash,
+					      size_t *hash_len)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	op.params[1].tmpref.buffer = (void *)chunk;
+	op.params[1].tmpref.size = chunk_len;
+
+	op.params[2].tmpref.buffer = (void *)hash;
+	op.params[2].tmpref.size = *hash_len;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_MAC_FINAL_COMPUTE, &op,
+				 &ret_orig);
+
+	if (res) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	if (!res)
+		*hash_len = op.params[2].tmpref.size;
+
+	return res;
+}
+
+static TEEC_Result ta_crypt_generate_key(ADBG_Case_t *c, TEEC_Session *s,
+					 TEE_ObjectHandle o, uint32_t key_size)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+	uint8_t *buf = NULL;
+	size_t blen = 0;
+
+	assert((uintptr_t)o <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)o;
+	op.params[0].value.b = key_size;
+
+	op.params[1].tmpref.buffer = buf;
+	op.params[1].tmpref.size = blen;
+
+	op.paramTypes =
+		TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT,
+				 TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_GENERATE_KEY, &op, &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	free(buf);
+	return res;
+}
+
+static TEE_Result ta_crypt_set_operation_key2(ADBG_Case_t *c, TEEC_Session *s,
+					      TEE_OperationHandle oph,
+					      TEE_ObjectHandle key1,
+					      TEE_ObjectHandle key2)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	assert((uintptr_t)oph <= UINT32_MAX);
+	op.params[0].value.a = (uint32_t)(uintptr_t)oph;
+
+	assert((uintptr_t)key1 <= UINT32_MAX);
+	op.params[0].value.b = (uint32_t)(uintptr_t)key1;
+
+	assert((uintptr_t)key2 <= UINT32_MAX);
+	op.params[1].value.a = (uint32_t)(uintptr_t)key2;
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT,
+					 TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_SET_OPERATION_KEY2, &op,
+				 &ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+						    ret_orig);
+	}
+
+	return res;
+}
+
+struct test_cipher {
+	uint32_t algo;
+	uint8_t mode;
+	size_t key_size;
+	size_t blk_size;
+	size_t nb_blk;
+	size_t nb_blk_inc;
+	const uint8_t *iv;
+	size_t iv_size;
+	uint16_t line;
+};
+
+#define MODE(mode)	 TEE_MODE_##mode
+#define ALGO(algo)	 TEE_ALG_##algo
+#define KEY(algo)	 TEE_ALG_GET_KEY_TYPE(algo, false)
+#define BLOCK_SIZE(algo) TEE_##algo##_BLOCK_SIZE
+
+#define TEST_CIPHER_NO_IV(algo, op, key_size, blk_size, nb_blk, nb_blk_inc)    \
+	{                                                                      \
+		(algo), MODE(op), (key_size), (blk_size), (nb_blk),            \
+			(nb_blk_inc), NULL, 0, __LINE__                        \
+	}
+
+#define TEST_CIPHER_IV(algo, op, key_size, blk_size, nb_blk, nb_blk_inc, iv)   \
+	{                                                                      \
+		(algo), MODE(op), (key_size), (blk_size), (nb_blk),            \
+			(nb_blk_inc), ciph_data_##iv,                          \
+			ARRAY_SIZE(ciph_data_##iv), __LINE__                   \
+	}
+
+struct test_cipher ac_cipher[] = {
+	/* AES */
+	TEST_CIPHER_NO_IV(ALGO(AES_ECB_NOPAD), ENCRYPT, 128, BLOCK_SIZE(AES), 4,
+			  2),
+	TEST_CIPHER_NO_IV(ALGO(AES_ECB_NOPAD), DECRYPT, 128, BLOCK_SIZE(AES), 4,
+			  2),
+	TEST_CIPHER_IV(ALGO(AES_CBC_NOPAD), ENCRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_CBC_NOPAD), DECRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_CTR), ENCRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_CTR), DECRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_CTS), ENCRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_CTS), DECRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_XTS), ENCRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	TEST_CIPHER_IV(ALGO(AES_XTS), DECRYPT, 128, BLOCK_SIZE(AES), 4, 2,
+		       128_iv),
+	/* DES */
+	TEST_CIPHER_NO_IV(ALGO(DES_ECB_NOPAD), ENCRYPT, 64, BLOCK_SIZE(DES), 4,
+			  2),
+	TEST_CIPHER_NO_IV(ALGO(DES_ECB_NOPAD), DECRYPT, 64, BLOCK_SIZE(DES), 4,
+			  2),
+	TEST_CIPHER_IV(ALGO(DES_CBC_NOPAD), ENCRYPT, 64, BLOCK_SIZE(DES), 4, 2,
+		       64_iv),
+	TEST_CIPHER_IV(ALGO(DES_CBC_NOPAD), DECRYPT, 64, BLOCK_SIZE(DES), 4, 2,
+		       64_iv),
+	/* DES3 */
+	TEST_CIPHER_NO_IV(ALGO(DES3_ECB_NOPAD), ENCRYPT, 128, BLOCK_SIZE(DES),
+			  4, 2),
+	TEST_CIPHER_NO_IV(ALGO(DES3_ECB_NOPAD), DECRYPT, 128, BLOCK_SIZE(DES),
+			  4, 2),
+	TEST_CIPHER_IV(ALGO(DES3_CBC_NOPAD), ENCRYPT, 128, BLOCK_SIZE(DES), 4,
+		       2, 64_iv),
+	TEST_CIPHER_IV(ALGO(DES3_CBC_NOPAD), DECRYPT, 128, BLOCK_SIZE(DES), 4,
+		       2, 64_iv),
+};
+
+struct test_cipher ac_cipher_mac[] = {
+	/* AES */
+	TEST_CIPHER_NO_IV(ALGO(AES_CBC_MAC_NOPAD), MAC, 128, BLOCK_SIZE(AES), 4,
+			  2),
+	TEST_CIPHER_NO_IV(ALGO(AES_CMAC), MAC, 128, BLOCK_SIZE(AES), 4, 2),
+	TEST_CIPHER_NO_IV(ALGO(AES_CBC_MAC_PKCS5), MAC, 128, BLOCK_SIZE(AES), 4,
+			  2),
+	/* DES */
+	TEST_CIPHER_NO_IV(ALGO(DES_CBC_MAC_NOPAD), MAC, 64, BLOCK_SIZE(DES), 4,
+			  2),
+	TEST_CIPHER_NO_IV(ALGO(DES_CBC_MAC_PKCS5), MAC, 64, BLOCK_SIZE(DES), 4,
+			  2),
+	/* DES3 */
+	TEST_CIPHER_NO_IV(ALGO(DES3_CBC_MAC_NOPAD), MAC, 128, BLOCK_SIZE(DES),
+			  4, 2),
+	TEST_CIPHER_NO_IV(ALGO(DES3_CBC_MAC_PKCS5), MAC, 128, BLOCK_SIZE(DES),
+			  4, 2),
+};
+
+static void check_cipher_memleak(ADBG_Case_t *c, TEEC_Session *ta_stat_sess,
+				 struct memstats_test *stats)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key1_hdl = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key2_hdl = TEE_HANDLE_NULL;
+	uint32_t ret_orig = 0;
+	bool test_full = true;
+	uint32_t key_type = 0;
+	size_t ciph_size = 0;
+	size_t inc_size = 0;
+	size_t idx = 0;
+	size_t out_size = 0;
+	size_t out_off = 0;
+	size_t op_key_size = 0;
+	size_t key_size = 0;
+	uint8_t *in = NULL;
+	uint8_t *out = NULL;
+	size_t ciph_allocated = 0;
+
+	struct test_cipher *test = ac_cipher;
+
+	for (size_t n = 0; n < ARRAY_SIZE(ac_cipher); n++, test++) {
+		test_full = true;
+		key_type = KEY(test->algo);
+		ciph_size = test->blk_size * test->nb_blk;
+		inc_size = test->blk_size * test->nb_blk_inc;
+
+		if (ciph_allocated < ciph_size) {
+			if (in)
+				free(in);
+
+			ciph_allocated = ciph_size;
+
+			in = malloc(ciph_allocated);
+			if (!ADBG_EXPECT_NOT_NULL(c, in))
+				goto out;
+
+			if (out)
+				free(out);
+
+			out = malloc(ciph_allocated);
+			if (!ADBG_EXPECT_NOT_NULL(c, out))
+				goto out;
+
+			/* Fill the Message value */
+			for (idx = 0; idx < ciph_allocated; idx++)
+				in[idx] = idx;
+		}
+
+redo_test:
+		Do_ADBG_BeginSubCase(c,
+				     "%sFull Cipher 0x%" PRIX32
+				     " mode %d - line: %u",
+				     (test_full) ? "" : "Not ", test->algo,
+				     test->mode, test->line);
+
+		res = xtest_teec_open_session(&session, &crypt_user_ta_uuid,
+					      NULL, &ret_orig);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		/* Generate a Cipher key(s) */
+		key_size = test->key_size;
+
+		/* Remove parity bit size */
+		if (key_type == TEE_TYPE_DES || key_type == TEE_TYPE_DES3)
+			key_size -= key_size / 8;
+
+		res = ta_crypt_cmd_allocate_transient_object(c, &session,
+							     key_type, key_size,
+							     &key1_hdl);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_generate_key(c, &session, key1_hdl, key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		op_key_size = key_size;
+		if (test->algo == ALGO(AES_XTS))
+			op_key_size *= 2;
+
+		/* Prepare cipher operation encrypt or decrypt */
+		res = ta_crypt_cmd_allocate_operation(c, &session, &op,
+						      test->algo, test->mode,
+						      op_key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		if (test->algo == ALGO(AES_XTS)) {
+			res = ta_crypt_cmd_allocate_transient_object(c,
+								     &session,
+								     key_type,
+								     key_size,
+								     &key2_hdl);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+
+			res = ta_crypt_generate_key(c, &session, key2_hdl,
+						    key_size);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+
+			res = ta_crypt_set_operation_key2(c, &session, op,
+							  key1_hdl, key2_hdl);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+		} else {
+			res = ta_crypt_cmd_set_operation_key(c, &session, op,
+							     key1_hdl);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+		}
+
+		Do_ADBG_Log("Free Key 1 object");
+		res = ta_crypt_cmd_free_transient_object(c, &session, key1_hdl);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		if (test->algo == ALGO(AES_XTS)) {
+			Do_ADBG_Log("Free Key 2 object");
+			res = ta_crypt_cmd_free_transient_object(c, &session,
+								 key2_hdl);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+		}
+
+		Do_ADBG_Log("Cipher Init");
+		res = ta_crypt_cipher_init(c, &session, op, test->iv,
+					   test->iv_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		Do_ADBG_Log("Cipher Update");
+		out_size = inc_size;
+		res = ta_crypt_cipher_update(c, &session, op, in, inc_size, out,
+					     &out_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		if (test_full) {
+			Do_ADBG_Log("Cipher Final");
+			out_off = out_size;
+			out_size = ciph_size - out_size;
+			res = ta_crypt_cipher_final(c, &session, op,
+						    in + inc_size,
+						    ciph_size - inc_size,
+						    out + out_off, &out_size);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+
+			res = ta_crypt_cmd_free_operation(c, &session, op);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+		}
+
+		TEEC_CloseSession(&session);
+		session.ctx = NULL;
+
+		res = memstat_end(c, ta_stat_sess, stats);
+		(void)ADBG_EXPECT_TEEC_SUCCESS(c, res);
+
+		Do_ADBG_EndSubCase(c, NULL);
+
+		if (test_full) {
+			test_full = false;
+			goto redo_test;
+		}
+	}
+out:
+	if (session.ctx)
+		TEEC_CloseSession(&session);
+
+	if (in)
+		free(in);
+	if (out)
+		free(out);
+}
+
+static void check_cipher_mac_memleak(ADBG_Case_t *c, TEEC_Session *ta_stat_sess,
+				     struct memstats_test *stats)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEE_OperationHandle op = TEE_HANDLE_NULL;
+	TEE_ObjectHandle key1_hdl = TEE_HANDLE_NULL;
+	uint32_t ret_orig = 0;
+	bool test_full = true;
+	uint32_t key_type = 0;
+	size_t ciph_size = 0;
+	size_t inc_size = 0;
+	size_t idx = 0;
+	size_t out_size = 0;
+	size_t op_key_size = 0;
+	size_t key_size = 0;
+	uint8_t *in = NULL;
+	uint8_t *out = NULL;
+	size_t ciph_allocated = 0;
+
+	struct test_cipher *test = ac_cipher_mac;
+
+	for (size_t n = 0; n < ARRAY_SIZE(ac_cipher_mac); n++, test++) {
+		test_full = true;
+		key_type = KEY(test->algo);
+		ciph_size = test->blk_size * test->nb_blk;
+		inc_size = test->blk_size * test->nb_blk_inc;
+
+		if (ciph_allocated < ciph_size) {
+			if (in)
+				free(in);
+
+			ciph_allocated = ciph_size;
+
+			in = malloc(ciph_allocated);
+			if (!ADBG_EXPECT_NOT_NULL(c, in))
+				goto out;
+
+			if (out)
+				free(out);
+
+			out = malloc(ciph_allocated);
+			if (!ADBG_EXPECT_NOT_NULL(c, out))
+				goto out;
+
+			/* Fill the Message value */
+			for (idx = 0; idx < ciph_allocated; idx++)
+				in[idx] = idx;
+		}
+
+redo_test:
+		Do_ADBG_BeginSubCase(c,
+				     "%sFull Cipher MAC 0x%" PRIX32
+				     " mode %d - line: %u",
+				     (test_full) ? "" : "Not ", test->algo,
+				     test->mode, test->line);
+
+		res = xtest_teec_open_session(&session, &crypt_user_ta_uuid,
+					      NULL, &ret_orig);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		/* Generate a Cipher key(s) */
+		key_size = test->key_size;
+
+		/* Remove parity bit size */
+		if (key_type == TEE_TYPE_DES || key_type == TEE_TYPE_DES3)
+			key_size -= key_size / 8;
+
+		res = ta_crypt_cmd_allocate_transient_object(c, &session,
+							     key_type, key_size,
+							     &key1_hdl);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_generate_key(c, &session, key1_hdl, key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		op_key_size = key_size;
+		if (test->algo == ALGO(AES_XTS))
+			op_key_size *= 2;
+
+		/* Prepare cipher operation encrypt or decrypt */
+		res = ta_crypt_cmd_allocate_operation(c, &session, &op,
+						      test->algo, test->mode,
+						      op_key_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		res = ta_crypt_cmd_set_operation_key(c, &session, op, key1_hdl);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		Do_ADBG_Log("Free Key 1 object");
+		res = ta_crypt_cmd_free_transient_object(c, &session, key1_hdl);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		Do_ADBG_Log("Cipher MAC Init");
+		res = ta_crypt_mac_init(c, &session, op, test->iv,
+					test->iv_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		Do_ADBG_Log("Cipher MAC Update");
+		res = ta_crypt_mac_update(c, &session, op, in, inc_size);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+			goto out;
+
+		if (test_full) {
+			Do_ADBG_Log("Cipher MAC Final");
+			out_size = ciph_size;
+			res = ta_crypt_mac_final_compute(c, &session, op,
+							 in + inc_size,
+							 ciph_size - inc_size,
+							 out, &out_size);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+
+			res = ta_crypt_cmd_free_operation(c, &session, op);
+			if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+				goto out;
+		}
+
+		TEEC_CloseSession(&session);
+		session.ctx = NULL;
+
+		res = memstat_end(c, ta_stat_sess, stats);
+		(void)ADBG_EXPECT_TEEC_SUCCESS(c, res);
+
+		Do_ADBG_EndSubCase(c, NULL);
+
+		if (test_full) {
+			test_full = false;
+			goto redo_test;
+		}
+	}
+out:
+	if (session.ctx)
+		TEEC_CloseSession(&session);
+
+	if (in)
+		free(in);
+	if (out)
+		free(out);
+}
+
+static void nxp_memleak_004(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEEC_Session ta_stat_sess = {};
+	uint32_t ret_orig = 0;
+	struct memstats_test stats = {};
+
+	res = open_ta_memstats(&ta_stat_sess);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/*
+	 * Get the current memory statistique
+	 */
+	res = memstat_start(c, &ta_stat_sess, &stats);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/*
+	 * Open and Close TA Crypto to get the overhead of memory
+	 * allocated on the heap but not freed when TA session is
+	 * closed (because of TA Global data)
+	 */
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	TEEC_CloseSession(&session);
+	res = memstat_diff_ta_user(c, &ta_stat_sess, &stats);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	check_cipher_memleak(c, &ta_stat_sess, &stats);
+
+out:
+	if (ta_stat_sess.ctx)
+		close_ta_memstats(&ta_stat_sess, &stats);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0004, nxp_memleak_004,
+		 "Test TEE Cipher operation memory leak");
+
+static void nxp_memleak_005(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = {};
+	TEEC_Session ta_stat_sess = {};
+	uint32_t ret_orig = 0;
+	struct memstats_test stats = {};
+
+	res = open_ta_memstats(&ta_stat_sess);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/*
+	 * Get the current memory statistique
+	 */
+	res = memstat_start(c, &ta_stat_sess, &stats);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	/*
+	 * Open and Close TA Crypto to get the overhead of memory
+	 * allocated on the heap but not freed when TA session is
+	 * closed (because of TA Global data)
+	 */
+	res = xtest_teec_open_session(&session, &crypt_user_ta_uuid, NULL,
+				      &ret_orig);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	TEEC_CloseSession(&session);
+	res = memstat_diff_ta_user(c, &ta_stat_sess, &stats);
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+		goto out;
+
+	check_cipher_mac_memleak(c, &ta_stat_sess, &stats);
+
+out:
+	if (ta_stat_sess.ctx)
+		close_ta_memstats(&ta_stat_sess, &stats);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0005, nxp_memleak_005,
+		 "Test TEE Cipher MAC operation memory leak");
diff --git a/host/xtest/regression_nxp/crypto/mp_signature.c b/host/xtest/regression_nxp/crypto/mp_signature.c
new file mode 100644
index 0000000..12525f6
--- /dev/null
+++ b/host/xtest/regression_nxp/crypto/mp_signature.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021-2022 NXP
+ */
+
+/*
+ * Test of the signature of a message using the Manufacturing Protection key
+ * This feature is only available on boards which are closed
+ */
+
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <tee_client_api.h>
+#include <tee_client_api_extensions.h>
+#include <ta_manufacturing_protection.h>
+#include <pta_manufact_protec.h>
+#include <utee_defines.h>
+
+#ifdef OPENSSL_FOUND
+#include <openssl/ecdsa.h>
+#include <openssl/sha.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+#include <openssl/obj_mac.h>
+#include <openssl/err.h>
+#endif /* OPENSSL_FOUND */
+
+/*
+ * Retrieve the MP public key
+ */
+static TEEC_Result get_pubkey(ADBG_Case_t *const c, TEEC_Session *sess,
+			      uint8_t *pubkey, size_t *pubkey_size,
+			      uint8_t *pubkey_pem, size_t *pubkey_pem_size)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t err_origin = 0;
+
+	/* Call PTA */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
+					 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE,
+					 TEEC_NONE);
+
+	op.params[0].tmpref.buffer = (void *)pubkey;
+	op.params[0].tmpref.size = *pubkey_size;
+
+	op.params[1].tmpref.buffer = (void *)pubkey_pem;
+	op.params[1].tmpref.size = *pubkey_pem_size;
+
+	/* Execute a function in the TA by invoking it (call pta) */
+	res = TEEC_InvokeCommand(sess, TA_MP_CMD_GET_MP_PUBK, &op, &err_origin);
+	*pubkey_size = op.params[0].tmpref.size;
+	*pubkey_pem_size = op.params[1].tmpref.size;
+
+	if (res == TEEC_ERROR_NOT_SUPPORTED)
+		return res;
+
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res)) {
+		Do_ADBG_Log("%s: PTA_MP_CMD_GET_PUBLIC_KEY res: %" PRIx32
+			    ", origin: %" PRIx32,
+			    __func__, res, err_origin);
+		return res;
+	}
+
+	return TEEC_SUCCESS;
+}
+
+#ifdef OPENSSL_FOUND
+/*
+ * Convert a signature to a DER representation following ASN1
+ *
+ * A signature of the DER format:
+ * SEQUENCE {
+ *    INTEGER 0x27361817047a4f09fd5ef43ab76eb1440ce8c12a0f31a8c02811282ea011b08d
+ *    INTEGER 0x25d09c08895417fdd21523815e195a1bb4b780c398413702ee98978b9e6fffed
+ * }
+ * First INTEGER is the first half the signature binary buffer: R component
+ * Second INTEGER is the second half the signature binary buffer: S component
+ *
+ * For simplicity, we are using the uncompressed form indicated by the first
+ * byte
+ *
+ * Note: If the INTEGER has its MSB bit set, it needs to be appended a 0x00
+ */
+#define DER_UNCOMPRESSED_FORM 0x4
+
+static int der_encap(uint8_t *der_sig, size_t *der_sig_size,
+		     const uint8_t *raw_sig, size_t raw_sig_size)
+{
+	size_t req = 0;
+
+	/*
+	 * For the simple uncompressed form, we just need to add a leading
+	 * byte
+	 */
+	req = raw_sig_size + 1;
+
+	if (*der_sig_size < req) {
+		*der_sig_size = req;
+		return EXIT_FAILURE;
+	}
+
+	der_sig[0] = DER_UNCOMPRESSED_FORM;
+	memcpy(der_sig + 1, raw_sig, raw_sig_size);
+
+	*der_sig_size = req;
+
+	return EXIT_SUCCESS;
+}
+
+static void print_ossl_errors(void)
+{
+	unsigned long error = 0;
+	const char *file = NULL;
+	int line = 0;
+	const char *data = NULL;
+	int flags = 0;
+
+	while ((error = ERR_get_error_line_data(&file, &line, &data, &flags)))
+		Do_ADBG_Log("OSSL(%lx)[%s@%d (%p | %x)]: %s", error, file, line,
+			    data, flags, ERR_error_string(error, NULL));
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+/* From https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes */
+static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+	if (!r || !s)
+		return 0;
+	BN_clear_free(sig->r);
+	BN_clear_free(sig->s);
+	sig->r = r;
+	sig->s = s;
+	return 1;
+}
+#endif
+
+static int verify_msg_sig_openssl(ADBG_Case_t *const c, uint8_t *mpmr_msg,
+				  size_t mpmr_msg_size, const uint8_t *raw_sig,
+				  size_t raw_sig_size, const uint8_t *pubkey,
+				  size_t pubkey_size)
+{
+	int ret = EXIT_FAILURE;
+	int err = 0;
+	int success = 0;
+	unsigned char digest[SHA256_DIGEST_LENGTH] = {};
+	SHA256_CTX sha_ctx = {};
+	ECDSA_SIG *sig = NULL;
+	uint8_t *der_pubkey = NULL;
+	size_t der_pubkey_size = 0;
+	EC_KEY *key = NULL;
+	EC_POINT *pub = NULL;
+	EC_GROUP *group = NULL;
+	BN_CTX *bn_ctx = NULL;
+	size_t req = 0;
+	size_t half_size = pubkey_size / 2;
+	BIGNUM *bn_r = NULL;
+	BIGNUM *bn_s = NULL;
+
+	success = SHA256_Init(&sha_ctx);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "SHA256_Init");
+		goto exit;
+	}
+
+	success = SHA256_Update(&sha_ctx, mpmr_msg, mpmr_msg_size);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "SHA256_Update");
+		goto exit;
+	}
+
+	success = SHA256_Final(digest, &sha_ctx);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "SHA256_Final");
+		goto exit;
+	}
+
+	key = EC_KEY_new();
+	if (!ADBG_EXPECT_NOT_NULL(c, key)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "EC_KEY_new");
+		goto exit;
+	}
+
+	group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+	if (!ADBG_EXPECT_NOT_NULL(c, group)) {
+		Do_ADBG_Log("%s: %s failed", __func__,
+			    "EC_GROUP_new_by_curve_name");
+		goto exit;
+	}
+
+	success = EC_KEY_set_group(key, group);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "EC_KEY_set_group");
+		goto exit;
+	}
+
+	pub = EC_POINT_new(group);
+	if (!ADBG_EXPECT_NOT_NULL(c, pub)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "EC_POINT_new");
+		goto exit;
+	}
+
+	bn_ctx = BN_CTX_new();
+	if (!ADBG_EXPECT_NOT_NULL(c, bn_ctx)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "BN_CTX_new");
+		goto exit;
+	}
+
+	err = der_encap(NULL, &req, pubkey, pubkey_size);
+	if (!ADBG_EXPECT(c, EXIT_FAILURE, err)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "der_encap get size");
+		goto exit;
+	}
+
+	der_pubkey = malloc(req);
+	if (!ADBG_EXPECT_NOT_NULL(c, der_pubkey)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "malloc");
+		goto exit;
+	}
+
+	der_pubkey_size = req;
+
+	/* We can pass the PEM version which already make it a der */
+	err = der_encap(der_pubkey, &der_pubkey_size, pubkey, pubkey_size);
+	if (!ADBG_EXPECT(c, EXIT_SUCCESS, err)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "der_encap pubkey");
+		goto exit;
+	}
+
+	success = EC_POINT_oct2point(group, pub, der_pubkey, der_pubkey_size,
+				     bn_ctx);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "EC_POINT_oct2point");
+		goto exit;
+	}
+
+	success = EC_KEY_set_public_key(key, pub);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "EC_KEY_set_public_key");
+		goto exit;
+	}
+
+	sig = ECDSA_SIG_new();
+	if (!ADBG_EXPECT_NOT_NULL(c, sig)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "ECDSA_SIG_new");
+		goto exit;
+	}
+
+	bn_r = BN_bin2bn(raw_sig, half_size, NULL);
+	if (!ADBG_EXPECT_NOT_NULL(c, bn_r)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "BN_bin2bn");
+		goto exit;
+	}
+
+	bn_s = BN_bin2bn(raw_sig + half_size, half_size, NULL);
+	if (!ADBG_EXPECT_NOT_NULL(c, bn_s)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "BN_bin2bn");
+		goto free_bn;
+	}
+
+	/*
+	 * When using ECDSA_SIG_set0, the memory management changes so after
+	 * this call, the pointer on the BIGNUM shall not be free directly
+	 */
+	success = ECDSA_SIG_set0(sig, bn_r, bn_s);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "ECDSA_SIG_set0");
+		goto free_bn;
+	}
+
+	success = ECDSA_do_verify(digest, SHA256_DIGEST_LENGTH, sig, key);
+	if (!ADBG_EXPECT(c, 1, success)) {
+		Do_ADBG_Log("%s: %s failed", __func__, "ECDSA_do_verify");
+		goto exit;
+	}
+
+	ret = EXIT_SUCCESS;
+	goto exit;
+
+free_bn:
+	free(bn_s);
+	free(bn_r);
+
+exit:
+	print_ossl_errors();
+	ECDSA_SIG_free(sig);
+	EC_KEY_free(key);
+	EC_POINT_free(pub);
+	EC_GROUP_free(group);
+	BN_CTX_free(bn_ctx);
+	free(der_pubkey);
+
+	return ret;
+}
+#else  /* OPENSSL_FOUND */
+static int verify_msg_sig_openssl(ADBG_Case_t *const c, uint8_t *mpmr_msg,
+				  size_t mpmr_msg_size, const uint8_t *raw_sig,
+				  size_t raw_sig_size, const uint8_t *pubkey,
+				  size_t pubkey_size)
+{
+	return EXIT_FAILURE;
+}
+#endif /* OPENSSL_FOUND */
+
+/*
+ * Call MP API to sign a message using CAAM MP private key and verify it
+ * When processing, CAAM is signing a concatenated message:
+ *   [MPMR] + [USER MESSAGE]
+ * When verifying it, the concatenated message must also be used
+ */
+static int sign_verify_message(ADBG_Case_t *const c, TEEC_Session *sess,
+			       size_t msg_size, uint8_t *pubkey,
+			       size_t pubkey_size)
+{
+	int ret = EXIT_FAILURE;
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = {};
+	uint32_t err_origin = 0;
+	size_t raw_sig_size = MP_PUBKEY_SIZE_NAX;
+	uint8_t *raw_sig = NULL;
+	/*
+	 * The message to verify is the concatenation of the MPMR and the
+	 * original message
+	 */
+	size_t mpmr_size = 32;
+	uint8_t *mpmr = NULL;
+	uint8_t *msg = NULL;
+	size_t mpmr_msg_size = mpmr_size + msg_size;
+	uint8_t *mpmr_msg = NULL;
+
+	/* Allocate memory for other components */
+	mpmr_msg = malloc(mpmr_msg_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, mpmr_msg))
+		goto exit;
+
+	mpmr = mpmr_msg;
+	msg = mpmr_msg + mpmr_size;
+
+	raw_sig = malloc(raw_sig_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, raw_sig)) {
+		Do_ADBG_Log("%s: %s failed: %" PRIx32,
+			    "Allocation of signature", __func__, ret);
+		goto exit;
+	}
+
+	/* Create dummy message of the length required */
+	memset(msg, 'A', msg_size);
+
+	/* Call PTA */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					 TEEC_MEMREF_TEMP_OUTPUT,
+					 TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE);
+
+	op.params[0].tmpref.buffer = (void *)msg;
+	op.params[0].tmpref.size = msg_size;
+
+	op.params[1].tmpref.buffer = (void *)raw_sig;
+	op.params[1].tmpref.size = raw_sig_size;
+
+	op.params[2].tmpref.buffer = (void *)mpmr;
+	op.params[2].tmpref.size = mpmr_size;
+
+	/* Execute a function in the TA by invoking it (call pta) */
+	res = TEEC_InvokeCommand(sess, TA_MP_CMD_SIGN_DATA, &op, &err_origin);
+	raw_sig_size = op.params[1].tmpref.size;
+	mpmr_size = op.params[2].tmpref.size;
+
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res)) {
+		Do_ADBG_Log("%s: TA_MP_CMD_SIGN_DATA res: %" PRIx32
+			    ", origin: %" PRIx32,
+			    __func__, res, err_origin);
+		goto exit;
+	}
+
+	ret = verify_msg_sig_openssl(c, mpmr_msg, mpmr_msg_size, raw_sig,
+				     raw_sig_size, pubkey, pubkey_size);
+	if (!ADBG_EXPECT(c, EXIT_SUCCESS, ret)) {
+		Do_ADBG_Log("%s: %s failed: %" PRIx32, __func__,
+			    "verify_msg_sig_openssl", ret);
+		goto exit;
+	}
+
+	ret = EXIT_SUCCESS;
+
+exit:
+	free(mpmr_msg);
+	free(raw_sig);
+
+	return ret;
+}
+
+static bool mp_pta_is_present(ADBG_Case_t *const c, TEEC_Context *ctx)
+{
+	static int present;
+	TEEC_Session sess = {};
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_UUID uuid = PTA_MANUFACT_PROTEC_UUID;
+	uint32_t err_origin = 0;
+
+	if (present != 0)
+		goto exit;
+
+	res = TEEC_OpenSession(ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL, NULL,
+			       &err_origin);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		present = -1;
+		goto exit;
+	}
+
+	if (res == TEEC_SUCCESS)
+		TEEC_CloseSession(&sess);
+
+	present = 1;
+
+exit:
+	return (present >= 0) ? true : false;
+}
+
+static void nxp_crypto_0020(ADBG_Case_t *const c)
+{
+	int ret = EXIT_FAILURE;
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	size_t msg_size_range_start = 256;
+	size_t msg_size_range_end = 4096;
+	size_t msg_size = 0;
+	size_t pubkey_size = MP_PUBKEY_SIZE_NAX;
+	uint8_t *pubkey = NULL;
+	size_t pubkey_pem_size = MP_PUBKEY_PEM_SIZE_MAX;
+	uint8_t *pubkey_pem = NULL;
+	TEEC_Context ctx = {};
+	TEEC_Session sess = {};
+	TEEC_UUID uuid = TA_MANUFACTURING_PROTECTION_UUID;
+	uint32_t err_origin = 0;
+
+	/* Initialize a context connecting to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res))
+		goto exit;
+
+	if (!mp_pta_is_present(c, &ctx)) {
+		Do_ADBG_Log("Skip test, pseudo TA not found");
+		return;
+	}
+
+#ifndef OPENSSL_FOUND
+	Do_ADBG_Log("Skip test, openssl not found");
+	return;
+#endif /* OPENSSL_FOUND */
+
+	pubkey = malloc(pubkey_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, pubkey))
+		goto exit;
+
+	pubkey_pem = malloc(pubkey_pem_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, pubkey_pem))
+		goto exit;
+
+	/* open a session with the TA */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
+			       NULL, &err_origin);
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res))
+		goto exit;
+
+	res = get_pubkey(c, &sess, pubkey, &pubkey_size, pubkey_pem,
+			 &pubkey_pem_size);
+
+	if (res == TEEC_ERROR_NOT_SUPPORTED) {
+		Do_ADBG_Log("Skip test, MP not functional");
+		return;
+	}
+
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res))
+		goto exit;
+
+	/* Loop over the different sizes of messages to sign */
+	for (msg_size = msg_size_range_start; msg_size <= msg_size_range_end;
+	     msg_size += msg_size_range_start) {
+		Do_ADBG_BeginSubCase(c, "Sign message of size %zu", msg_size);
+
+		ret = sign_verify_message(c, &sess, msg_size, pubkey,
+					  pubkey_size);
+		if (!ADBG_EXPECT(c, EXIT_SUCCESS, ret)) {
+			Do_ADBG_EndSubCase(c, NULL);
+			goto exit;
+		}
+
+		Do_ADBG_EndSubCase(c, NULL);
+	}
+
+exit:
+	TEEC_CloseSession(&sess);
+	TEEC_FinalizeContext(&ctx);
+	free(pubkey);
+	free(pubkey_pem);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0020, nxp_crypto_0020,
+		 "Test MP signature of messages");
+
+static void nxp_crypto_0021(ADBG_Case_t *const c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Context ctx = {};
+	TEEC_Session sess = {};
+	TEEC_UUID uuid = PTA_MANUFACT_PROTEC_UUID;
+	uint32_t err_origin = 0;
+
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (!ADBG_EXPECT(c, TEEC_SUCCESS, res))
+		return;
+
+	if (!mp_pta_is_present(c, &ctx)) {
+		Do_ADBG_Log("Skip test, pseudo TA not found");
+		return;
+	}
+
+	/* open a session with the PTA, should fail */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
+			       NULL, &err_origin);
+
+	ADBG_EXPECT(c, TEEC_ERROR_ACCESS_DENIED, res);
+	ADBG_EXPECT(c, TEEC_ORIGIN_TRUSTED_APP, err_origin);
+
+	if (res == TEEC_SUCCESS)
+		TEEC_CloseSession(&sess);
+	TEEC_FinalizeContext(&ctx);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0021, nxp_crypto_0021,
+		 "Test MP PTA cannot be opened from CA");
diff --git a/host/xtest/regression_nxp/crypto/nxp_crypto_test_vectors.h b/host/xtest/regression_nxp/crypto/nxp_crypto_test_vectors.h
new file mode 100644
index 0000000..fd9a3dc
--- /dev/null
+++ b/host/xtest/regression_nxp/crypto/nxp_crypto_test_vectors.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2021 NXP
+ */
+#ifndef __NXP_CRYPTO_TEST_VECTORS_H__
+#define __NXP_CRYPTO_TEST_VECTORS_H__
+
+#include <stdint.h>
+
+static const uint8_t ciph_data_64_iv[] = {
+	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, /* 12345678 */
+};
+
+static const uint8_t ciph_data_128_iv[] = {
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 01234567 */
+	0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, /* 89ABCDEF */
+};
+
+static const uint8_t ciph_data_aes_key[] = {
+	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, /* 12345678 */
+	0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, /* 9ABCDEF0 */
+};
+
+static const uint8_t ciph_data_ref[] = {
+	0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, /* 23456789 */
+	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, /* ABCDEF01 */
+	0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, /* 3456789A */
+	0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, /* BCDEF012 */
+	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, /* 456789AB */
+	0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, /* CDEF0123 */
+};
+
+static const uint8_t ciph_data_ref2[] = {
+	0x6d, 0x2c, 0x07, 0xe1, 0xfc, 0x86, 0xf9, 0x9c, 0x6e, 0x2a, 0x8f,
+	0x65, 0x67, 0x82, 0x8b, 0x42, 0x62, 0xa9, 0xc2, 0x3d, 0x0f, 0x3e,
+	0xd8, 0xab, 0x32, 0x48, 0x22, 0x83, 0xc7, 0x97, 0x96, 0xf0, 0xad,
+	0xba, 0x1b, 0xcd, 0x37, 0x36, 0x08, 0x49, 0x96, 0x45, 0x2a, 0x91,
+	0x7f, 0xae, 0x98, 0x00, 0x5a, 0xeb, 0xe6, 0x1f, 0x9e, 0x91, 0xc3,
+};
+
+static const uint8_t ciph_data_out2[] = {
+	0x34, 0x5d, 0xeb, 0x1d, 0x67, 0xb9, 0x5e, 0x60, 0x0e, 0x05, 0xca,
+	0xd4, 0xc3, 0x2e, 0xc3, 0x81, 0xaa, 0xdb, 0x3e, 0x2c, 0x1e, 0xc7,
+	0xe0, 0xfb, 0x95, 0x6d, 0xc3, 0x8e, 0x68, 0x60, 0xcf, 0x05, 0x53,
+	0x53, 0x55, 0x66, 0xe1, 0xb1, 0x2f, 0xa9, 0xf8, 0x7d, 0x29, 0x26,
+	0x6c, 0xa2, 0x6d, 0xf4, 0x27, 0x23, 0x3d, 0xf0, 0x35, 0xdf, 0x28,
+};
+
+static const uint8_t ciph_data_key2[] = { 0x47, 0x13, 0xa7, 0xb2, 0xf9, 0x3e,
+					  0xfe, 0x80, 0x9b, 0x42, 0xec, 0xc4,
+					  0x52, 0x13, 0xef, 0x9f };
+
+static const uint8_t ciph_data_iv2[] = { 0xeb, 0xfa, 0x19, 0xb0, 0xeb, 0xf3,
+					 0xd5, 0x7f, 0xea, 0xbd, 0x4c, 0x4b,
+					 0xd0, 0x4b, 0xea, 0x01 };
+
+static const uint8_t ciph_data_ref3[] = {
+	0x46, 0xfe, 0x82, 0xfb, 0x4e, 0x6d, 0xa0, 0xca, 0x9e, 0xe4, 0xf5, 0xae,
+	0x55, 0x7f, 0x2c, 0x4d, 0xd9, 0x42, 0xc6, 0xcb, 0xf7, 0x34, 0x05, 0x68,
+	0x05, 0x15, 0x75, 0x16, 0x65, 0x90, 0xfa, 0xf9, 0xdc, 0xe1, 0x0c, 0x55,
+	0xfb, 0x1e, 0xbf, 0x25, 0x6c, 0xe1, 0x21, 0x22, 0x5e, 0x1d, 0x2e, 0x14,
+	0x37, 0x4b, 0xa7, 0x57, 0x68, 0xf1, 0x1a, 0x4c, 0xd6, 0x47, 0xa8, 0xc2,
+	0x12, 0x64, 0xb1, 0x12, 0xc5, 0xf3, 0x09, 0x2b, 0x98, 0x26, 0x77, 0x31,
+	0x59, 0x59, 0xf4, 0x5e, 0xe4, 0xdc, 0x9a, 0xed, 0x67, 0x83, 0x7c, 0xa2,
+	0xd3, 0x8b, 0x3a, 0x39, 0x27, 0x8a, 0xef, 0x71, 0x76, 0xdb, 0x4c, 0x7d,
+	0x67, 0x89, 0xac, 0x13
+};
+
+static const uint8_t ciph_data_out3[] = {
+	0x25, 0x24, 0x26, 0x1d, 0x09, 0xe5, 0x10, 0xa0, 0x9b, 0xf8, 0xbc, 0x7a,
+	0x7b, 0x17, 0x36, 0x69, 0x85, 0x03, 0x36, 0xcd, 0x5e, 0x0c, 0x2b, 0xeb,
+	0x73, 0xe8, 0x84, 0x62, 0x08, 0x6e, 0x78, 0x63, 0xee, 0xc7, 0x3d, 0xd3,
+	0x9f, 0x11, 0xaf, 0x0b, 0x07, 0xfc, 0xdd, 0xe7, 0x43, 0x47, 0xc5, 0x2c,
+	0x3e, 0x51, 0xfb, 0x1b, 0x2d, 0xf6, 0x50, 0xdd, 0x46, 0xfa, 0x1f, 0x6a,
+	0x76, 0x2b, 0x55, 0x0c, 0x8c, 0x5f, 0xc6, 0x16, 0xf7, 0x7c, 0x99, 0x1b,
+	0xd2, 0xa9, 0x02, 0xd0, 0x4e, 0x4f, 0xa0, 0xd6, 0xb0, 0xb2, 0xc2, 0x78,
+	0x4f, 0x04, 0x52, 0x45, 0x59, 0xce, 0xd2, 0x0a, 0xa6, 0xf6, 0xe8, 0x74,
+	0x3b, 0xd7, 0x30, 0xe6
+};
+
+static const uint8_t ciph_data_key3[] = { 0x0c, 0x9b, 0xe2, 0xe6, 0xdf, 0x0b,
+					  0x9d, 0x5c, 0x2a, 0x4d, 0xf3, 0x58,
+					  0x9c, 0xff, 0x85, 0x4f };
+
+static const uint8_t ciph_data_iv3[] = { 0x1d, 0x44, 0xfb, 0x25, 0xe6, 0x86,
+					 0x85, 0xae, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00 };
+#endif /* __NXP_CRYPTO_TEST_VECTORS_H__ */
diff --git a/host/xtest/regression_nxp/dek_blob/dek_blob.c b/host/xtest/regression_nxp/dek_blob/dek_blob.c
new file mode 100644
index 0000000..d9cb465
--- /dev/null
+++ b/host/xtest/regression_nxp/dek_blob/dek_blob.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+
+#include <utee_defines.h>
+#include <ta_crypt.h>
+#include <util.h>
+
+#include <pta_dek_blob.h>
+
+/* Structure to represent a DEK blob resulting of an encapsulation */
+struct dekblob {
+	/* Header of the DEK blob */
+	struct hab_dek_blob_header header;
+	/* Array for the blob of data encapsulated */
+	uint8_t blob[];
+};
+
+/* Structure to represent pages and partition of Secure Memory to use */
+struct sm_config {
+	unsigned int first_page_to_use;
+	unsigned int additional_pages;
+	unsigned int partition_to_use;
+};
+
+enum sm_params {
+	DEFAULT_START_PAGE = 3,
+	INVALID_START_PAGE = 20,
+	DEFAULT_ADD_PAGES = 1,
+	INVALID_ADD_PAGES = 20,
+	DEFAULT_PARTITION = 1,
+	NOT_OWN_PARTITION = 0,
+	INVALID_PARTITION = 20,
+};
+
+/* Structure to hold parameter of a DEK blob generation */
+struct dek_blob_gen_st {
+	const char *const fmt; /* Description of the test */
+	size_t key_size;       /* Size of the key to use */
+	unsigned int iteration; /* Number of test iteration */
+	/* Secure memory configuration to use */
+	const struct sm_config *sm_config;
+	size_t padding;	  /* Extra space to use for the output buffer */
+	uint32_t exp_res; /* Expected result of generation */
+};
+
+/* Memory space of the component of a DEK blob */
+#define BLOB_PADDING	48
+#define DEK_HEADER_SIZE 8
+#define DEKBLOB_PADDING (BLOB_PADDING + DEK_HEADER_SIZE)
+
+/* Macro to create struct dek_blob_gen_st object */
+#define DEK_BLOB_ST(_str, _key_size, _iteration, _sm_config, _padding, \
+		    _exp_res) \
+	{ \
+		(_str), (_key_size), ( _iteration), (_sm_config), (_padding), \
+		(_exp_res) \
+	}
+
+#define DEK_BLOB(_str, _key_size, _iteration) \
+	DEK_BLOB_ST((_str), (_key_size), (_iteration), NULL, DEKBLOB_PADDING, \
+		    TEEC_SUCCESS)
+
+/*
+ * We are checking the error code for operation not supported:
+ * - key size not supported -> pass key size
+ * - sm not existent -> pass key size
+ * - buffer too small -> add param out_buffer_size
+ */
+static const struct dek_blob_gen_st dek_blob_gen_sts[] = {
+	DEK_BLOB("16 bytes key", 16, 100),
+	DEK_BLOB("24 bytes key", 24, 100),
+	DEK_BLOB("32 bytes key", 32, 100),
+};
+
+static size_t dekblob_create_header(struct hab_dek_blob_header *header,
+				    size_t key_size)
+{
+	size_t total_size = key_size + BLOB_PADDING + sizeof(*header);
+
+	header->tag = HAB_HDR_TAG;
+	header->len_msb = (total_size >> 8) & 0xff;
+	header->len_lsb = total_size & 0xff;
+	header->par = HAB_HDR_V4;
+	header->mode = HAB_HDR_MODE_CCM;
+	header->alg = HAB_HDR_ALG_AES;
+	header->size = key_size;
+	header->flg = 0;
+
+	return total_size;
+}
+
+static void dekblob_create(ADBG_Case_t *c, TEEC_Session *db_session,
+			   size_t key_size, const struct sm_config *sm_config,
+			   size_t out_buffer_size, uint32_t exp_res)
+{
+	struct hab_dek_blob_header exp_header = {};
+	struct dekblob *dekblob_out = NULL;
+	uint8_t *key = NULL;
+	size_t exp_dek_blob_size = 0;
+	const uint8_t key_byte_value = 0xBA;
+
+	TEEC_Operation dek_op = TEEC_OPERATION_INITIALIZER;
+	TEEC_Operation sm_op = TEEC_OPERATION_INITIALIZER;
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	uint32_t ret_orig = 0;
+	uint32_t param2_type = 0;
+	uint32_t param3_type = 0;
+
+	/* Allocate memory for random key and DEK blob */
+	dekblob_out = calloc(1, out_buffer_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, dekblob_out)) {
+		Do_ADBG_Log("Failed to allocate memory for DEK blob");
+		return;
+	}
+
+	/* Create key for blob */
+	key = malloc(key_size);
+	if (!ADBG_EXPECT_NOT_NULL(c, key)) {
+		Do_ADBG_Log("Failed to allocate memory for random key");
+		goto out;
+	}
+
+	memset(key, key_byte_value, key_size);
+
+	/* Create the DEK blob calling the PTA to encapsulate the random key */
+	dek_op.params[0].tmpref.buffer = (void *)key;
+	dek_op.params[0].tmpref.size = key_size;
+
+	dek_op.params[1].tmpref.buffer = (void *)dekblob_out;
+	dek_op.params[1].tmpref.size = out_buffer_size;
+
+	if (sm_config) {
+		dek_op.params[2].value.a = sm_config->first_page_to_use;
+		dek_op.params[2].value.b = sm_config->additional_pages;
+		dek_op.params[3].value.a = sm_config->partition_to_use;
+
+		param2_type = TEEC_VALUE_INPUT;
+		param3_type = TEEC_VALUE_INPUT;
+	} else {
+		/* Backward compatibility */
+		param2_type = TEEC_NONE;
+		param3_type = TEEC_NONE;
+	}
+
+	dek_op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					     TEEC_MEMREF_TEMP_OUTPUT,
+					     param2_type, param3_type);
+
+	res = TEEC_InvokeCommand(db_session, PTA_DEK_CMD_BLOB_ENCAPSULATE,
+				 &dek_op, &ret_orig);
+	if (!ADBG_EXPECT_TEEC_RESULT(c, exp_res, res)) {
+		Do_ADBG_Log("DEK operation returned unexpected value");
+		goto out;
+	}
+
+	/* If the encapsulation did not expect to succed, returns */
+	if (exp_res != TEEC_SUCCESS)
+		goto out;
+
+	if (sm_config) {
+		/* Free the partition which was used */
+		sm_op.params[0].value.a = sm_config->partition_to_use;
+		sm_op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+						    TEEC_NONE, TEEC_NONE);
+		res = TEEC_InvokeCommand(db_session, PTA_DEK_CMD_FREE_PARTITION,
+					 &sm_op, &ret_orig);
+		if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+			Do_ADBG_Log("Failed to free SM partition %d",
+				    sm_config->partition_to_use);
+			goto out;
+		}
+	}
+
+	/* Create the expected header and getting expecting out size */
+	exp_dek_blob_size = dekblob_create_header(&exp_header, key_size);
+
+	/* Verify the size returned */
+	if (!ADBG_EXPECT(c, exp_dek_blob_size, dek_op.params[1].tmpref.size)) {
+		Do_ADBG_Log("The DEK blob does not have the expected size");
+		goto out;
+	}
+
+	/* Verify the header */
+	if (!ADBG_EXPECT_BUFFER(c, &exp_header, sizeof(exp_header),
+				&dekblob_out->header,
+				sizeof(dekblob_out->header))) {
+		Do_ADBG_Log("The DEK blob header is malformed");
+		goto out;
+	}
+
+out:
+	free(key);
+	free(dekblob_out);
+}
+
+static void nxp_dek_blob_1001(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	uint32_t ret_orig = 0;
+	TEEC_UUID pta_dekblob = PTA_DEK_BLOB_UUID;
+	TEEC_Session db_session = {};
+
+	size_t idx = 0;
+	unsigned int itr = 0;
+
+	/* Open PTA for DEK blob, if it fails, skip the test */
+	res = xtest_teec_open_session(&db_session, &pta_dekblob, NULL,
+				      &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log(
+			"Skip test, pseudo TA for DEK encapsulation not found");
+		return;
+	}
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+		Do_ADBG_Log("Failed to open PTA for DEK encapsulation");
+		return;
+	}
+
+	for (idx = 0; idx < ARRAY_SIZE(dek_blob_gen_sts); idx++) {
+		const struct dek_blob_gen_st *st = &dek_blob_gen_sts[idx];
+
+		Do_ADBG_BeginSubCase(c, "Generation using %s", st->fmt);
+
+		for (itr = 0; itr < st->iteration; itr++) {
+			dekblob_create(c, &db_session, st->key_size,
+				       st->sm_config,
+				       st->key_size + st->padding, st->exp_res);
+		}
+
+		Do_ADBG_EndSubCase(c, "Generation using %s", st->fmt);
+	}
+
+	TEEC_CloseSession(&db_session);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 1001, nxp_dek_blob_1001,
+		 "Test TEE DEK Blob generation");
diff --git a/host/xtest/regression_nxp/digprog/digprog.c b/host/xtest/regression_nxp/digprog/digprog.c
new file mode 100644
index 0000000..4f74699
--- /dev/null
+++ b/host/xtest/regression_nxp/digprog/digprog.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+#include <utee_defines.h>
+#include <util.h>
+#include <string.h>
+
+#include <pta_digprog.h>
+
+static void digprog_pta(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_UUID uuid = PTA_DIGPROG_UUID;
+	TEEC_Session session = {};
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	res = xtest_teec_open_session(&session, &uuid, NULL, &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log("Skip test, PTA for DIGPROG not found");
+		return;
+	}
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+		Do_ADBG_Log("Failed to open TA for DIGPROG");
+		return;
+	}
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(&session, 0, &op, &ret_orig);
+
+	ADBG_EXPECT_TEEC_RESULT(c, TEEC_SUCCESS, res);
+	ADBG_EXPECT_TRUE(c, op.params[0].value.a != 0);
+
+	Do_ADBG_Log("i.MX Platform Digprog 0x%" PRIx32, op.params[0].value.a);
+
+	TEEC_CloseSession(&session);
+}
+ADBG_CASE_DEFINE(regression_nxp, 0011, digprog_pta, "Test i.MX DIGPROG PTA");
diff --git a/host/xtest/regression_nxp/ocotp/ocotp.c b/host/xtest/regression_nxp/ocotp/ocotp.c
new file mode 100644
index 0000000..2968500
--- /dev/null
+++ b/host/xtest/regression_nxp/ocotp/ocotp.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+#include <utee_defines.h>
+#include <util.h>
+#include <string.h>
+
+#include <pta_ocotp.h>
+
+#define UID_TC(_sz, _exp_res) \
+	{ \
+		.uid_size = (_sz), .exp_res = (_exp_res), \
+	}
+
+struct chip_uid_test_case {
+	size_t uid_size;
+	TEEC_Result exp_res;
+};
+
+static const struct chip_uid_test_case chip_uid_tc[] = {
+	UID_TC(0, TEEC_ERROR_BAD_PARAMETERS),
+	UID_TC(-1, TEEC_ERROR_OUT_OF_MEMORY),
+	UID_TC(1, TEEC_ERROR_BAD_PARAMETERS),
+	UID_TC(7, TEEC_ERROR_BAD_PARAMETERS),
+	UID_TC(8, TEEC_SUCCESS),
+	UID_TC(9, TEEC_ERROR_BAD_PARAMETERS),
+	UID_TC(16, TEEC_ERROR_BAD_PARAMETERS),
+	UID_TC(255, TEEC_ERROR_BAD_PARAMETERS),
+};
+
+static void chip_uid(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_UUID uuid = PTA_OCOTP_UUID;
+	TEEC_Session session = {};
+	uint32_t ret_orig = 0;
+	unsigned int i = 0;
+	unsigned int j = 0;
+
+	Do_ADBG_BeginSubCase(c, "Test i.MX Chip IUD read");
+
+	res = xtest_teec_open_session(&session, &uuid, NULL, &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log("Skip test, PTA for OCOTP not found");
+		goto err;
+	}
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+		Do_ADBG_Log("Failed to open TA for OCOTP");
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(chip_uid_tc); i++) {
+		TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+		const struct chip_uid_test_case *tc = &chip_uid_tc[i];
+		uint8_t val[8] = {};
+
+		Do_ADBG_BeginSubCase(c, "Request UID size %zu", tc->uid_size);
+
+		op.params[0].tmpref.size = tc->uid_size;
+		op.params[0].tmpref.buffer = val;
+
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
+						 TEEC_NONE, TEEC_NONE,
+						 TEEC_NONE);
+
+		res = TEEC_InvokeCommand(&session, PTA_OCOTP_CHIP_UID, &op,
+					 &ret_orig);
+
+		if (!ADBG_EXPECT_TEEC_RESULT(c, tc->exp_res, res))
+			goto err;
+
+		if (res == TEEC_SUCCESS) {
+			printf("Chip UID: ");
+			for (j = 0; j < ARRAY_SIZE(val); j++)
+				printf("%02x", val[j]);
+			printf("\n");
+		}
+
+		Do_ADBG_EndSubCase(c, "Request UID size %zu", tc->uid_size);
+	}
+
+err:
+	Do_ADBG_EndSubCase(c, "Test i.MX Chip IUD read");
+	TEEC_CloseSession(&session);
+}
+
+#define FUSE_READ_TC(_b, _w, _exp_res) \
+	{ \
+		.bank = (_b), .word = (_w), .exp_res = (_exp_res), \
+	}
+
+struct fuse_read_test_case {
+	unsigned int bank;
+	unsigned int word;
+	TEEC_Result exp_res;
+};
+
+static const struct fuse_read_test_case fuse_read_tc[] = {
+	FUSE_READ_TC(0, 1, TEEC_SUCCESS),
+	FUSE_READ_TC(0, 2, TEEC_SUCCESS),
+	FUSE_READ_TC(-1, -1, TEEC_ERROR_BAD_PARAMETERS),
+	FUSE_READ_TC(1, 128, TEEC_ERROR_BAD_PARAMETERS),
+	FUSE_READ_TC(128, 1, TEEC_ERROR_BAD_PARAMETERS),
+};
+
+static void fuse_read(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_UUID uuid = PTA_OCOTP_UUID;
+	TEEC_Session session = {};
+	uint32_t ret_orig = 0;
+	unsigned int i = 0;
+
+	Do_ADBG_BeginSubCase(c, "Test i.MX OCOTP fuse read");
+
+	res = xtest_teec_open_session(&session, &uuid, NULL, &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log("Skip test, PTA for OCOTP not found");
+		goto err;
+	}
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+		Do_ADBG_Log("Failed to open TA for OCOTP");
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fuse_read_tc); i++) {
+		TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+		const struct fuse_read_test_case *tc = &fuse_read_tc[i];
+
+		Do_ADBG_BeginSubCase(c, "Request fuse read bank %d word %d",
+				     tc->bank, tc->word);
+
+		op.params[0].value.a = tc->bank;
+		op.params[0].value.b = tc->word;
+
+		op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+						 TEEC_VALUE_OUTPUT, TEEC_NONE,
+						 TEEC_NONE);
+
+		res = TEEC_InvokeCommand(&session, PTA_OCOTP_READ_FUSE, &op,
+					 &ret_orig);
+
+		if (!ADBG_EXPECT_TEEC_RESULT(c, tc->exp_res, res))
+			goto err;
+
+		if (res == TEEC_SUCCESS)
+			Do_ADBG_Log("Fuse: 0x%X", op.params[1].value.a);
+
+		Do_ADBG_EndSubCase(c, "Request fuse read bank %d word %d",
+				   tc->bank, tc->word);
+	}
+
+err:
+	Do_ADBG_EndSubCase(c, "Test i.MX OCOTP fuse read");
+	TEEC_CloseSession(&session);
+}
+
+static void ocotp_pta(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_UUID uuid = PTA_OCOTP_UUID;
+	TEEC_Session session = {};
+	uint32_t ret_orig = 0;
+
+	Do_ADBG_BeginSubCase(c, "Open OCOTP PTA");
+
+	res = xtest_teec_open_session(&session, &uuid, NULL, &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log("Skip test, PTA for OCOTP not found");
+		return;
+	}
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) {
+		Do_ADBG_Log("Failed to open TA for OCOTP");
+		return;
+	}
+
+	TEEC_CloseSession(&session);
+
+	Do_ADBG_EndSubCase(c, "Open OCOTP PTA");
+
+	chip_uid(c);
+	fuse_read(c);
+}
+ADBG_CASE_DEFINE(regression_nxp, 0010, ocotp_pta, "Test i.MX OCOTP PTA");
diff --git a/host/xtest/regression_nxp/peripherals/i2c.c b/host/xtest/regression_nxp/peripherals/i2c.c
new file mode 100644
index 0000000..5b49a14
--- /dev/null
+++ b/host/xtest/regression_nxp/peripherals/i2c.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <assert.h>
+#include <pta_i2c_rtc_test.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+
+#include <utee_defines.h>
+#include <util.h>
+
+static TEEC_Result run_test_suite(ADBG_Case_t *c, TEEC_Session *s)
+{
+	TEEC_Result res = TEEC_ERROR_GENERIC;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	uint32_t ret_orig = 0;
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE,
+			TEEC_NONE, TEEC_NONE);
+
+	res = TEEC_InvokeCommand(s, PTA_CMD_I2C_RTC_RUN_TEST_SUITE, &op,
+			&ret_orig);
+
+	if (res != TEEC_SUCCESS) {
+		(void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP,
+				ret_orig);
+	}
+
+	return res;
+}
+
+static void nxp_peripheral_i2c_001(ADBG_Case_t *c)
+{
+	TEEC_Result res = TEE_ERROR_GENERIC;
+	TEEC_Session session = { };
+
+	const TEEC_UUID pta_ls_i2c_rtc_test_uuid = PTA_LS_I2C_RTC_TEST_SUITE_UUID;
+	uint32_t ret_orig = 0;
+
+	/* Pseudo TA is optional: warn and nicely exit if not found */
+	res = xtest_teec_open_session(&session, &pta_ls_i2c_rtc_test_uuid, NULL,
+				      &ret_orig);
+	if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
+		Do_ADBG_Log("regression_nxp 0006 - skip test, PTA not found");
+		return;
+	}
+	ADBG_EXPECT_TEEC_SUCCESS(c, res);
+
+	res = run_test_suite(c, &session);
+	ADBG_EXPECT_TEEC_SUCCESS(c, res);
+
+	TEEC_CloseSession(&session);
+}
+
+ADBG_CASE_DEFINE(regression_nxp, 0006, nxp_peripheral_i2c_001,
+		"Test LS I2C driver with RTC clock (Will take around 10 Seconds)");
diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c
index c61f4db..3120fca 100644
--- a/host/xtest/xtest_main.c
+++ b/host/xtest/xtest_main.c
@@ -40,6 +40,9 @@ ADBG_SUITE_DEFINE(pkcs11);
 ADBG_SUITE_DEFINE(ffa_spmc);
 #endif
 ADBG_SUITE_DEFINE(regression);
+#ifdef CFG_REGRESSION_NXP
+ADBG_SUITE_DEFINE(regression_nxp);
+#endif
 
 char *xtest_tee_name = NULL;
 unsigned int level = 0;
@@ -63,7 +66,14 @@ static const char glevel[] = "0";
 #define FFA_SPMC_SUITE	""
 #endif
 
-static char gsuitename[] = "regression" GP_SUITE PKCS11_SUITE FFA_SPMC_SUITE;
+#ifdef CFG_REGRESSION_NXP
+#define NXP_SUITE	"+regression_nxp"
+#else
+#define NXP_SUITE	""
+#endif
+
+
+static char gsuitename[] = "regression" GP_SUITE PKCS11_SUITE FFA_SPMC_SUITE NXP_SUITE;
 
 void usage(char *program);
 
@@ -100,6 +110,10 @@ void usage(char *program)
 	printf("applets:\n");
 	printf("\t--sha-perf [opts]  SHA performance testing tool (-h for usage)\n");
 	printf("\t--aes-perf [opts]  AES performance testing tool (-h for usage)\n");
+	printf("\t--crypto-perf      Crypto performance testing tool for OP-TEE\n");
+	printf("\t--crypto-perf -h   show usage of Crypto performance testing tool\n");
+	printf("\n");
+
 #ifdef CFG_SECSTOR_TA_MGMT_PTA
 	printf("\t--install-ta [directory or list of TAs]\n");
 	printf("\t                   Install TAs\n");
@@ -156,6 +170,8 @@ int main(int argc, char *argv[])
 		return sha_perf_runner_cmd_parser(argc-1, &argv[1]);
 	else if (argc > 1 && !strcmp(argv[1], "--aes-perf"))
 		return aes_perf_runner_cmd_parser(argc-1, &argv[1]);
+	else if (argc > 1 && !strcmp(argv[1], "--crypto-perf"))
+		return crypto_perf_runner_cmd_parser(argc-1, &argv[1]);
 #ifdef CFG_SECSTOR_TA_MGMT_PTA
 	else if (argc > 1 && !strcmp(argv[1], "--install-ta"))
 		return install_ta_runner_cmd_parser(argc - 1, argv + 1);
@@ -249,6 +265,10 @@ next:
 #ifdef CFG_SPMC_TESTS
 		else if (!strcmp(token, "ffa_spmc"))
 			ret = Do_ADBG_AppendToSuite(&all, &ADBG_Suite_ffa_spmc);
+#endif
+#ifdef CFG_REGRESSION_NXP
+		else if (!strcmp(token, "regression_nxp"))
+			ret = Do_ADBG_AppendToSuite(&all, &ADBG_Suite_regression_nxp);
 #endif
 		else {
 			fprintf(stderr, "Unkown test suite: %s\n", token);
diff --git a/host/xtest/xtest_test.h b/host/xtest/xtest_test.h
index 215024b..83c4371 100644
--- a/host/xtest/xtest_test.h
+++ b/host/xtest/xtest_test.h
@@ -24,6 +24,9 @@ ADBG_SUITE_DECLARE(pkcs11);
 ADBG_SUITE_DECLARE(ffa_spmc);
 #endif
 ADBG_SUITE_DECLARE(regression);
+#ifdef CFG_REGRESSION_NXP
+ADBG_SUITE_DECLARE(regression_nxp);
+#endif
 
 /* TEEC_Result */
 ADBG_ENUM_TABLE_DECLARE(TEEC_Result);
diff --git a/ta/CMakeLists.txt b/ta/CMakeLists.txt
index b8df063..82b6577 100644
--- a/ta/CMakeLists.txt
+++ b/ta/CMakeLists.txt
@@ -23,4 +23,5 @@ target_include_directories(${PROJECT_NAME}
 	INTERFACE bti_test/include
 	INTERFACE supp_plugin/include
 	INTERFACE large/include
+	INTERFACE mp_sign/include
 )
diff --git a/ta/Makefile b/ta/Makefile
index 20f22e6..31fb0f6 100644
--- a/ta/Makefile
+++ b/ta/Makefile
@@ -32,7 +32,9 @@ TA_DIRS := create_fail_test \
 	   aes_perf \
 	   socket \
 	   supp_plugin \
-	   large
+	   large \
+	   crypto_perf \
+	   mp_sign
 
 ifeq ($(CFG_SECURE_DATA_PATH),y)
 TA_DIRS += sdp_basic
@@ -46,7 +48,7 @@ endif
 all: ta
 
 .PHONY: ta
-ta: 
+ta:
 	$(q)$(foreach dir,$(TA_DIRS), $(MAKE) -C $(dir) O=$(out-dir)/ta/$(dir) &&) true
 
 # remove build directories including ta/<ta-name>/ directories.
diff --git a/ta/crypto_perf/Android.mk b/ta/crypto_perf/Android.mk
new file mode 100644
index 0000000..ceb8916
--- /dev/null
+++ b/ta/crypto_perf/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 690d2100-dbe5-11e6-bf26-cec0c932ce01.ta
+include $(BUILD_OPTEE_MK)
diff --git a/ta/crypto_perf/Makefile b/ta/crypto_perf/Makefile
new file mode 100644
index 0000000..f8dbaf5
--- /dev/null
+++ b/ta/crypto_perf/Makefile
@@ -0,0 +1,3 @@
+BINARY = 690d2100-dbe5-11e6-bf26-cec0c932ce01
+include ../ta_common.mk
+
diff --git a/ta/crypto_perf/include/ta_crypto_perf.h b/ta/crypto_perf/include/ta_crypto_perf.h
new file mode 100644
index 0000000..207a0c8
--- /dev/null
+++ b/ta/crypto_perf/include/ta_crypto_perf.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2018-2022 NXP
+ */
+
+#ifndef __TA_CRYPTO_PERF_H__
+#define __TA_CRYPTO_PERF_H__
+
+#include <ta_crypto_perf_test.h>
+#include <tee_api.h>
+#include <utee_defines.h>
+
+#define FORCE_DEBUG 0
+
+#ifndef FORCE_DEBUG
+#define CHECK(res, name, action) do { \
+		if ((res) != TEE_SUCCESS) { \
+			DMSG(name ": 0x%08x", (res)); \
+			action \
+		} \
+	} while (0)
+#else
+#define CHECK(res, name, action) do { \
+		if ((res) != TEE_SUCCESS) { \
+			MSG(name ": 0x%08x", (res)); \
+			action \
+		} \
+	} while (0)
+#endif
+
+uint32_t get_nb_algo(void);
+uint32_t get_size_name_alg_list(void);
+void     copy_name_alg_list(char *buffer);
+uint32_t get_alg_id(char *name, size_t size);
+
+
+/* Cipher Functions */
+TEE_Result TA_CipherPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_CipherProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_CipherFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Digest Functions */
+TEE_Result TA_DigestPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_DigestProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_DigestFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Mac Functions */
+TEE_Result TA_MacPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_MacProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_MacFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Asymmetric Cipher Functions */
+TEE_Result TA_AsymCipherPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AsymCipherProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AsymCipherFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Asymmetric Digest Functions */
+TEE_Result TA_AsymDigestPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AsymDigestProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AsymDigestFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Key Derivation Functions */
+TEE_Result TA_KeyDerivePrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_KeyDeriveProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_KeyDeriveFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Authenticated Encryption Functions */
+TEE_Result TA_AuthenEncPrepareAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AuthenEncProcessAlgo(uint32_t algo, TEE_Param params[4]);
+TEE_Result TA_AuthenEncFreeAlgo(uint32_t algo, TEE_Param params[4]);
+
+/* Key generation functions */
+TEE_Result TA_PrepareGen(uint32_t ParamTypes, TEE_Param Params[4]);
+TEE_Result TA_Generate(uint32_t ParamTypes, TEE_Param Params[4]);
+void TA_FreeGen(void);
+#endif
diff --git a/ta/crypto_perf/include/ta_crypto_perf_test.h b/ta/crypto_perf/include/ta_crypto_perf_test.h
new file mode 100644
index 0000000..f447d8e
--- /dev/null
+++ b/ta/crypto_perf/include/ta_crypto_perf_test.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2018, 2022 NXP
+ */
+
+#ifndef __TA_CRYPTO_PERF_TEST_H__
+#define __TA_CRYPTO_PERF_TEST_H__
+
+#include <tee_api_types.h>
+
+/* This UUID is generated with uuidgen */
+#define TA_CRYPTO_PERF_TEST_UUID { 0x690d2100, 0xdbe5, 0x11e6, \
+	{ 0xbf, 0x26, 0xce, 0xc0, 0xc9, 0x32, 0xce, 0x01 } }
+
+/* TA Capabilities structure */
+struct ta_caps {
+	uint8_t  nb_algo;
+	uint32_t sizeof_alg_list;
+
+};
+
+/* Define of TA Command available */
+#define TA_CRYPTO_PERF_CMD_GET_CAPS		(1)
+#define TA_CRYPTO_PERF_CMD_GET_LIST_ALG	(2)
+#define TA_CRYPTO_PERF_CMD_PREPARE_ALG	(3)
+#define TA_CRYPTO_PERF_CMD_PROCESS		(4)
+#define TA_CRYPTO_PERF_CMD_FREE_ALG		(5)
+#define TA_CRYPTO_PERF_CMD_PREPARE_GEN		(6)
+#define TA_CRYPTO_PERF_CMD_GENERATE		(7)
+#define TA_CRYPTO_PERF_CMD_FREE_GEN		(8)
+
+#endif
diff --git a/ta/crypto_perf/include/test_vectors_dsa.h b/ta/crypto_perf/include/test_vectors_dsa.h
new file mode 100644
index 0000000..efd1bd9
--- /dev/null
+++ b/ta/crypto_perf/include/test_vectors_dsa.h
@@ -0,0 +1,427 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2021, SumUp Services GmbH
+ * Copyright 2021-2022 NXP
+ */
+
+#ifndef __TEST_VECTORS_DSA_H__
+#define __TEST_VECTORS_DSA_H__
+
+#include <stdint.h>
+#include <util.h>
+
+/*
+ * Test data from 186-3dsatestvectors.zip KeyPair.rsp
+ * http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3dsatestvectors.zip
+ * Copied from regression_4000_data.h
+ */
+static const uint8_t keygen_dsa512_p[] = {
+	0xC8, 0x6B, 0xB7, 0x91, 0xD6, 0x63, 0xCE, 0xC0, 0xC6, 0xB8, 0xAC, 0x5B,
+	0xEB, 0xA7, 0xEF, 0x17, 0xBE, 0x1A, 0x1A, 0x36, 0x6B, 0x38, 0x40, 0x0E,
+	0x69, 0x13, 0x32, 0xD4, 0x4B, 0xBE, 0x00, 0xB5, 0x29, 0x7F, 0x6B, 0x87,
+	0xAA, 0x1D, 0x98, 0x37, 0xD2, 0xAC, 0x62, 0x26, 0xD7, 0xFD, 0xE1, 0xC9,
+	0x13, 0x4F, 0x2A, 0xF2, 0x82, 0xEC, 0xA8, 0x83, 0x6F, 0x29, 0xD3, 0xF5,
+	0x16, 0xB9, 0x13, 0xCD,
+};
+
+static const uint8_t keygen_dsa512_q[] = {
+	0x8D, 0xF9, 0x8B, 0x8A, 0xDA, 0x3B, 0x0B, 0x1C, 0xFA, 0x1C, 0xA7, 0xE8,
+	0x9A, 0xA2, 0xD7, 0xC3, 0x2D, 0xD5, 0x9D, 0x1B,
+};
+
+static const uint8_t keygen_dsa512_g[] = {
+	0xB3, 0xE2, 0xFD, 0x38, 0xE0, 0x9A, 0x21, 0x64, 0x8F, 0x6D, 0x7E, 0x4F,
+	0xC2, 0x24, 0x18, 0x88, 0xEC, 0xA4, 0xCB, 0xB0, 0x5F, 0x43, 0xD8, 0x2B,
+	0x5B, 0xDE, 0x01, 0xB4, 0xD2, 0x24, 0x1F, 0x80, 0xE7, 0xFC, 0xF3, 0x15,
+	0xFA, 0x0C, 0x5B, 0x6F, 0x81, 0x55, 0x8C, 0x80, 0x36, 0xFB, 0x4D, 0xB5,
+	0x8C, 0x5A, 0x26, 0xBE, 0xFB, 0x78, 0xEA, 0x62, 0x6A, 0x9D, 0x5E, 0xD0,
+	0x21, 0x0C, 0xD9, 0x4E,
+};
+static const uint8_t keygen_dsa576_p[] = {
+	0xF7, 0x85, 0x23, 0x2C, 0x2C, 0x86, 0xD4, 0x2B, 0xE5, 0x09, 0xAB, 0x60,
+	0xD6, 0x79, 0x05, 0x13, 0x75, 0x78, 0x1E, 0xAE, 0xEB, 0x5F, 0xBA, 0xFA,
+	0x6E, 0x05, 0xE7, 0xB3, 0x8D, 0x33, 0x4B, 0xE5, 0xB5, 0xAA, 0xD4, 0xE6,
+	0xA3, 0x9B, 0xA2, 0xF5, 0x7B, 0xF6, 0x32, 0xE6, 0x31, 0x6F, 0x34, 0x46,
+	0x16, 0xEA, 0xD8, 0x94, 0x79, 0xD7, 0x69, 0x23, 0xA4, 0x04, 0xE2, 0x25,
+	0xBB, 0x6D, 0xCC, 0x6E, 0x99, 0xB7, 0x90, 0x90, 0x89, 0xB9, 0x88, 0x19,
+};
+
+static const uint8_t keygen_dsa576_q[] = {
+	0xF0, 0xD8, 0x71, 0x31, 0xB5, 0x01, 0xC1, 0x6B, 0x09, 0xCE, 0x7D, 0x2F,
+	0x82, 0x48, 0xB0, 0x21, 0x9C, 0xD6, 0xB5, 0xB1,
+};
+
+static const uint8_t keygen_dsa576_g[] = {
+	0x33, 0x45, 0xB8, 0x9A, 0x17, 0x4B, 0xBF, 0xD3, 0xB2, 0xBA, 0xD2, 0xE4,
+	0xAC, 0x54, 0xA0, 0x9B, 0x5F, 0x5D, 0x95, 0x88, 0x9C, 0x0C, 0x59, 0xCE,
+	0x40, 0x0C, 0x05, 0xFD, 0xC4, 0x9D, 0x22, 0x27, 0xDA, 0xA6, 0xD1, 0x10,
+	0x61, 0x46, 0x31, 0x5C, 0x7D, 0x4E, 0xF6, 0x01, 0x38, 0x9A, 0x7E, 0x72,
+	0x4E, 0x7A, 0x07, 0xFB, 0x6D, 0x20, 0x9D, 0x59, 0xC6, 0x33, 0x6A, 0x64,
+	0xBF, 0x14, 0x30, 0x4E, 0x0C, 0x64, 0x9D, 0x11, 0xCF, 0x64, 0xCE, 0x29,
+};
+
+static const uint8_t keygen_dsa640_p[] = {
+	0x88, 0x8C, 0x58, 0x99, 0xF4, 0x78, 0xEA, 0x31, 0x56, 0xB7, 0x2C, 0x70,
+	0xDC, 0x09, 0x5D, 0xB9, 0x13, 0x16, 0xCE, 0xDF, 0xFD, 0x8C, 0x4E, 0xF8,
+	0x32, 0x59, 0x00, 0x58, 0xD6, 0x44, 0x4F, 0x95, 0xF7, 0x85, 0x14, 0xC3,
+	0x10, 0x5A, 0xA2, 0x44, 0x2F, 0xA2, 0xC9, 0xB4, 0x88, 0x89, 0xA1, 0xAE,
+	0x0E, 0x82, 0xE1, 0xC1, 0x45, 0x09, 0x98, 0xF7, 0xCB, 0xF2, 0xD8, 0xA0,
+	0x6E, 0x32, 0x02, 0xE4, 0x0E, 0x7A, 0x43, 0x3A, 0xE1, 0x04, 0x4C, 0xC5,
+	0x78, 0x0E, 0x02, 0x27, 0xC4, 0xD0, 0xCA, 0x29,
+};
+
+static const uint8_t keygen_dsa640_q[] = {
+	0xD7, 0x63, 0x4F, 0x3E, 0x6D, 0x52, 0x93, 0x69, 0xFA, 0xFF, 0xDE, 0x0D,
+	0x57, 0x3F, 0x24, 0xBB, 0x01, 0xF8, 0x01, 0xAD,
+};
+
+static const uint8_t keygen_dsa640_g[] = {
+	0x76, 0xCB, 0x07, 0xB9, 0xE9, 0x3F, 0x3C, 0xA5, 0x18, 0x43, 0x83, 0xE6,
+	0xBC, 0x42, 0x09, 0xD9, 0xC5, 0x1C, 0x56, 0x57, 0x0B, 0x5B, 0x46, 0x65,
+	0x00, 0x67, 0xCA, 0x33, 0xC0, 0xA6, 0x37, 0xEA, 0x89, 0xAE, 0xDF, 0x1D,
+	0x79, 0x96, 0xC7, 0x0C, 0xD2, 0xAC, 0xD3, 0x2C, 0x46, 0xC2, 0xA0, 0x9D,
+	0x4B, 0x06, 0xB5, 0xDF, 0xAE, 0x73, 0xEB, 0x9A, 0x6A, 0x54, 0x39, 0x2C,
+	0xB1, 0x98, 0xAD, 0x44, 0xF3, 0x29, 0xC9, 0xC5, 0x75, 0xF1, 0x3C, 0xD8,
+	0x3B, 0xA1, 0x85, 0x29, 0x38, 0xB9, 0x17, 0xA5,
+};
+
+static const uint8_t keygen_dsa704_p[] = {
+	0xDA, 0xEA, 0x9B, 0x6B, 0x35, 0x06, 0x2E, 0x7E, 0x71, 0xB2, 0x11, 0xD0,
+	0x37, 0x84, 0x88, 0xC0, 0x50, 0x94, 0x73, 0x78, 0xA8, 0x9C, 0xBD, 0x8C,
+	0xB1, 0x0A, 0xD5, 0x89, 0x52, 0x39, 0xBF, 0x41, 0xDC, 0xB9, 0xE5, 0x16,
+	0x1A, 0x86, 0xD5, 0xCF, 0xD6, 0x26, 0x84, 0x95, 0xE9, 0x0D, 0xCD, 0x98,
+	0x21, 0x6B, 0x3C, 0xFE, 0x6D, 0x2D, 0x42, 0x1A, 0x3F, 0xE0, 0xFF, 0x07,
+	0x41, 0x82, 0x30, 0x15, 0x17, 0xF3, 0x0F, 0x7B, 0xA0, 0xD3, 0x46, 0xFA,
+	0x1F, 0x1E, 0xEC, 0xBD, 0x26, 0xCE, 0x4C, 0xE3, 0xBD, 0x73, 0xA3, 0xA6,
+	0xA0, 0x12, 0xE1, 0xFD,
+};
+
+static const uint8_t keygen_dsa704_q[] = {
+	0xCE, 0xB3, 0x2E, 0x41, 0xEB, 0xFD, 0x22, 0x2A, 0xCE, 0x9A, 0xAF, 0x24,
+	0xE3, 0x02, 0x50, 0xDE, 0x47, 0xBC, 0x4C, 0x1F,
+};
+
+static const uint8_t keygen_dsa704_g[] = {
+	0x08, 0x83, 0x72, 0x6D, 0x0A, 0x8F, 0x19, 0x61, 0xE4, 0x62, 0x40, 0x29,
+	0x66, 0x6B, 0xDE, 0xBD, 0xAB, 0xE3, 0x5B, 0x58, 0x3F, 0xF5, 0xEA, 0xDE,
+	0x8E, 0x7A, 0x34, 0xAF, 0x1C, 0x99, 0x03, 0x1A, 0x51, 0x17, 0xFC, 0xE0,
+	0xA3, 0x22, 0x43, 0x63, 0xB6, 0x7E, 0x29, 0x4B, 0x23, 0x6C, 0xD1, 0xDE,
+	0x59, 0xEC, 0x1D, 0x67, 0x94, 0xDD, 0x2E, 0x88, 0x86, 0xD3, 0xD6, 0x68,
+	0x58, 0x36, 0x48, 0xF8, 0xEF, 0x38, 0x3F, 0xF5, 0x87, 0x96, 0x38, 0xD3,
+	0x48, 0x50, 0x1F, 0xA3, 0x4A, 0xCA, 0xD7, 0x4D, 0xC3, 0x84, 0x83, 0xB1,
+	0x8A, 0x95, 0xE0, 0xB3,
+};
+
+static const uint8_t keygen_dsa768_p[] = {
+	0xF0, 0xB1, 0x93, 0xFD, 0x53, 0x98, 0x23, 0x43, 0xFB, 0x04, 0xB1, 0x31,
+	0x80, 0x3D, 0xD3, 0x95, 0x56, 0x51, 0xCC, 0x32, 0xA4, 0x51, 0x00, 0x8A,
+	0x80, 0xB6, 0x87, 0x70, 0xD7, 0x77, 0x8D, 0xA6, 0xC2, 0xB5, 0x85, 0xE1,
+	0xE0, 0x9E, 0x11, 0x28, 0x72, 0xE9, 0x45, 0x5B, 0x4D, 0xC9, 0xDC, 0x46,
+	0x64, 0x2F, 0x44, 0xD8, 0x24, 0xE3, 0x9B, 0xCC, 0xF9, 0x66, 0x31, 0x9C,
+	0x40, 0x64, 0xED, 0xC5, 0x48, 0x30, 0x84, 0x0C, 0xF9, 0x1F, 0xBC, 0x75,
+	0xD8, 0x8C, 0x53, 0x30, 0x25, 0xB6, 0xBD, 0xDA, 0xBE, 0xBC, 0xBA, 0x86,
+	0xB3, 0x7D, 0x27, 0x74, 0x9D, 0x68, 0xEA, 0xB8, 0xE0, 0x09, 0x3A, 0x7F,
+};
+
+static const uint8_t keygen_dsa768_q[] = {
+	0xC9, 0x8C, 0x79, 0x7B, 0x98, 0xB5, 0xFD, 0x80, 0x5D, 0x4B, 0x26, 0x30,
+	0x42, 0x63, 0xDE, 0x37, 0xAB, 0x4B, 0xB7, 0xAF,
+};
+
+static const uint8_t keygen_dsa768_g[] = {
+	0xD4, 0xE8, 0xF1, 0xB9, 0x6D, 0x40, 0x26, 0x19, 0x72, 0x39, 0x5C, 0x6F,
+	0x68, 0x4C, 0x8C, 0x18, 0xD8, 0x49, 0x3C, 0xB6, 0x5D, 0x72, 0xE3, 0xF4,
+	0x89, 0x24, 0x69, 0xC8, 0x76, 0x83, 0x38, 0xA2, 0x23, 0xF5, 0xB3, 0xD5,
+	0xCB, 0x0F, 0xC4, 0xFE, 0x45, 0x65, 0x2F, 0x2C, 0x3D, 0x32, 0x02, 0x28,
+	0xE5, 0xCA, 0x34, 0xEC, 0x1A, 0xBB, 0x82, 0x93, 0x2A, 0xD9, 0x64, 0x1E,
+	0xC5, 0x91, 0x34, 0x60, 0xF2, 0xE2, 0x2D, 0x64, 0x4E, 0x46, 0xAA, 0x00,
+	0x6F, 0x26, 0xD8, 0x98, 0x97, 0xBF, 0xCC, 0xF1, 0x1B, 0x4A, 0x8A, 0x7D,
+	0x39, 0xA4, 0xA4, 0x23, 0x82, 0x64, 0x78, 0x40, 0xED, 0x4C, 0x96, 0xB9,
+};
+
+static const uint8_t keygen_dsa832_p[] = {
+	0x93, 0x47, 0x85, 0x69, 0x79, 0xF2, 0xAA, 0xC2, 0x83, 0xA4, 0x08, 0x2F,
+	0x3C, 0xE5, 0x4D, 0x3B, 0xFF, 0x4D, 0xC5, 0xF4, 0x03, 0x20, 0xFA, 0x15,
+	0xA8, 0x27, 0x80, 0x55, 0x29, 0x57, 0x60, 0x0B, 0x75, 0x01, 0x7B, 0x65,
+	0xCE, 0x4D, 0x7C, 0xF6, 0x7C, 0x4F, 0x1D, 0xC3, 0x67, 0xF2, 0xC1, 0x64,
+	0x38, 0x49, 0x54, 0x60, 0x57, 0x05, 0xEB, 0x31, 0xFA, 0x7B, 0x50, 0xA1,
+	0x0F, 0xCB, 0xC4, 0x4E, 0xDF, 0x92, 0x5A, 0x8B, 0x11, 0xBA, 0x6B, 0x7E,
+	0x7A, 0xB4, 0x80, 0xD0, 0x9A, 0xE2, 0x88, 0x7D, 0x83, 0xA6, 0x81, 0x81,
+	0x71, 0xD0, 0x06, 0xDE, 0xCC, 0xA4, 0xB9, 0x0A, 0x6B, 0x81, 0x31, 0x28,
+	0x1D, 0xEF, 0x5F, 0x99, 0xDE, 0xEC, 0xDA, 0x4D,
+};
+
+static const uint8_t keygen_dsa832_q[] = {
+	0xF8, 0xF5, 0xAF, 0x31, 0x0D, 0xBE, 0x6F, 0x4B, 0x79, 0x87, 0xA2, 0x98,
+	0xED, 0xF1, 0x2A, 0x93, 0x3D, 0x12, 0x5D, 0x25,
+};
+
+static const uint8_t keygen_dsa832_g[] = {
+	0x11, 0x21, 0xBC, 0x83, 0x7A, 0xD9, 0x5F, 0x0E, 0xA2, 0xF7, 0x96, 0xB7,
+	0x6A, 0xDD, 0xAE, 0xBA, 0x11, 0x26, 0x58, 0xF6, 0xB1, 0xCF, 0x94, 0x35,
+	0x3B, 0xFB, 0x9C, 0x9B, 0x16, 0xB8, 0x58, 0xBA, 0x2F, 0x5C, 0xE5, 0x18,
+	0xE1, 0x29, 0xA6, 0xA3, 0x1C, 0x0C, 0xA5, 0xC7, 0xAE, 0xE8, 0x31, 0x26,
+	0x8C, 0xCD, 0xA5, 0x69, 0xB2, 0x74, 0x31, 0x15, 0xCE, 0x82, 0xCD, 0x32,
+	0xF7, 0xC8, 0x90, 0x60, 0x96, 0x61, 0x07, 0x60, 0x63, 0x6B, 0x48, 0x03,
+	0xCD, 0x1F, 0x58, 0x7D, 0x8E, 0xAF, 0x26, 0x16, 0x3B, 0xC6, 0xA6, 0x03,
+	0xB4, 0xE1, 0x3E, 0xBE, 0x5B, 0xC9, 0xD3, 0xBD, 0xB6, 0x31, 0xC9, 0x34,
+	0x2C, 0x2B, 0x08, 0x3C, 0xE0, 0x1C, 0x1E, 0x01,
+};
+
+static const uint8_t keygen_dsa896_p[] = {
+	0xCA, 0x16, 0xD2, 0xB2, 0x7C, 0xC5, 0x25, 0x99, 0x3A, 0xCC, 0xCB, 0x3F,
+	0x72, 0xAE, 0xD4, 0xA0, 0x1E, 0xE0, 0x19, 0x6A, 0x8A, 0xC2, 0xFC, 0xD5,
+	0xB2, 0xCC, 0xD1, 0x6F, 0xA3, 0x95, 0x30, 0xEC, 0x2B, 0x4A, 0x46, 0x6C,
+	0x72, 0xC3, 0x31, 0xFD, 0x94, 0x00, 0x55, 0xE7, 0x03, 0xC3, 0xDE, 0xD7,
+	0xE3, 0xF8, 0xAF, 0x32, 0x0A, 0x29, 0x32, 0xC5, 0x97, 0x93, 0x2A, 0xE6,
+	0xC6, 0x82, 0x49, 0x5C, 0x76, 0xB3, 0xCB, 0x47, 0xD7, 0xFF, 0xEA, 0xE5,
+	0x47, 0x87, 0x08, 0x6C, 0xEA, 0x6D, 0x1A, 0xF6, 0x47, 0xBA, 0xE3, 0x94,
+	0xE9, 0xFE, 0xF6, 0x06, 0xA1, 0x99, 0xDC, 0xCB, 0x3D, 0x7A, 0x06, 0x31,
+	0xAC, 0x25, 0xD3, 0x3C, 0x35, 0xAD, 0x36, 0x8D, 0x25, 0x41, 0xE9, 0x21,
+	0xD1, 0xF9, 0xC3, 0xC9,
+};
+
+static const uint8_t keygen_dsa896_q[] = {
+	0xAE, 0x42, 0x0A, 0x1D, 0x76, 0xA9, 0xFB, 0xF1, 0xCB, 0x2D, 0x73, 0x35,
+	0x3F, 0x98, 0x63, 0x34, 0xE1, 0xCD, 0x3C, 0xCF,
+};
+
+static const uint8_t keygen_dsa896_g[] = {
+	0x12, 0xD0, 0x15, 0x32, 0x0B, 0x7D, 0xE3, 0xD0, 0x36, 0x51, 0x79, 0x3E,
+	0xB4, 0x4E, 0xE2, 0x1E, 0x5E, 0x3E, 0x43, 0x4C, 0x5D, 0x49, 0x9D, 0xD4,
+	0xA3, 0xE3, 0xC8, 0x1F, 0x46, 0xA2, 0xCE, 0x95, 0xF9, 0x8D, 0xFC, 0xFD,
+	0x50, 0x48, 0xBF, 0xB5, 0x25, 0xB6, 0xFD, 0xF9, 0xF1, 0x97, 0xD5, 0x82,
+	0xEE, 0xE7, 0xDF, 0xC6, 0xDD, 0x09, 0x96, 0x15, 0xC0, 0x95, 0x60, 0xF4,
+	0x53, 0xF6, 0x19, 0xA4, 0x84, 0x53, 0xE4, 0x87, 0xB6, 0x0C, 0x6C, 0x01,
+	0x31, 0x72, 0x56, 0xA4, 0x2E, 0x25, 0xFC, 0x46, 0xB0, 0x47, 0xF3, 0x5A,
+	0x90, 0x69, 0xAC, 0x64, 0x02, 0xCB, 0x1F, 0x5F, 0x10, 0x70, 0x2B, 0x71,
+	0xF7, 0x9B, 0x70, 0x22, 0x7F, 0x05, 0xEB, 0xCB, 0x6D, 0x66, 0xDE, 0xFC,
+	0xED, 0x51, 0xC2, 0x4D,
+};
+
+static const uint8_t keygen_dsa960_p[] = {
+	0xCA, 0x86, 0x31, 0x0C, 0x62, 0xC7, 0x25, 0x2F, 0xAA, 0x8D, 0xA5, 0x51,
+	0x97, 0x81, 0xB8, 0xC5, 0xFD, 0xDB, 0x47, 0xC4, 0x8E, 0xDF, 0x06, 0xAA,
+	0x76, 0xAD, 0x47, 0xDD, 0x56, 0x6C, 0x97, 0xEB, 0x8C, 0xEC, 0x59, 0x79,
+	0x1B, 0xBF, 0x96, 0x80, 0x50, 0x72, 0x8E, 0x2F, 0x34, 0x71, 0x5B, 0x03,
+	0x2D, 0xB0, 0x31, 0x37, 0x8C, 0xC4, 0x62, 0x99, 0x9D, 0xC2, 0xDF, 0x68,
+	0x35, 0xD5, 0x3F, 0xC1, 0x4B, 0xC4, 0x2F, 0xFA, 0xBD, 0x7E, 0xA5, 0x20,
+	0x8F, 0xB9, 0x5F, 0x98, 0xA9, 0x1B, 0xAF, 0x8A, 0xF8, 0x29, 0xEB, 0x44,
+	0xB6, 0x50, 0x96, 0xE2, 0xB4, 0x3D, 0x3C, 0xE6, 0x8B, 0xD5, 0x15, 0x39,
+	0x4F, 0xF4, 0xC3, 0x32, 0xD3, 0xE6, 0x36, 0x0D, 0x23, 0xFF, 0x76, 0x15,
+	0x05, 0xC1, 0xDF, 0xC2, 0x82, 0xCE, 0xDD, 0x60, 0x05, 0x92, 0x56, 0xE5,
+};
+
+static const uint8_t keygen_dsa960_q[] = {
+	0xCE, 0x0A, 0x68, 0xA4, 0xAC, 0x5E, 0x8E, 0x4C, 0xA6, 0x8A, 0xAB, 0xA9,
+	0x39, 0xC7, 0xB4, 0x10, 0xCC, 0xF6, 0x1E, 0x2F,
+};
+
+static const uint8_t keygen_dsa960_g[] = {
+	0x8A, 0x50, 0x28, 0x45, 0x69, 0x0E, 0x55, 0xB8, 0x86, 0xB5, 0xCB, 0xBC,
+	0x49, 0x8D, 0x73, 0x79, 0xE3, 0x26, 0x4E, 0x90, 0x71, 0xF2, 0xBB, 0x50,
+	0x18, 0xF8, 0x6D, 0x14, 0x8F, 0xCA, 0x20, 0xF7, 0x02, 0x31, 0x71, 0x8A,
+	0x7E, 0xF0, 0xFE, 0x9C, 0xAD, 0x05, 0x5E, 0x11, 0xB3, 0x40, 0x66, 0xE1,
+	0x2B, 0x0D, 0x84, 0x15, 0x18, 0x65, 0x00, 0xFA, 0x0D, 0x8A, 0x87, 0xC9,
+	0xBF, 0x4A, 0x5C, 0x53, 0x29, 0xEB, 0x44, 0xCA, 0xAE, 0x86, 0x50, 0x3B,
+	0xBB, 0x73, 0x06, 0x83, 0x72, 0x77, 0x17, 0xDB, 0x6E, 0x14, 0xAD, 0xCE,
+	0xD2, 0x51, 0xE6, 0x1F, 0xA2, 0x64, 0xE4, 0x5F, 0x35, 0x7D, 0x7A, 0xBE,
+	0x55, 0x9B, 0xB6, 0x0F, 0x3C, 0xA1, 0xD2, 0x45, 0xDD, 0xF8, 0xC4, 0x03,
+	0x45, 0xAA, 0x12, 0xE4, 0x90, 0x8C, 0xAC, 0x04, 0x45, 0x74, 0x11, 0x28,
+};
+
+static const uint8_t keygen_dsa1024_p[] = {
+	0xAF, 0xA6, 0x9C, 0x37, 0x47, 0xD4, 0x65, 0xA6, 0xB1, 0x8D, 0xAC, 0x2E,
+	0xAB, 0xD5, 0x36, 0xCC, 0x83, 0x47, 0xDD, 0xB6, 0x12, 0xCC, 0x93, 0xA5,
+	0xBF, 0x7B, 0x24, 0xE7, 0x4A, 0xED, 0xEC, 0x63, 0x9E, 0x0B, 0x2D, 0xF8,
+	0xB3, 0x6B, 0xBB, 0xF9, 0x40, 0x8D, 0x56, 0x26, 0x60, 0xD0, 0xDD, 0x03,
+	0xF8, 0xC3, 0x82, 0x00, 0x2C, 0x27, 0x82, 0x5E, 0x30, 0x8B, 0x9D, 0xF1,
+	0xF7, 0xB2, 0x61, 0x01, 0x31, 0x30, 0xF3, 0x05, 0x2F, 0xF4, 0xB7, 0x1C,
+	0x1C, 0x3C, 0xB0, 0x2D, 0x2F, 0x1F, 0xE6, 0x2E, 0x21, 0x81, 0x0D, 0xFD,
+	0x66, 0x36, 0x90, 0x39, 0x4D, 0xA0, 0xCF, 0xFA, 0xDD, 0xF7, 0xD5, 0xE4,
+	0x09, 0xAA, 0x45, 0xDB, 0xE1, 0x55, 0x39, 0xD9, 0xF7, 0xDF, 0x34, 0x67,
+	0xBF, 0x95, 0x9B, 0xF2, 0x4A, 0x15, 0x42, 0x6F, 0x32, 0x1F, 0xDE, 0xA6,
+	0xFE, 0x18, 0x46, 0x6B, 0x8C, 0x4E, 0x01, 0x7F,
+};
+
+static const uint8_t keygen_dsa1024_q[] = {
+	0xCC, 0x18, 0x69, 0xCE, 0x9E, 0x92, 0xE7, 0xCD, 0xBF, 0x94, 0xB5, 0xAD,
+	0x83, 0x5A, 0x56, 0xD6, 0x4E, 0xC4, 0xF7, 0xED,
+};
+
+static const uint8_t keygen_dsa1024_g[] = {
+	0x14, 0x1D, 0x91, 0xAB, 0x8F, 0xFF, 0xFB, 0x2D, 0xD3, 0x2A, 0x43, 0xB5,
+	0x01, 0x40, 0xA4, 0xC7, 0x48, 0x0E, 0xE0, 0x10, 0xA9, 0xF7, 0x8B, 0x7E,
+	0x45, 0x90, 0xE0, 0x17, 0xC1, 0xB4, 0xE9, 0xBA, 0xC0, 0x04, 0xEF, 0x0F,
+	0xD6, 0x07, 0x78, 0x05, 0x25, 0xCF, 0x9D, 0x39, 0x66, 0x59, 0x53, 0xF8,
+	0xCE, 0x1C, 0x61, 0x1B, 0x7F, 0x95, 0x9B, 0xD5, 0xB6, 0xF9, 0xC7, 0xE3,
+	0xB8, 0x00, 0x78, 0x50, 0xE3, 0x4C, 0x76, 0xF8, 0x0E, 0x96, 0x11, 0xDB,
+	0x28, 0x53, 0xA5, 0xBB, 0x22, 0xC5, 0x71, 0x97, 0x09, 0xBC, 0xEE, 0x55,
+	0x9B, 0x6B, 0x22, 0x64, 0xE4, 0x49, 0x2C, 0xCD, 0x9E, 0xA5, 0x86, 0xF0,
+	0x3F, 0x08, 0xCD, 0x88, 0x07, 0xF6, 0x6E, 0x3F, 0x8E, 0x99, 0x31, 0xBA,
+	0x1A, 0xB9, 0x8E, 0xEC, 0xA3, 0x13, 0xC2, 0x85, 0xA5, 0xDC, 0xA4, 0xF0,
+	0x1F, 0xB2, 0xC8, 0xD5, 0x19, 0x79, 0xCA, 0x6A,
+};
+
+static const uint8_t keygen_dsa2048_p[] = {
+	0xea, 0x1f, 0xb1, 0xaf, 0x22, 0x88, 0x15, 0x58, 0xef, 0x93, 0xbe, 0x8a,
+	0x5f, 0x86, 0x53, 0xc5, 0xa5, 0x59, 0x43, 0x4c, 0x49, 0xc8, 0xc2, 0xc1,
+	0x2a, 0xce, 0x5e, 0x9c, 0x41, 0x43, 0x4c, 0x9c, 0xf0, 0xa8, 0xe9, 0x49,
+	0x8a, 0xcb, 0x0f, 0x46, 0x63, 0xc0, 0x8b, 0x44, 0x84, 0xea, 0xce, 0x84,
+	0x5f, 0x6f, 0xb1, 0x7d, 0xac, 0x62, 0xc9, 0x8e, 0x70, 0x6a, 0xf0, 0xfc,
+	0x74, 0xe4, 0xda, 0x1c, 0x6c, 0x2b, 0x3f, 0xbf, 0x5a, 0x1d, 0x58, 0xff,
+	0x82, 0xfc, 0x1a, 0x66, 0xf3, 0xe8, 0xb1, 0x22, 0x52, 0xc4, 0x02, 0x78,
+	0xff, 0xf9, 0xdd, 0x7f, 0x10, 0x2e, 0xed, 0x2c, 0xb5, 0xb7, 0x32, 0x3e,
+	0xbf, 0x19, 0x08, 0xc2, 0x34, 0xd9, 0x35, 0x41, 0x4d, 0xde, 0xd7, 0xf8,
+	0xd2, 0x44, 0xe5, 0x45, 0x61, 0xb0, 0xdc, 0xa3, 0x9b, 0x30, 0x1d, 0xe8,
+	0xc4, 0x9d, 0xa9, 0xfb, 0x23, 0xdf, 0x33, 0xc6, 0x18, 0x2e, 0x3f, 0x98,
+	0x32, 0x08, 0xc5, 0x60, 0xfb, 0x51, 0x19, 0xfb, 0xf7, 0x8e, 0xbe, 0x3e,
+	0x65, 0x64, 0xee, 0x23, 0x5c, 0x6a, 0x15, 0xcb, 0xb9, 0xac, 0x24, 0x7b,
+	0xab, 0xa5, 0xa4, 0x23, 0xbc, 0x65, 0x82, 0xa1, 0xa9, 0xd8, 0xa2, 0xb4,
+	0xf0, 0xe9, 0xe3, 0xd9, 0xdb, 0xac, 0x12, 0x2f, 0x75, 0x0d, 0xd7, 0x54,
+	0x32, 0x51, 0x35, 0x25, 0x74, 0x88, 0xb1, 0xf6, 0xec, 0xab, 0xf2, 0x1b,
+	0xff, 0x29, 0x47, 0xfe, 0x0d, 0x3b, 0x2c, 0xb7, 0xff, 0xe6, 0x7f, 0x4e,
+	0x7f, 0xcd, 0xf1, 0x21, 0x4f, 0x60, 0x53, 0xe7, 0x2a, 0x5b, 0xb0, 0xdd,
+	0x20, 0xa0, 0xe9, 0xfe, 0x6d, 0xb2, 0xdf, 0x0a, 0x90, 0x8c, 0x36, 0xe9,
+	0x5e, 0x60, 0xbf, 0x49, 0xca, 0x43, 0x68, 0xb8, 0xb8, 0x92, 0xb9, 0xc7,
+	0x9f, 0x61, 0xef, 0x91, 0xc4, 0x75, 0x67, 0xc4, 0x0e, 0x1f, 0x80, 0xac,
+	0x5a, 0xa6, 0x6e, 0xf7,
+};
+
+static const uint8_t keygen_dsa2048_q[] = {
+	0x8e, 0xc7, 0x3f, 0x37, 0x61, 0xca, 0xf5, 0xfd, 0xfe, 0x6e, 0x4e, 0x82,
+	0x09, 0x8b, 0xf1, 0x0f, 0x89, 0x87, 0x40, 0xdc, 0xb8, 0x08, 0x20, 0x4b,
+	0xf6, 0xb1, 0x8f, 0x50, 0x71, 0x92, 0xc1, 0x9d,
+};
+
+static const uint8_t keygen_dsa2048_g[] = {
+	0xe4, 0xc4, 0xec, 0xa8, 0x84, 0x15, 0xb2, 0x3e, 0xcf, 0x81, 0x1c, 0x96,
+	0xe4, 0x8c, 0xd2, 0x42, 0x00, 0xfe, 0x91, 0x66, 0x31, 0xa6, 0x8a, 0x68,
+	0x4e, 0x6c, 0xcb, 0x6b, 0x19, 0x13, 0x41, 0x3d, 0x34, 0x4d, 0x1d, 0x8d,
+	0x84, 0xa3, 0x33, 0x83, 0x9d, 0x88, 0xee, 0xe4, 0x31, 0x52, 0x1f, 0x6e,
+	0x35, 0x7c, 0x16, 0xe6, 0xa9, 0x3b, 0xe1, 0x11, 0xa9, 0x80, 0x76, 0x73,
+	0x9c, 0xd4, 0x01, 0xba, 0xb3, 0xb9, 0xd5, 0x65, 0xbf, 0x4f, 0xb9, 0x9e,
+	0x9d, 0x18, 0x5b, 0x1e, 0x14, 0xd6, 0x1c, 0x93, 0x70, 0x01, 0x33, 0xf9,
+	0x08, 0xba, 0xe0, 0x3e, 0x28, 0x76, 0x4d, 0x10, 0x7d, 0xcd, 0x2e, 0xa7,
+	0x67, 0x42, 0x17, 0x62, 0x20, 0x74, 0xbb, 0x19, 0xef, 0xff, 0x48, 0x2f,
+	0x5f, 0x5c, 0x1a, 0x86, 0xd5, 0x55, 0x1b, 0x2f, 0xc6, 0x8d, 0x1c, 0x6e,
+	0x9d, 0x80, 0x11, 0x95, 0x8e, 0xf4, 0xb9, 0xc2, 0xa3, 0xa5, 0x5d, 0x0d,
+	0x3c, 0x88, 0x2e, 0x6a, 0xd7, 0xf9, 0xf0, 0xf3, 0xc6, 0x15, 0x68, 0xf7,
+	0x8d, 0x07, 0x06, 0xb1, 0x0a, 0x26, 0xf2, 0x3b, 0x4f, 0x19, 0x7c, 0x32,
+	0x2b, 0x82, 0x50, 0x02, 0x28, 0x4a, 0x0a, 0xca, 0x91, 0x80, 0x7b, 0xba,
+	0x98, 0xec, 0xe9, 0x12, 0xb8, 0x0e, 0x10, 0xcd, 0xf1, 0x80, 0xcf, 0x99,
+	0xa3, 0x5f, 0x21, 0x0c, 0x16, 0x55, 0xfb, 0xfd, 0xd7, 0x4f, 0x13, 0xb1,
+	0xb5, 0x04, 0x65, 0x91, 0xf8, 0x40, 0x38, 0x73, 0xd1, 0x22, 0x39, 0x83,
+	0x4d, 0xd6, 0xc4, 0xec, 0xeb, 0x42, 0xbf, 0x74, 0x82, 0xe1, 0x79, 0x4a,
+	0x16, 0x01, 0x35, 0x7b, 0x62, 0x9d, 0xdf, 0xa9, 0x71, 0xf2, 0xed, 0x27,
+	0x3b, 0x14, 0x6e, 0xc1, 0xca, 0x06, 0xd0, 0xad, 0xf5, 0x5d, 0xd9, 0x1d,
+	0x65, 0xc3, 0x72, 0x97, 0xbd, 0xa7, 0x8c, 0x6d, 0x21, 0x0c, 0x0b, 0xc2,
+	0x6e, 0x55, 0x83, 0x02,
+};
+
+static const uint8_t keygen_dsa3072_p[] = {
+	0xf3, 0x35, 0x66, 0x6d, 0xd1, 0x33, 0x91, 0x65, 0xaf, 0x8b, 0x9a, 0x5e,
+	0x38, 0x35, 0xad, 0xfe, 0x15, 0xc1, 0x58, 0xe4, 0xc3, 0xc7, 0xbd, 0x53,
+	0x13, 0x2e, 0x7d, 0x58, 0x28, 0xc3, 0x52, 0xf5, 0x93, 0xa9, 0xa7, 0x87,
+	0x76, 0x0c, 0xe3, 0x4b, 0x78, 0x98, 0x79, 0x94, 0x1f, 0x2f, 0x01, 0xf0,
+	0x23, 0x19, 0xf6, 0xae, 0x0b, 0x75, 0x6f, 0x1a, 0x84, 0x2b, 0xa5, 0x4c,
+	0x85, 0x61, 0x2e, 0xd6, 0x32, 0xee, 0x2d, 0x79, 0xef, 0x17, 0xf0, 0x6b,
+	0x77, 0xc6, 0x41, 0xb7, 0xb0, 0x80, 0xaf, 0xf5, 0x2a, 0x03, 0xfc, 0x24,
+	0x62, 0xe8, 0x0a, 0xbc, 0x64, 0xd2, 0x23, 0x72, 0x3c, 0x23, 0x6d, 0xee,
+	0xb7, 0xd2, 0x01, 0x07, 0x8e, 0xc0, 0x1c, 0xa1, 0xfb, 0xc1, 0x76, 0x31,
+	0x39, 0xe2, 0x50, 0x99, 0xa8, 0x4e, 0xc3, 0x89, 0x15, 0x9c, 0x40, 0x97,
+	0x92, 0x08, 0x07, 0x36, 0xbd, 0x7c, 0xaa, 0x81, 0x6b, 0x92, 0xed, 0xf2,
+	0x3f, 0x2c, 0x35, 0x1f, 0x90, 0x07, 0x4a, 0xa5, 0xea, 0x26, 0x51, 0xb3,
+	0x72, 0xf8, 0xb5, 0x8a, 0x0a, 0x65, 0x55, 0x4d, 0xb2, 0x56, 0x1d, 0x70,
+	0x6a, 0x63, 0x68, 0x50, 0x00, 0xac, 0x57, 0x6b, 0x7e, 0x45, 0x62, 0xe2,
+	0x62, 0xa1, 0x42, 0x85, 0xa9, 0xc6, 0x37, 0x0b, 0x29, 0x0e, 0x4e, 0xb7,
+	0x75, 0x75, 0x27, 0xd8, 0x0b, 0x6c, 0x0f, 0xd5, 0xdf, 0x83, 0x1d, 0x36,
+	0xf3, 0xd1, 0xd3, 0x5f, 0x12, 0xab, 0x06, 0x05, 0x48, 0xde, 0x16, 0x05,
+	0xfd, 0x15, 0xf7, 0xc7, 0xaa, 0xfe, 0xd6, 0x88, 0xb1, 0x46, 0xa0, 0x2c,
+	0x94, 0x51, 0x56, 0xe2, 0x84, 0xf5, 0xb7, 0x12, 0x82, 0x04, 0x5a, 0xba,
+	0x98, 0x44, 0xd4, 0x8b, 0x5d, 0xf2, 0xe9, 0xe7, 0xa5, 0x88, 0x71, 0x21,
+	0xea, 0xe7, 0xd7, 0xb0, 0x1d, 0xb7, 0xcd, 0xf6, 0xff, 0x91, 0x7c, 0xd8,
+	0xeb, 0x50, 0xc6, 0xbf, 0x1d, 0x54, 0xf9, 0x0c, 0xce, 0x1a, 0x49, 0x1a,
+	0x9c, 0x74, 0xfe, 0xa8, 0x8f, 0x7e, 0x72, 0x30, 0xb0, 0x47, 0xd1, 0x6b,
+	0x5a, 0x60, 0x27, 0x88, 0x1d, 0x6f, 0x15, 0x48, 0x18, 0xf0, 0x6e, 0x51,
+	0x3f, 0xaf, 0x40, 0xc8, 0x81, 0x46, 0x30, 0xe4, 0xe2, 0x54, 0xf1, 0x7a,
+	0x47, 0xbf, 0xe9, 0xcb, 0x51, 0x9b, 0x98, 0x28, 0x99, 0x35, 0xbf, 0x17,
+	0x67, 0x3a, 0xe4, 0xc8, 0x03, 0x35, 0x04, 0xa2, 0x0a, 0x89, 0x8d, 0x00,
+	0x32, 0xee, 0x40, 0x2b, 0x72, 0xd5, 0x98, 0x63, 0x22, 0xf3, 0xbd, 0xfb,
+	0x27, 0x40, 0x05, 0x61, 0xf7, 0x47, 0x6c, 0xd7, 0x15, 0xea, 0xab, 0xb7,
+	0x33, 0x8b, 0x85, 0x4e, 0x51, 0xfc, 0x2f, 0xa0, 0x26, 0xa5, 0xa5, 0x79,
+	0xb6, 0xdc, 0xea, 0x1b, 0x1c, 0x05, 0x59, 0xc1, 0x3d, 0x3c, 0x11, 0x36,
+	0xf3, 0x03, 0xf4, 0xb4, 0xd2, 0x5a, 0xd5, 0xb6, 0x92, 0x22, 0x99, 0x57,
+};
+
+static const uint8_t keygen_dsa3072_q[] = {
+	0xd3, 0xeb, 0xa6, 0x52, 0x12, 0x40, 0x69, 0x40, 0x15, 0xef, 0x94, 0x41,
+	0x2e, 0x08, 0xbf, 0x3c, 0xf8, 0xd6, 0x35, 0xa4, 0x55, 0xa3, 0x98, 0xd6,
+	0xf2, 0x10, 0xf6, 0x16, 0x90, 0x41, 0x65, 0x3b,
+};
+
+static const uint8_t keygen_dsa3072_g[] = {
+	0xce, 0x84, 0xb3, 0x0d, 0xdf, 0x29, 0x0a, 0x9f, 0x78, 0x7a, 0x7c, 0x2f,
+	0x1c, 0xe9, 0x2c, 0x1c, 0xbf, 0x4e, 0xf4, 0x00, 0xe3, 0xcd, 0x7c, 0xe4,
+	0x97, 0x8d, 0xb2, 0x10, 0x4d, 0x73, 0x94, 0xb4, 0x93, 0xc1, 0x83, 0x32,
+	0xc6, 0x4c, 0xec, 0x90, 0x6a, 0x71, 0xc3, 0x77, 0x8b, 0xd9, 0x33, 0x41,
+	0x16, 0x5d, 0xee, 0x8e, 0x6c, 0xd4, 0xca, 0x6f, 0x13, 0xaf, 0xff, 0x53,
+	0x11, 0x91, 0x19, 0x4a, 0xda, 0x55, 0xec, 0xf0, 0x1f, 0xf9, 0x4d, 0x6c,
+	0xf7, 0xc4, 0x76, 0x8b, 0x82, 0xdd, 0x29, 0xcd, 0x13, 0x1a, 0xaf, 0x20,
+	0x2a, 0xef, 0xd4, 0x0e, 0x56, 0x43, 0x75, 0x28, 0x5c, 0x01, 0xf3, 0x22,
+	0x0a, 0xf4, 0xd7, 0x0b, 0x96, 0xf1, 0x39, 0x54, 0x20, 0xd7, 0x78, 0x22,
+	0x8f, 0x14, 0x61, 0xf5, 0xd0, 0xb8, 0xe4, 0x73, 0x57, 0xe8, 0x7b, 0x1f,
+	0xe3, 0x28, 0x62, 0x23, 0xb5, 0x53, 0xe3, 0xfc, 0x99, 0x28, 0xf1, 0x6a,
+	0xe3, 0x06, 0x7d, 0xed, 0x67, 0x21, 0xbe, 0xdf, 0x1d, 0x1a, 0x01, 0xbf,
+	0xd2, 0x2b, 0x9a, 0xe8, 0x5f, 0xce, 0x77, 0x82, 0x0d, 0x88, 0xcd, 0xf5,
+	0x0a, 0x6b, 0xde, 0x20, 0x66, 0x8a, 0xd7, 0x7a, 0x70, 0x7d, 0x1c, 0x60,
+	0xfc, 0xc5, 0xd5, 0x1c, 0x9d, 0xe4, 0x88, 0x61, 0x0d, 0x02, 0x85, 0xeb,
+	0x8f, 0xf7, 0x21, 0xff, 0x14, 0x1f, 0x93, 0xa9, 0xfb, 0x23, 0xc1, 0xd1,
+	0xf7, 0x65, 0x4c, 0x07, 0xc4, 0x6e, 0x58, 0x83, 0x6d, 0x16, 0x52, 0x82,
+	0x8f, 0x71, 0x05, 0x7b, 0x8a, 0xff, 0x0b, 0x07, 0x78, 0xef, 0x2c, 0xa9,
+	0x34, 0xea, 0x9d, 0x0f, 0x37, 0xda, 0xdd, 0xad, 0xe2, 0xd8, 0x23, 0xa4,
+	0xd8, 0xe3, 0x62, 0x72, 0x10, 0x82, 0xe2, 0x79, 0xd0, 0x03, 0xb5, 0x75,
+	0xee, 0x59, 0xfd, 0x05, 0x0d, 0x10, 0x5d, 0xfd, 0x71, 0xcd, 0x63, 0x15,
+	0x4e, 0xfe, 0x43, 0x1a, 0x08, 0x69, 0x17, 0x8d, 0x98, 0x11, 0xf4, 0xf2,
+	0x31, 0xdc, 0x5d, 0xcf, 0x3b, 0x0e, 0xc0, 0xf2, 0xb0, 0xf9, 0x89, 0x6c,
+	0x32, 0xec, 0x6c, 0x7e, 0xe7, 0xd6, 0x0a, 0xa9, 0x71, 0x09, 0xe0, 0x92,
+	0x24, 0x90, 0x73, 0x28, 0xd4, 0xe6, 0xac, 0xd1, 0x01, 0x17, 0xe4, 0x57,
+	0x74, 0x40, 0x6c, 0x4c, 0x94, 0x7d, 0xa8, 0x02, 0x06, 0x49, 0xc3, 0x16,
+	0x8f, 0x69, 0x0e, 0x0b, 0xd6, 0xe9, 0x1a, 0xc6, 0x70, 0x74, 0xd1, 0xd4,
+	0x36, 0xb5, 0x8a, 0xe3, 0x74, 0x52, 0x3d, 0xea, 0xf6, 0xc9, 0x3c, 0x1e,
+	0x69, 0x20, 0xdb, 0x4a, 0x08, 0x0b, 0x74, 0x48, 0x04, 0xbb, 0x07, 0x3c,
+	0xec, 0xfe, 0x83, 0xfa, 0x93, 0x98, 0xcf, 0x15, 0x0a, 0xfa, 0x28, 0x6d,
+	0xc7, 0xeb, 0x79, 0x49, 0x75, 0x0c, 0xf5, 0x00, 0x1c, 0xe1, 0x04, 0xe9,
+	0x18, 0x7f, 0x7e, 0x16, 0x85, 0x9a, 0xfa, 0x8f, 0xd0, 0xd7, 0x75, 0xae,
+};
+
+#define CPERF_DSA_TEST_DATA(size, vect) \
+	{ \
+		size, vect##_p, ARRAY_SIZE(vect##_p), vect##_g, \
+			ARRAY_SIZE(vect##_g), vect##_q, ARRAY_SIZE(vect##_q) \
+	}
+
+static const struct dsa_key_type {
+	uint32_t key_size_bits;
+	const uint8_t *prime;
+	size_t prime_len;
+	const uint8_t *base;
+	size_t base_len;
+	const uint8_t *sub_prime;
+	size_t sub_prime_len;
+} dsa_key_types[] = {
+	CPERF_DSA_TEST_DATA(512, keygen_dsa512),
+	CPERF_DSA_TEST_DATA(576, keygen_dsa576),
+	CPERF_DSA_TEST_DATA(640, keygen_dsa640),
+	CPERF_DSA_TEST_DATA(704, keygen_dsa704),
+	CPERF_DSA_TEST_DATA(768, keygen_dsa768),
+	CPERF_DSA_TEST_DATA(832, keygen_dsa832),
+	CPERF_DSA_TEST_DATA(896, keygen_dsa896),
+	CPERF_DSA_TEST_DATA(960, keygen_dsa960),
+	CPERF_DSA_TEST_DATA(1024, keygen_dsa1024),
+	CPERF_DSA_TEST_DATA(2048, keygen_dsa2048),
+	CPERF_DSA_TEST_DATA(3072, keygen_dsa3072),
+};
+
+#endif
diff --git a/ta/crypto_perf/include/user_ta_header_defines.h b/ta/crypto_perf/include/user_ta_header_defines.h
new file mode 100644
index 0000000..8a30eb5
--- /dev/null
+++ b/ta/crypto_perf/include/user_ta_header_defines.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2018 NXP
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+#include <ta_crypto_perf.h>
+
+#define TA_UUID TA_CRYPTO_PERF_TEST_UUID
+
+#define TA_FLAGS		(TA_FLAG_USER_MODE | TA_FLAG_EXEC_DDR | \
+				TA_FLAG_SINGLE_INSTANCE)
+#define TA_STACK_SIZE		(4 * 1024)
+#define TA_DATA_SIZE		(64 * 1024)
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/ta/crypto_perf/sub.mk b/ta/crypto_perf/sub.mk
new file mode 100644
index 0000000..fa03d8c
--- /dev/null
+++ b/ta/crypto_perf/sub.mk
@@ -0,0 +1,11 @@
+global-incdirs-y += include
+srcs-y += ta_entry.c
+srcs-y += ta_alg_list.c
+srcs-y += ta_alg_cipher.c
+srcs-y += ta_alg_digest.c
+srcs-y += ta_alg_mac.c
+srcs-y += ta_alg_asymcipher.c
+srcs-y += ta_alg_asymdigest.c
+srcs-y += ta_alg_keyderive.c
+srcs-y += ta_alg_ae.c
+srcs-y += ta_keygen.c
diff --git a/ta/crypto_perf/ta_alg_ae.c b/ta/crypto_perf/ta_alg_ae.c
new file mode 100644
index 0000000..4f30241
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_ae.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+#define ENCRYPT_ALGO (1 << 0)
+#define DECRYPT_ALGO (1 << 1)
+
+static TEE_OperationHandle authenEnc_op;
+static TEE_OperationHandle authenDec_op;
+
+static uint8_t tag[64];
+static size_t  tag_len;
+static uint32_t gen_tag_len;
+static uint8_t nonce[15];
+static size_t  nonce_len;
+static uint8_t aad[16];
+static size_t  aad_len;
+
+static void TA_FreeOp(uint8_t which)
+{
+	if ((which & ENCRYPT_ALGO) && (authenEnc_op)) {
+		TEE_FreeOperation(authenEnc_op);
+		authenEnc_op = NULL;
+	}
+	if ((which & DECRYPT_ALGO) && (authenDec_op)) {
+		TEE_FreeOperation(authenDec_op);
+		authenDec_op = NULL;
+	}
+}
+
+TEE_Result TA_AuthenEncPrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/* Cipher Preparation: Don't need to check again input params */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectType	 objType;
+
+	uint8_t L;
+
+	size_t  payload_len = 0;
+	uint32_t keysize;
+	uint32_t op_keysize;
+
+	keysize = params[1].value.a;
+	payload_len = params[1].value.b;
+
+	/*
+	 * Just in case there was an issue and Operation Handles
+	 * was no freed
+	 */
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, false);
+	switch (objType) {
+	case TEE_TYPE_AES:
+		if ((keysize != 128) && (keysize != 192) && (keysize != 256))
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	op_keysize = keysize;
+
+	/* Calculate the value of L */
+	for (L = 2; L < 9; L++) {
+		if (payload_len < (size_t)(1 << (L * 3)))
+			break;
+	}
+
+	if (L > 8)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	switch (TEE_ALG_GET_CHAIN_MODE(algo)) {
+	case TEE_CHAIN_MODE_CCM:
+		/* Nonce Size is 15-L where 1 < L < 9 */
+		nonce_len = (15 - L);
+		TEE_GenerateRandom(nonce, nonce_len);
+		tag_len = 32;
+		gen_tag_len = 32;
+		aad_len = 2;
+		TEE_GenerateRandom(aad, aad_len);
+		break;
+
+	case TEE_CHAIN_MODE_GCM:
+		/* Nonce Size is 15-L where 1 < L < 9 */
+		nonce_len = (15 - L);
+		TEE_GenerateRandom(nonce, nonce_len);
+		tag_len = 96;
+		gen_tag_len = 96;
+		aad_len = 0;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	/* Prepare Keys and Operation handles */
+	res = TEE_AllocateOperation(&authenEnc_op, algo,
+		TEE_MODE_ENCRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Encrypt Authentication",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateOperation(&authenDec_op, algo,
+		TEE_MODE_DECRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Decrypt Authentication",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject Authentication",
+		goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, keysize, NULL, 0);
+	CHECK(res, "TEE_GenerateKey Authentication", goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(authenEnc_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Encrypt Authentication",
+		goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(authenDec_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Decrypt Authentication",
+		goto PrepareExit_Error;);
+
+	TEE_FreeTransientObject(hKey);
+
+
+	/*
+	 * Set params[2].value.b = 1 to inform that decryption is supported.
+	 */
+	params[2].value.b = 1;
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	if (hKey)
+		TEE_FreeTransientObject(hKey);
+
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	return res;
+}
+
+TEE_Result TA_AuthenEncProcessAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Cipher Process: Don't need to check again input params */
+	TEE_Result res;
+	uint8_t *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+	uint32_t nb_loop;
+	size_t   payload_len;
+
+	in          = params[0].memref.buffer;
+	payload_len = params[0].memref.size;
+	out         = params[1].memref.buffer;
+
+	/* Block size are 128 bits - 64 bytes */
+	nb_loop = payload_len / 64;
+
+	if (nb_loop == 0) {
+		inSize  = payload_len;
+		outSize = payload_len;
+		nb_loop = 1;
+	} else {
+		inSize  = 64;
+		outSize = 64;
+	}
+
+	if (params[2].value.b == 0) {
+		res = TEE_AEInit(authenEnc_op, nonce, nonce_len,
+			tag_len, aad_len, payload_len);
+		CHECK(res, "TEE_AEInit Encrypt Authentication", return res;);
+
+		if (aad_len)
+			TEE_AEUpdateAAD(authenEnc_op, aad, aad_len);
+	} else {
+		res = TEE_AEInit(authenDec_op, nonce, nonce_len,
+			tag_len, aad_len, payload_len);
+		CHECK(res, "TEE_AEInit Decrypt Authentication", return res;);
+
+		if (aad_len)
+			TEE_AEUpdateAAD(authenDec_op, aad, aad_len);
+	}
+
+	for (nb_loop -= 1; nb_loop > 0; nb_loop--) {
+		if (params[2].value.b == 0) {
+			res = TEE_AEUpdate(authenEnc_op, in, inSize,
+				out, &outSize);
+			CHECK(res, "TEE_AEUpdate Encrypt", return res;);
+		} else {
+			res = TEE_AEUpdate(authenDec_op, in, inSize,
+				out, &outSize);
+			CHECK(res, "TEE_AEUpdate Decrypt", return res;);
+		}
+		in  += 64;
+		out += 64;
+	}
+
+	if (params[2].value.b == 0) {
+		res = TEE_AEEncryptFinal(authenEnc_op, in, inSize,
+			out, &outSize, tag, &gen_tag_len);
+		CHECK(res, "TEE_EAEncryptFinal Encrypt", return res;);
+	} else {
+		res = TEE_AEDecryptFinal(authenDec_op, in, inSize,
+			out, &outSize, tag, gen_tag_len);
+		CHECK(res, "TEE_EADecryptFinal Decrypt", return res;);
+	}
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_AuthenEncFreeAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	if (params[2].value.b == 0)
+		TA_FreeOp(ENCRYPT_ALGO);
+	else
+		TA_FreeOp(DECRYPT_ALGO);
+
+	return TEE_SUCCESS;
+}
+
diff --git a/ta/crypto_perf/ta_alg_asymcipher.c b/ta/crypto_perf/ta_alg_asymcipher.c
new file mode 100644
index 0000000..b78aae4
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_asymcipher.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+#define ENCRYPT_ALGO (1 << 0)
+#define DECRYPT_ALGO (1 << 1)
+
+static TEE_OperationHandle asymcipherEnc_op;
+static TEE_OperationHandle asymcipherDec_op;
+
+static void TA_FreeOp(uint8_t which)
+{
+	if ((which & ENCRYPT_ALGO) && (asymcipherEnc_op)) {
+		TEE_FreeOperation(asymcipherEnc_op);
+		asymcipherEnc_op = NULL;
+	}
+	if ((which & DECRYPT_ALGO) && (asymcipherDec_op)) {
+		TEE_FreeOperation(asymcipherDec_op);
+		asymcipherDec_op = NULL;
+	}
+}
+
+TEE_Result TA_AsymCipherPrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/*
+	 * Asymmetric Cipher Preparation:
+	 * Don't need to check again input params
+	 */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectType	 objType;
+
+	uint32_t keysize;
+	uint32_t op_keysize;
+
+	keysize = params[1].value.a;
+
+	/*
+	 * Just in case there was an issue and Operation Handles
+	 * was no freed
+	 */
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, true);
+	switch (objType) {
+	case TEE_TYPE_RSA_KEYPAIR:
+		if ((keysize != 256) && (keysize != 512) &&
+		    (keysize != 768) && (keysize != 1024) &&
+			(keysize != 1536) && (keysize != 2048))
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	op_keysize = keysize;
+
+	/* Prepare Keys and Operation handles */
+	res = TEE_AllocateOperation(&asymcipherEnc_op, algo,
+		TEE_MODE_ENCRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Encrypt AsymCipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateOperation(&asymcipherDec_op, algo,
+		TEE_MODE_DECRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Decrypt AsymCipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject AsymCipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, keysize, NULL, 0);
+	CHECK(res, "TEE_GenerateKey AsymCipher", goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(asymcipherEnc_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Encrypt AsymCipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(asymcipherDec_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Decrypt AsymCipher",
+		goto PrepareExit_Error;);
+
+	TEE_FreeTransientObject(hKey);
+
+	/*
+	 * Set params[2].value.b = 1 to inform that decryption is supported.
+	 */
+	params[2].value.b = 1;
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	if (hKey)
+		TEE_FreeTransientObject(hKey);
+
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	return res;
+}
+
+TEE_Result TA_AsymCipherProcessAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Asymmetric Cipher Process: Don't need to check again input params */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	in      = params[0].memref.buffer;
+	inSize  = params[0].memref.size;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	if (params[2].value.b == 0) {
+		res = TEE_AsymmetricEncrypt(asymcipherEnc_op, NULL, 0,
+			in, inSize, out, &outSize);
+		CHECK(res, "TEE_AsymmetricEncrypt AsymCipher", return res;);
+	} else {
+		res = TEE_AsymmetricDecrypt(asymcipherDec_op, NULL, 0,
+			in, inSize, out, &outSize);
+		CHECK(res, "TEE_AsymmetricDecrypt AsymCipher", return res;);
+	}
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_AsymCipherFreeAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Asymmetric Cipher Free: Don't need to check again input params */
+	if (params[2].value.b == 0)
+		TA_FreeOp(ENCRYPT_ALGO);
+	else
+		TA_FreeOp(DECRYPT_ALGO);
+
+	return TEE_SUCCESS;
+}
+
diff --git a/ta/crypto_perf/ta_alg_asymdigest.c b/ta/crypto_perf/ta_alg_asymdigest.c
new file mode 100644
index 0000000..7fdb040
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_asymdigest.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018, 2021-2022 NXP
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ta_crypto_perf.h>
+#include <tee_ta_api.h>
+#include <test_vectors_dsa.h>
+#include <trace.h>
+#include <user_ta_header_defines.h>
+
+#define SIGN_ALGO	(1 << 0)
+#define VERIFY_ALGO	(1 << 1)
+
+static TEE_OperationHandle asymdigestSign_op;
+static TEE_OperationHandle asymdigestVerif_op;
+static uint8_t *prime;
+static size_t prime_len;
+static uint8_t *subprime;
+static size_t subprime_len;
+static uint8_t *base;
+static size_t base_len;
+
+static void TA_FreeOp(uint8_t which)
+{
+	if ((which & SIGN_ALGO) && (asymdigestSign_op)) {
+		TEE_FreeOperation(asymdigestSign_op);
+		asymdigestSign_op = NULL;
+	}
+	if ((which & VERIFY_ALGO) && (asymdigestVerif_op)) {
+		TEE_FreeOperation(asymdigestVerif_op);
+		asymdigestVerif_op = NULL;
+	}
+
+	if (base)
+		TEE_Free(base);
+	if (subprime)
+		TEE_Free(subprime);
+	if (prime)
+		TEE_Free(prime);
+
+	base     = NULL;
+	subprime = NULL;
+	prime    = NULL;
+}
+
+TEE_Result TA_AsymDigestPrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/*
+	 * Asymmetric Digest Preparation:
+	 * Don't need to check again input params
+	 */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectType	 objType;
+	TEE_Attribute    attrs[5];
+	uint8_t          nb_attrs = 0;
+
+	uint32_t keysize;
+	uint32_t op_keysize;
+	uint8_t n = 0;
+
+	keysize = params[1].value.a;
+
+	/*
+	 * Just in case there was an issue and Operation Handles
+	 * was no freed
+	 */
+	TA_FreeOp(SIGN_ALGO | VERIFY_ALGO);
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, true);
+
+	op_keysize = keysize;
+
+	switch (objType) {
+	case TEE_TYPE_RSA_KEYPAIR:
+		if ((keysize < 256) || (keysize > 4096))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 64)
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		break;
+
+	case TEE_TYPE_DSA_KEYPAIR:
+		if ((keysize < 512) || (keysize > 3072))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 64)
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		for (n = 0; n < ARRAY_SIZE(dsa_key_types); n++) {
+			if (dsa_key_types[n].key_size_bits != keysize)
+				continue;
+
+			prime_len = dsa_key_types[n].prime_len;
+			subprime_len = dsa_key_types[n].sub_prime_len;
+			base_len = dsa_key_types[n].base_len;
+
+			prime = TEE_Malloc(dsa_key_types[n].prime_len, 0);
+			subprime = TEE_Malloc(dsa_key_types[n].sub_prime_len,
+					      0);
+			base = TEE_Malloc(dsa_key_types[n].base_len, 0);
+
+			if ((!prime) || (!subprime) || (!base)) {
+				res = TEE_ERROR_OUT_OF_MEMORY;
+				goto PrepareExit_Error;
+			}
+
+			memcpy(prime, dsa_key_types[n].prime,
+			       dsa_key_types[n].prime_len);
+			memcpy(subprime, dsa_key_types[n].sub_prime,
+			       dsa_key_types[n].sub_prime_len);
+			memcpy(base, dsa_key_types[n].base,
+			       dsa_key_types[n].base_len);
+			break;
+		}
+
+		attrs[0].attributeID = TEE_ATTR_DSA_PRIME;
+		attrs[0].content.ref.buffer = (void *)prime;
+		attrs[0].content.ref.length = prime_len;
+
+		attrs[1].attributeID = TEE_ATTR_DSA_SUBPRIME;
+		attrs[1].content.ref.buffer = (void *)subprime;
+		attrs[1].content.ref.length = subprime_len;
+
+		attrs[2].attributeID = TEE_ATTR_DSA_BASE;
+		attrs[2].content.ref.buffer = (void *)base;
+		attrs[2].content.ref.length = base_len;
+
+		nb_attrs = 3;
+
+		break;
+
+	case TEE_TYPE_ECDSA_KEYPAIR:
+		if ((keysize < 192) || (keysize > 521))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		attrs[0].attributeID = TEE_ATTR_ECC_CURVE;
+		attrs[0].content.value.b = sizeof(int);
+
+		switch (algo) {
+		case TEE_ALG_ECDSA_P192:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P192;
+			break;
+
+		case TEE_ALG_ECDSA_P224:
+			attrs[0].content.value.a =  TEE_ECC_CURVE_NIST_P224;
+			break;
+
+		case TEE_ALG_ECDSA_P256:
+			attrs[0].content.value.a =  TEE_ECC_CURVE_NIST_P256;
+			break;
+
+		case TEE_ALG_ECDSA_P384:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P384;
+			break;
+
+		case TEE_ALG_ECDSA_P521:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P521;
+			keysize = 528;
+			break;
+
+		default:
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		nb_attrs = 1;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	/* Prepare Keys and Operation handles */
+	res = TEE_AllocateOperation(&asymdigestSign_op, algo,
+		TEE_MODE_SIGN, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Encrypt AsymDigest",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateOperation(&asymdigestVerif_op, algo,
+		TEE_MODE_VERIFY, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Decrypt AsymDigest",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, op_keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject AsymDigest",
+		goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, op_keysize, attrs, nb_attrs);
+	CHECK(res, "TEE_GenerateKey AsymDigest", goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(asymdigestSign_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Encrypt AsymDigest",
+		goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(asymdigestVerif_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Decrypt AsymDigest",
+		goto PrepareExit_Error;);
+
+	TEE_FreeTransientObject(hKey);
+
+	/*
+	 * Set params[2].value.b = 1 to inform that verify is supported.
+	 */
+	params[2].value.b = 1;
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	if (hKey)
+		TEE_FreeTransientObject(hKey);
+
+	TA_FreeOp(SIGN_ALGO | VERIFY_ALGO);
+
+	return res;
+}
+
+TEE_Result TA_AsymDigestProcessAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/*
+	 * Asymmetric Digest Process:
+	 * Don't need to check again input params
+	 */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+	TEE_Attribute attrs[1];
+	uint8_t       nb_attrs = 0;
+
+	in      = params[0].memref.buffer;
+	inSize  = params[0].memref.size;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	if (TEE_ALG_GET_CHAIN_MODE(algo) == TEE_CHAIN_MODE_PKCS1_PSS_MGF1) {
+		attrs[0].attributeID = TEE_ATTR_RSA_PSS_SALT_LENGTH;
+		attrs[0].content.value.a = 20;
+		nb_attrs = 1;
+	}
+
+	if (params[2].value.b == 0) {
+		res = TEE_AsymmetricSignDigest(asymdigestSign_op, attrs,
+			nb_attrs, in, inSize, out, &outSize);
+		/* Update the size of the output */
+		params[1].memref.size = outSize;
+		CHECK(res, "TEE_AsymmetricSignDigest AsymDigest",
+			return res;);
+	} else {
+		res = TEE_AsymmetricVerifyDigest(asymdigestVerif_op, attrs,
+			nb_attrs, in, inSize, out, outSize);
+		CHECK(res, "TEE_AsymmetricVerifyDigest AsymDigest",
+			return res;);
+	}
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_AsymDigestFreeAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Asymmetric Digest Free: Don't need to check again input params */
+	if (params[2].value.b == 0)
+		TA_FreeOp(SIGN_ALGO);
+	else
+		TA_FreeOp(VERIFY_ALGO);
+
+	return TEE_SUCCESS;
+}
+
diff --git a/ta/crypto_perf/ta_alg_cipher.c b/ta/crypto_perf/ta_alg_cipher.c
new file mode 100644
index 0000000..87be8f4
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_cipher.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+#define ENCRYPT_ALGO (1 << 0)
+#define DECRYPT_ALGO (1 << 1)
+
+static TEE_OperationHandle cipherEnc_op;
+static TEE_OperationHandle cipherDec_op;
+
+static void TA_FreeOp(uint8_t which)
+{
+	if ((which & ENCRYPT_ALGO) && (cipherEnc_op)) {
+		TEE_FreeOperation(cipherEnc_op);
+		cipherEnc_op = NULL;
+	}
+	if ((which & DECRYPT_ALGO) && (cipherDec_op)) {
+		TEE_FreeOperation(cipherDec_op);
+		cipherDec_op = NULL;
+	}
+}
+
+TEE_Result TA_CipherPrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/* Cipher Preparation: Don't need to check again input params */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectHandle hKey2 = NULL;
+	TEE_ObjectType	 objType;
+
+	uint32_t keysize;
+	uint32_t op_keysize;
+	uint8_t  *iv_key     = NULL;
+	size_t   iv_key_size = 0;
+
+	static uint8_t iv[16] = {0};
+
+	keysize = params[1].value.a;
+
+	/*
+	 * Just in case there was an issue and Operation Handles
+	 * was no freed
+	 */
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, false);
+	switch (objType) {
+	case TEE_TYPE_AES:
+		if ((keysize != 128) && (keysize != 192) && (keysize != 256))
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_DES:
+		if (keysize != 64)
+			return TEE_ERROR_BAD_PARAMETERS;
+		/* Don't count the parity key size */
+		keysize -= (keysize / 8);
+		break;
+
+	case TEE_TYPE_DES3:
+		if ((keysize != 128) && (keysize != 192))
+			return TEE_ERROR_BAD_PARAMETERS;
+		/* Don't count the parity key size */
+		keysize -= (keysize / 8);
+		break;
+
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	op_keysize = keysize;
+	switch (TEE_ALG_GET_CHAIN_MODE(algo)) {
+	case TEE_CHAIN_MODE_ECB_NOPAD:
+		break;
+
+	case TEE_CHAIN_MODE_CBC_NOPAD:
+	case TEE_CHAIN_MODE_CTR:
+	case TEE_CHAIN_MODE_CTS:
+		iv_key      = iv;
+
+		if ((objType == TEE_TYPE_DES) || (objType == TEE_TYPE_DES3))
+			iv_key_size = 8;
+		else
+			iv_key_size = sizeof(iv);
+		break;
+
+	case TEE_CHAIN_MODE_XTS:
+		iv_key      = iv;
+		iv_key_size = sizeof(iv);
+		op_keysize *= 2;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	/* Prepare Keys and Operation handles */
+	res = TEE_AllocateOperation(&cipherEnc_op, algo,
+		TEE_MODE_ENCRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Encrypt Cipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateOperation(&cipherDec_op, algo,
+		TEE_MODE_DECRYPT, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Encrypt Cipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject Cipher",
+		goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, keysize, NULL, 0);
+	CHECK(res, "TEE_GenerateKey Cipher", goto PrepareExit_Error;);
+
+	if (algo == TEE_ALG_AES_XTS) {
+		/* Allocate the second key */
+		res = TEE_AllocateTransientObject(objType, keysize, &hKey2);
+		CHECK(res, "TEE_AllocateTransientObject Cipher",
+			goto PrepareExit_Error;);
+
+		res = TEE_GenerateKey(hKey2, keysize, NULL, 0);
+		CHECK(res, "TEE_GenerateKey Cipher", goto PrepareExit_Error;);
+
+		res = TEE_SetOperationKey2(cipherEnc_op, hKey, hKey2);
+		CHECK(res, "TEE_SetOperationKey2 Encrypt Cipher",
+			goto PrepareExit_Error;);
+
+		res = TEE_SetOperationKey2(cipherDec_op, hKey, hKey2);
+		CHECK(res, "TEE_SetOperationKey2 Decrypt Cipher",
+			goto PrepareExit_Error;);
+
+		TEE_FreeTransientObject(hKey2);
+	} else {
+		res = TEE_SetOperationKey(cipherEnc_op, hKey);
+		CHECK(res, "TEE_SetOperationKey Encrypt Cipher",
+			goto PrepareExit_Error;);
+
+		res = TEE_SetOperationKey(cipherDec_op, hKey);
+		CHECK(res, "TEE_SetOperationKey Decrypt Cipher",
+			goto PrepareExit_Error;);
+	}
+
+	TEE_FreeTransientObject(hKey);
+
+	if (iv_key) {
+		/* Generate IV Key */
+		TEE_GenerateRandom(iv_key, iv_key_size);
+	}
+
+	TEE_CipherInit(cipherEnc_op, iv_key, iv_key_size);
+	TEE_CipherInit(cipherDec_op, iv_key, iv_key_size);
+
+	/*
+	 * Set params[2].value.b = 1 to inform that decryption is supported.
+	 */
+	params[2].value.b = 1;
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	if (hKey)
+		TEE_FreeTransientObject(hKey);
+	if (hKey2)
+		TEE_FreeTransientObject(hKey2);
+
+	TA_FreeOp(ENCRYPT_ALGO | DECRYPT_ALGO);
+
+	return res;
+}
+
+TEE_Result TA_CipherProcessAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Cipher Process: Don't need to check again input params */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	in      = params[0].memref.buffer;
+	inSize  = params[0].memref.size;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	if (params[2].value.b == 0) {
+		res = TEE_CipherUpdate(cipherEnc_op, in, inSize, out, &outSize);
+		CHECK(res, "TEE_CipherUpdate Encrypt Cipher", return res;);
+	} else {
+		res = TEE_CipherUpdate(cipherDec_op, in, inSize, out, &outSize);
+		CHECK(res, "TEE_CipherUpdate Decrypt Cipher", return res;);
+	}
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_CipherFreeAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/* Cipher Free: Don't need to check again input params */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	in      = params[0].memref.buffer;
+	inSize  = 0;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	if (TEE_ALG_GET_CHAIN_MODE(algo) == TEE_CHAIN_MODE_CTS)
+		inSize = TEE_AES_BLOCK_SIZE;
+
+	if (params[2].value.b == 0) {
+		res = TEE_CipherDoFinal(cipherEnc_op, in,
+			inSize, out, &outSize);
+		CHECK(res, "TEE_CipherDoFinal Encrypt Cipher", return res;);
+
+		TA_FreeOp(ENCRYPT_ALGO);
+	} else {
+		res = TEE_CipherDoFinal(cipherDec_op, in,
+			inSize, out, &outSize);
+		CHECK(res, "TEE_CipherDoFinal Decrypt Cipher", return res;);
+
+		TA_FreeOp(DECRYPT_ALGO);
+	}
+
+	return TEE_SUCCESS;
+}
+
diff --git a/ta/crypto_perf/ta_alg_digest.c b/ta/crypto_perf/ta_alg_digest.c
new file mode 100644
index 0000000..e55ed03
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_digest.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+static TEE_OperationHandle digest_op;
+
+static void TA_FreeOp(void)
+{
+	if (digest_op) {
+		TEE_FreeOperation(digest_op);
+		digest_op = NULL;
+	}
+}
+
+
+TEE_Result TA_DigestPrepareAlgo(uint32_t algo, TEE_Param params[4] __unused)
+{
+	/* Digest Preparation: Don't need to check again input params */
+	TEE_Result res;
+
+	/*
+	 * Just in case there was an issue and Operation Handle
+	 * was no freed
+	 */
+	TA_FreeOp();
+
+	res = TEE_AllocateOperation(&digest_op, algo, TEE_MODE_DIGEST, 0);
+	CHECK(res, "TEE_AllocateOperation Digest", goto PrepareExit_Error;);
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	TA_FreeOp();
+	return res;
+}
+
+TEE_Result TA_DigestProcessAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Digest Process: Don't need to check again input params */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	in      = params[0].memref.buffer;
+	inSize  = params[0].memref.size;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	res = TEE_DigestDoFinal(digest_op, in, inSize, out, &outSize);
+	CHECK(res, "TEE_DigestDoFinal Digest", return res;);
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_DigestFreeAlgo(uint32_t algo __unused,
+	TEE_Param params[4] __unused)
+{
+	/* Digest Free: Don't need to check again input params */
+	TA_FreeOp();
+	return TEE_SUCCESS;
+}
diff --git a/ta/crypto_perf/ta_alg_keyderive.c b/ta/crypto_perf/ta_alg_keyderive.c
new file mode 100644
index 0000000..474fbdc
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_keyderive.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018, 2021 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+static TEE_OperationHandle deriveKey_op;
+static uint8_t *prime;
+static uint8_t *base;
+static uint8_t *public_key;
+static uint8_t *public_x_2;
+static uint8_t *public_y_2;
+
+static TEE_ObjectHandle hKeyDerived;
+
+static void TA_FreeOp(void)
+{
+	if (deriveKey_op) {
+		TEE_FreeOperation(deriveKey_op);
+		deriveKey_op = NULL;
+	}
+
+	if (hKeyDerived) {
+		TEE_FreeTransientObject(hKeyDerived);
+		hKeyDerived = NULL;
+	}
+
+	if (prime)
+		TEE_Free(prime);
+	if (base)
+		TEE_Free(base);
+	if (public_key)
+		TEE_Free(public_key);
+	if (public_x_2)
+		TEE_Free(public_x_2);
+	if (public_y_2)
+		TEE_Free(public_y_2);
+
+	prime       = NULL;
+	base        = NULL;
+	public_key  = NULL;
+	public_x_2  = NULL;
+	public_y_2  = NULL;
+
+}
+
+TEE_Result TA_KeyDerivePrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/*
+	 * Asymmetric Cipher Preparation:
+	 * Don't need to check again input params
+	 */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectType	 objType;
+	TEE_Attribute    attrs[5];
+	uint8_t          nb_attrs = 0;
+
+	uint32_t keysize;
+	uint32_t op_keysize;
+
+	keysize = params[1].value.a;
+
+	/*
+	 * Just in case there was an issue and Operation Handles
+	 * was no freed
+	 */
+	TA_FreeOp();
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, true);
+
+	op_keysize = keysize;
+
+	switch (objType) {
+	case TEE_TYPE_DH_KEYPAIR:
+		if ((keysize < 256) || (keysize > 2048))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		prime       = TEE_Malloc(keysize / 8, 0);
+		base        = TEE_Malloc(keysize / 64, 0);
+		public_key  = TEE_Malloc(keysize / 8, 0);
+
+		if ((!prime) || (!base) || (!public_key)) {
+			res = TEE_ERROR_OUT_OF_MEMORY;
+			goto PrepareExit_Error;
+		}
+
+		TEE_GenerateRandom(prime, keysize / 8);
+		TEE_GenerateRandom(base, keysize / 64);
+		TEE_GenerateRandom(public_key, keysize / 8);
+
+		/*
+		 * WARNING if prime is even, PKHA Exponentiation
+		 * generate an error ensure if it will be even
+		 * all the time
+		 */
+		prime[(keysize / 8) - 1] |= 1;
+
+		attrs[0].attributeID = TEE_ATTR_DH_PRIME;
+		attrs[0].content.ref.buffer = (void *)prime;
+		attrs[0].content.ref.length = keysize / 8;
+
+		attrs[1].attributeID = TEE_ATTR_DH_BASE;
+		attrs[1].content.ref.buffer = (void *)base;
+		attrs[1].content.ref.length = keysize / 64;
+
+		nb_attrs = 2;
+
+		break;
+
+	case TEE_TYPE_ECDH_KEYPAIR:
+		if ((keysize < 192) || (keysize > 528))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		attrs[0].attributeID = TEE_ATTR_ECC_CURVE;
+		attrs[0].content.value.b = sizeof(int);
+
+		switch (algo) {
+		case TEE_ALG_ECDH_P192:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P192;
+			break;
+
+		case TEE_ALG_ECDH_P224:
+			attrs[0].content.value.a =  TEE_ECC_CURVE_NIST_P224;
+			break;
+
+		case TEE_ALG_ECDH_P256:
+			attrs[0].content.value.a =  TEE_ECC_CURVE_NIST_P256;
+			break;
+
+		case TEE_ALG_ECDH_P384:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P384;
+			break;
+
+		case TEE_ALG_ECDH_P521:
+			attrs[0].content.value.a = TEE_ECC_CURVE_NIST_P521;
+			keysize = 528;
+			break;
+
+		default:
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+		public_x_2  = TEE_Malloc(keysize / 8, 0);
+		public_y_2  = TEE_Malloc(keysize / 8, 0);
+
+		if ((!public_x_2) || (!public_y_2)) {
+			res = TEE_ERROR_OUT_OF_MEMORY;
+			goto PrepareExit_Error;
+		}
+
+		TEE_GenerateRandom(public_x_2, keysize / 8);
+		TEE_GenerateRandom(public_y_2, keysize / 8);
+
+		nb_attrs = 1;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+
+	/* Prepare Keys and Operation handles */
+	res = TEE_AllocateOperation(&deriveKey_op, algo,
+		TEE_MODE_DERIVE, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Key Derive",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, op_keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject Key Derive",
+		goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET,
+		keysize, &hKeyDerived);
+	CHECK(res, "TEE_AllocateTransientObject Key Derive",
+		goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, op_keysize, attrs, nb_attrs);
+	CHECK(res, "TEE_GenerateKey Key Derive", goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(deriveKey_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Derive Key", goto PrepareExit_Error;);
+
+	TEE_FreeTransientObject(hKey);
+
+	/*
+	 * Set params[2].value.b = 0 to inform that there is no reverse.
+	 */
+	params[2].value.b = 0;
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	if (hKey)
+		TEE_FreeTransientObject(hKey);
+
+	TA_FreeOp();
+	return res;
+}
+
+TEE_Result TA_KeyDeriveProcessAlgo(uint32_t algo, TEE_Param params[4])
+{
+	TEE_Result    res;
+	TEE_Attribute attrs[2];
+	uint8_t       nb_attrs = 0;
+	void *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	inSize  = params[0].memref.size;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	if (algo == TEE_ALG_DH_DERIVE_SHARED_SECRET) {
+		attrs[0].attributeID = TEE_ATTR_DH_PUBLIC_VALUE;
+		attrs[0].content.ref.buffer = (void *)public_key;
+		attrs[0].content.ref.length = inSize;
+		nb_attrs = 1;
+	} else {
+		attrs[0].attributeID = TEE_ATTR_ECC_PUBLIC_VALUE_X;
+		attrs[0].content.ref.buffer = (void *)public_x_2;
+		attrs[0].content.ref.length = inSize;
+
+		attrs[1].attributeID = TEE_ATTR_ECC_PUBLIC_VALUE_Y;
+		attrs[1].content.ref.buffer = (void *)public_y_2;
+		attrs[1].content.ref.length = inSize;
+		nb_attrs = 2;
+
+	}
+
+	if (params[2].value.b == 0) {
+		TEE_ResetTransientObject(hKeyDerived);
+
+		TEE_DeriveKey(deriveKey_op, attrs, nb_attrs, hKeyDerived);
+
+		res = TEE_GetObjectBufferAttribute(hKeyDerived,
+			TEE_ATTR_SECRET_VALUE,
+			out, &outSize);
+		CHECK(res, "TEE_GetObjectBufferAttribute Key Derive",
+			return res;);
+	}
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_KeyDeriveFreeAlgo(uint32_t algo __unused,
+	TEE_Param params[4] __unused)
+{
+	TA_FreeOp();
+
+	return TEE_SUCCESS;
+}
+
diff --git a/ta/crypto_perf/ta_alg_list.c b/ta/crypto_perf/ta_alg_list.c
new file mode 100644
index 0000000..d0b2dc9
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_list.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018-2021 NXP
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <util.h>
+
+#include <ta_crypto_perf.h>
+
+const uint32_t id_alg_list[] = {
+	TEE_ALG_AES_ECB_NOPAD,
+	TEE_ALG_AES_CBC_NOPAD,
+	TEE_ALG_AES_CTR,
+	TEE_ALG_AES_CTS,
+	TEE_ALG_AES_XTS,
+	TEE_ALG_AES_CBC_MAC_NOPAD,
+	TEE_ALG_AES_CBC_MAC_PKCS5,
+	TEE_ALG_AES_CMAC,
+	TEE_ALG_AES_CCM,
+	TEE_ALG_AES_GCM,
+	TEE_ALG_DES_ECB_NOPAD,
+	TEE_ALG_DES_CBC_NOPAD,
+	TEE_ALG_DES_CBC_MAC_NOPAD,
+	TEE_ALG_DES_CBC_MAC_PKCS5,
+	TEE_ALG_DES3_ECB_NOPAD,
+	TEE_ALG_DES3_CBC_NOPAD,
+	TEE_ALG_DES3_CBC_MAC_NOPAD,
+	TEE_ALG_DES3_CBC_MAC_PKCS5,
+	TEE_ALG_RSASSA_PKCS1_V1_5_MD5,
+	TEE_ALG_RSASSA_PKCS1_V1_5_SHA1,
+	TEE_ALG_RSASSA_PKCS1_V1_5_SHA224,
+	TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
+	TEE_ALG_RSASSA_PKCS1_V1_5_SHA384,
+	TEE_ALG_RSASSA_PKCS1_V1_5_SHA512,
+	TEE_ALG_RSASSA_PKCS1_V1_5_MD5SHA1,
+	TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1,
+	TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224,
+	TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256,
+	TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384,
+	TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512,
+	TEE_ALG_RSAES_PKCS1_V1_5,
+	TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1,
+	TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224,
+	TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256,
+	TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384,
+	TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512,
+	TEE_ALG_RSA_NOPAD,
+	TEE_ALG_DSA_SHA1,
+	TEE_ALG_DSA_SHA224,
+	TEE_ALG_DSA_SHA256,
+	TEE_ALG_DH_DERIVE_SHARED_SECRET,
+	TEE_ALG_MD5,
+	TEE_ALG_SHA1,
+	TEE_ALG_SHA224,
+	TEE_ALG_SHA256,
+	TEE_ALG_SHA384,
+	TEE_ALG_SHA512,
+	TEE_ALG_MD5SHA1,
+	TEE_ALG_HMAC_MD5,
+	TEE_ALG_HMAC_SHA1,
+	TEE_ALG_HMAC_SHA224,
+	TEE_ALG_HMAC_SHA256,
+	TEE_ALG_HMAC_SHA384,
+	TEE_ALG_HMAC_SHA512,
+	TEE_ALG_ECDSA_P192,
+	TEE_ALG_ECDSA_P224,
+	TEE_ALG_ECDSA_P256,
+	TEE_ALG_ECDSA_P384,
+	TEE_ALG_ECDSA_P521,
+	TEE_ALG_ECDH_P192,
+	TEE_ALG_ECDH_P224,
+	TEE_ALG_ECDH_P256,
+	TEE_ALG_ECDH_P384,
+	TEE_ALG_ECDH_P521
+};
+
+const char *name_alg_list[] = {
+	"AES_ECB_NOPAD",
+	"AES_CBC_NOPAD",
+	"AES_CTR",
+	"AES_CTS",
+	"AES_XTS",
+	"AES_CBC_MAC_NOPAD",
+	"AES_CBC_MAC_PKCS5",
+	"AES_CMAC",
+	"AES_CCM",
+	"AES_GCM",
+	"DES_ECB_NOPAD",
+	"DES_CBC_NOPAD",
+	"DES_CBC_MAC_NOPAD",
+	"DES_CBC_MAC_PKCS5",
+	"DES3_ECB_NOPAD",
+	"DES3_CBC_NOPAD",
+	"DES3_CBC_MAC_NOPAD",
+	"DES3_CBC_MAC_PKCS5",
+	"RSASSA_PKCS1_V1_5_MD5",
+	"RSASSA_PKCS1_V1_5_SHA1",
+	"RSASSA_PKCS1_V1_5_SHA224",
+	"RSASSA_PKCS1_V1_5_SHA256",
+	"RSASSA_PKCS1_V1_5_SHA384",
+	"RSASSA_PKCS1_V1_5_SHA512",
+	"RSASSA_PKCS1_V1_5_MD5SHA1",
+	"RSASSA_PKCS1_PSS_MGF1_SHA1",
+	"RSASSA_PKCS1_PSS_MGF1_SHA224",
+	"RSASSA_PKCS1_PSS_MGF1_SHA256",
+	"RSASSA_PKCS1_PSS_MGF1_SHA384",
+	"RSASSA_PKCS1_PSS_MGF1_SHA512",
+	"RSAES_PKCS1_V1_5",
+	"RSAES_PKCS1_OAEP_MGF1_SHA1",
+	"RSAES_PKCS1_OAEP_MGF1_SHA224",
+	"RSAES_PKCS1_OAEP_MGF1_SHA256",
+	"RSAES_PKCS1_OAEP_MGF1_SHA384",
+	"RSAES_PKCS1_OAEP_MGF1_SHA512",
+	"RSA_NOPAD",
+	"DSA_SHA1",
+	"DSA_SHA224",
+	"DSA_SHA256",
+	"DH_DERIVE_SHARED_SECRET",
+	"MD5",
+	"SHA1",
+	"SHA224",
+	"SHA256",
+	"SHA384",
+	"SHA512",
+	"MD5SHA1",
+	"HMAC_MD5",
+	"HMAC_SHA1",
+	"HMAC_SHA224",
+	"HMAC_SHA256",
+	"HMAC_SHA384",
+	"HMAC_SHA512",
+	"ECDSA_P192",
+	"ECDSA_P224",
+	"ECDSA_P256",
+	"ECDSA_P384",
+	"ECDSA_P521",
+	"ECDH_P192",
+	"ECDH_P224",
+	"ECDH_P256",
+	"ECDH_P384",
+	"ECDH_P521"
+};
+
+uint32_t get_nb_algo(void)
+{
+	return ARRAY_SIZE(id_alg_list);
+}
+
+uint32_t get_size_name_alg_list(void)
+{
+	uint32_t idx;
+	uint32_t size = 0;
+
+	for (idx = 0; idx < get_nb_algo(); idx++)
+		size += (strlen(name_alg_list[idx]) + 1);
+
+	return size;
+}
+
+void copy_name_alg_list(char *buffer)
+{
+	uint32_t idx;
+	uint32_t size;
+
+	for (idx = 0; idx < get_nb_algo(); idx++) {
+		size = (strlen(name_alg_list[idx]) + 1);
+		memcpy(buffer, name_alg_list[idx], size);
+		buffer += size;
+	}
+}
+
+uint32_t get_alg_id(char *name, size_t size)
+{
+	uint32_t idx;
+
+	for (idx = 0; idx < get_nb_algo(); idx++) {
+		if (!(strncmp(name_alg_list[idx], name, size)))
+			return id_alg_list[idx];
+	}
+
+	return (uint32_t)(-1);
+}
diff --git a/ta/crypto_perf/ta_alg_mac.c b/ta/crypto_perf/ta_alg_mac.c
new file mode 100644
index 0000000..8424838
--- /dev/null
+++ b/ta/crypto_perf/ta_alg_mac.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <stdio.h>
+#include <trace.h>
+
+#include <tee_ta_api.h>
+#include <user_ta_header_defines.h>
+#include <ta_crypto_perf.h>
+
+static TEE_OperationHandle mac_op;
+
+static void TA_FreeOp(void)
+{
+	if (mac_op) {
+		TEE_FreeOperation(mac_op);
+		mac_op = NULL;
+	}
+}
+
+
+TEE_Result TA_MacPrepareAlgo(uint32_t algo, TEE_Param params[4])
+{
+	/* Mac Preparation: Don't need to check again input params */
+	TEE_Result       res;
+	TEE_ObjectHandle hKey  = NULL;
+	TEE_ObjectType   objType;
+
+	uint32_t keysize;
+	uint32_t op_keysize;
+	uint8_t  *iv_key     = NULL;
+	size_t   iv_key_size = 0;
+
+	static uint8_t iv[16] = {0};
+
+	keysize = params[1].value.a;
+
+	/*
+	 * Just in case there was an issue and Operation Handle
+	 * was no freed
+	 */
+	TA_FreeOp();
+
+	/* Check the key size */
+	objType = TEE_ALG_GET_KEY_TYPE(algo, false);
+	switch (objType) {
+	case TEE_TYPE_AES:
+		if ((keysize != 128) && (keysize != 192) && (keysize != 256))
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_DES:
+		if (keysize != 64)
+			return TEE_ERROR_BAD_PARAMETERS;
+		/* Don't count the parity key size */
+		keysize -= (keysize / 8);
+		break;
+
+	case TEE_TYPE_DES3:
+		if ((keysize != 128) && (keysize != 192))
+			return TEE_ERROR_BAD_PARAMETERS;
+		/* Don't count the parity key size */
+		keysize -= (keysize / 8);
+		break;
+
+	case TEE_TYPE_HMAC_MD5:
+		if ((keysize < 64) || (keysize > 512))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_HMAC_SHA1:
+		if ((keysize < 80) || (keysize > 512))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_HMAC_SHA224:
+		if ((keysize < 112) || (keysize > 512))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_HMAC_SHA256:
+		if ((keysize < 192) || (keysize > 1024))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_HMAC_SHA384:
+		if ((keysize < 256) || (keysize > 1024))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	case TEE_TYPE_HMAC_SHA512:
+		if ((keysize < 256) || (keysize > 1024))
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		if (keysize % 8)
+			return TEE_ERROR_BAD_PARAMETERS;
+		break;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	op_keysize = keysize;
+	switch (TEE_ALG_GET_CHAIN_MODE(algo)) {
+	case TEE_CHAIN_MODE_CBC_NOPAD:
+	case TEE_CHAIN_MODE_CTR:
+	case TEE_CHAIN_MODE_CTS:
+		iv_key      = iv;
+
+		if ((objType == TEE_TYPE_DES) || (objType == TEE_TYPE_DES3))
+			iv_key_size = 8;
+		else
+			iv_key_size = sizeof(iv);
+		break;
+
+	case TEE_CHAIN_MODE_XTS:
+		iv_key      = iv;
+		iv_key_size = sizeof(iv);
+		op_keysize *= 2;
+		break;
+
+	default:
+		break;
+	}
+
+	/* Prepare Keys */
+	res = TEE_AllocateOperation(&mac_op, algo, TEE_MODE_MAC, op_keysize);
+	CHECK(res, "TEE_AllocateOperation Mac", goto PrepareExit_Error;);
+
+	res = TEE_AllocateTransientObject(objType, keysize, &hKey);
+	CHECK(res, "TEE_AllocateTransientObject Mac", goto PrepareExit_Error;);
+
+	res = TEE_GenerateKey(hKey, keysize, NULL, 0);
+	CHECK(res, "TEE_GenerateKey Cipher", goto PrepareExit_Error;);
+
+	res = TEE_SetOperationKey(mac_op, hKey);
+	CHECK(res, "TEE_SetOperationKey Mac", goto PrepareExit_Error;);
+
+	TEE_FreeTransientObject(hKey);
+
+	if (iv_key) {
+		/* Generate IV Key */
+		TEE_GenerateRandom(iv_key, iv_key_size);
+	}
+
+	TEE_MACInit(mac_op, iv_key, iv_key_size);
+
+	return TEE_SUCCESS;
+
+PrepareExit_Error:
+	TA_FreeOp();
+	return res;
+}
+
+TEE_Result TA_MacProcessAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Mac Process: Don't need to check again input params */
+	void *in;
+	uint32_t inSize;
+
+	in      = params[0].memref.buffer;
+	inSize  = params[0].memref.size;
+
+	TEE_MACUpdate(mac_op, in, inSize);
+
+	return TEE_SUCCESS;
+
+}
+
+TEE_Result TA_MacFreeAlgo(uint32_t algo __unused, TEE_Param params[4])
+{
+	/* Mac Free: Don't need to check again input params */
+	TEE_Result res;
+	void *in, *out;
+	uint32_t inSize;
+	uint32_t outSize;
+
+	in      = params[0].memref.buffer;
+	/*
+	 * Just to do the finalize without error
+	 * Size must be blocksize at least
+	 */
+	inSize  = 16;
+	out     = params[1].memref.buffer;
+	outSize = params[1].memref.size;
+
+	res = TEE_MACComputeFinal(mac_op, in, inSize, out, &outSize);
+	CHECK(res, "TEE_MACComputeFinal Mac", return res;);
+
+	TA_FreeOp();
+	return TEE_SUCCESS;
+}
diff --git a/ta/crypto_perf/ta_entry.c b/ta/crypto_perf/ta_entry.c
new file mode 100644
index 0000000..421a187
--- /dev/null
+++ b/ta/crypto_perf/ta_entry.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2018-2022 NXP
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <tee_ta_api.h>
+#include <ta_crypto_perf.h>
+
+struct ta_caps ta_crypto_caps;
+
+/*
+ * Trusted Application Entry Points
+ */
+
+/* Called each time a new instance is created */
+TEE_Result TA_CreateEntryPoint(void)
+{
+	ta_crypto_caps.nb_algo         = get_nb_algo();
+	ta_crypto_caps.sizeof_alg_list = get_size_name_alg_list();
+	return TEE_SUCCESS;
+}
+
+/* Called each time an instance is destroyed */
+void TA_DestroyEntryPoint(void)
+{
+}
+
+/* Called each time a session is opened */
+TEE_Result TA_OpenSessionEntryPoint(uint32_t nParamTypes, TEE_Param pParams[4],
+				    void **ppSessionContext)
+{
+	(void)nParamTypes;
+	(void)pParams;
+	(void)ppSessionContext;
+	return TEE_SUCCESS;
+}
+
+/* Called each time a session is closed */
+void TA_CloseSessionEntryPoint(void *pSessionContext)
+{
+	(void)pSessionContext;
+}
+
+static TEE_Result TA_GetCaps(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(
+		TEE_PARAM_TYPE_MEMREF_OUTPUT,
+		TEE_PARAM_TYPE_NONE,
+		TEE_PARAM_TYPE_NONE,
+		TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[0].memref.size < sizeof(struct ta_caps))
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	/* Fill the TA Crypto caps structure */
+	memcpy(Params[0].memref.buffer, &ta_crypto_caps,
+		sizeof(struct ta_caps));
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result TA_GetListAlg(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(
+		TEE_PARAM_TYPE_MEMREF_OUTPUT,
+		TEE_PARAM_TYPE_NONE,
+		TEE_PARAM_TYPE_NONE,
+		TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if ((Params[0].memref.size < get_size_name_alg_list()) ||
+		(Params[0].memref.buffer == NULL))
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	copy_name_alg_list(Params[0].memref.buffer);
+	return TEE_SUCCESS;
+}
+
+static TEE_Result TA_PrepareAlgo(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t alg_id;
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(
+		TEE_PARAM_TYPE_MEMREF_INPUT,
+		TEE_PARAM_TYPE_VALUE_INPUT,
+		TEE_PARAM_TYPE_VALUE_OUTPUT,
+		TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[0].memref.buffer == NULL)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	alg_id = get_alg_id(Params[0].memref.buffer, Params[0].memref.size);
+
+	Params[2].value.a = alg_id;
+
+	if (alg_id == (uint32_t)(-1))
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	/* Call Algorithm's class preparation function */
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_CIPHER:
+		res = TA_CipherPrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_DIGEST:
+		res = TA_DigestPrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_MAC:
+		res = TA_MacPrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_CIPHER:
+		res = TA_AsymCipherPrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		res = TA_AsymDigestPrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_KEY_DERIVATION:
+		res = TA_KeyDerivePrepareAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_AE:
+		res = TA_AuthenEncPrepareAlgo(alg_id, Params);
+		break;
+
+	default:
+		res = TEE_ERROR_NOT_SUPPORTED;
+		break;
+	}
+
+	return res;
+}
+
+static TEE_Result TA_ProcessAlgo(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t alg_id;
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(
+		TEE_PARAM_TYPE_MEMREF_INPUT,
+		TEE_PARAM_TYPE_MEMREF_INOUT,
+		TEE_PARAM_TYPE_VALUE_INPUT,
+		TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[0].memref.buffer == NULL)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[1].memref.buffer == NULL)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[2].value.a == 0)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	alg_id = Params[2].value.a;
+
+	/* Call Algorithm's class process function */
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_CIPHER:
+		res = TA_CipherProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_DIGEST:
+		res = TA_DigestProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_MAC:
+		res = TA_MacProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_CIPHER:
+		res = TA_AsymCipherProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		res = TA_AsymDigestProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_KEY_DERIVATION:
+		res = TA_KeyDeriveProcessAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_AE:
+		res = TA_AuthenEncProcessAlgo(alg_id, Params);
+		break;
+
+	default:
+		res = TEE_ERROR_NOT_SUPPORTED;
+		break;
+	}
+
+	return res;
+}
+
+static TEE_Result TA_FreeAlgo(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t alg_id;
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(
+		TEE_PARAM_TYPE_MEMREF_INPUT,
+		TEE_PARAM_TYPE_MEMREF_INOUT,
+		TEE_PARAM_TYPE_VALUE_INPUT,
+		TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[0].memref.buffer == NULL)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[1].memref.buffer == NULL)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (Params[2].value.a == 0)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	alg_id = Params[2].value.a;
+
+	/* Call Algorithm's free function */
+	switch (TEE_ALG_GET_CLASS(alg_id)) {
+	case TEE_OPERATION_CIPHER:
+		res = TA_CipherFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_DIGEST:
+		res = TA_DigestFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_MAC:
+		res = TA_MacFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_CIPHER:
+		res = TA_AsymCipherFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_ASYMMETRIC_SIGNATURE:
+		res = TA_AsymDigestFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_KEY_DERIVATION:
+		res = TA_KeyDeriveFreeAlgo(alg_id, Params);
+		break;
+
+	case TEE_OPERATION_AE:
+		res = TA_AuthenEncFreeAlgo(alg_id, Params);
+		break;
+
+	default:
+		res = TEE_ERROR_NOT_SUPPORTED;
+		break;
+	}
+
+	return res;
+
+}
+
+/* Called when a command is invoked */
+TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,
+				      uint32_t nCommandID, uint32_t nParamTypes,
+				      TEE_Param pParams[4])
+{
+	(void)pSessionContext;
+	switch (nCommandID) {
+	case TA_CRYPTO_PERF_CMD_GET_CAPS:
+		/* Returns the TA Capabilities */
+		return TA_GetCaps(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_GET_LIST_ALG:
+		/* Copy the List of Algorithms' name */
+		return TA_GetListAlg(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_PREPARE_ALG:
+		/* Prepare the algorithm */
+		return TA_PrepareAlgo(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_PROCESS:
+		return TA_ProcessAlgo(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_FREE_ALG:
+		return TA_FreeAlgo(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_PREPARE_GEN:
+		return TA_PrepareGen(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_GENERATE:
+		return TA_Generate(nParamTypes, pParams);
+
+	case TA_CRYPTO_PERF_CMD_FREE_GEN:
+		TA_FreeGen();
+		return TEE_SUCCESS;
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/ta/crypto_perf/ta_keygen.c b/ta/crypto_perf/ta_keygen.c
new file mode 100644
index 0000000..2a126b1
--- /dev/null
+++ b/ta/crypto_perf/ta_keygen.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2022 NXP
+ */
+
+#include <string.h>
+
+#include <ta_crypto_perf.h>
+#include <test_vectors_dsa.h>
+
+static TEE_ObjectHandle hkey_gen;
+static TEE_Attribute key_gen_attrs[4];
+static uint32_t key_gen_nb_attrs;
+
+static uint8_t dh_prime[2048 / 8];
+static uint8_t dh_base[2048 / 64];
+
+TEE_Result TA_PrepareGen(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t keysize = 0;
+	uint32_t alg_id = 0;
+	TEE_ObjectType objType = 0;
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+						  TEE_PARAM_TYPE_VALUE_INPUT,
+						  TEE_PARAM_TYPE_VALUE_OUTPUT,
+						  TEE_PARAM_TYPE_NONE);
+	bool with_private = false;
+	uint32_t alg_class = 0;
+	uint32_t curve = 0;
+	unsigned int n = 0;
+	uint32_t prime_len = 0;
+	uint32_t base_len = 0;
+
+	if (ParamTypes != exp_ParamTypes) {
+		EMSG("Parameter type differ: %" PRIx32 " instead of %" PRIx32,
+		     ParamTypes, exp_ParamTypes);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	if (!Params[0].memref.buffer) {
+		EMSG("Name of the algorithm not provided");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	keysize = Params[1].value.a;
+
+	/* Retrieve the algorithm identifier from the name */
+	alg_id = get_alg_id(Params[0].memref.buffer, Params[0].memref.size);
+	if (alg_id == (uint32_t)(-1)) {
+		EMSG("Cannot retrieve algorithm ID from name");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	Params[2].value.a = alg_id;
+	Params[2].value.b = 0;
+
+	/* We need the private key as the public one cannot be generated */
+	alg_class = TEE_ALG_GET_CLASS(alg_id);
+
+	if (alg_class == TEE_OPERATION_DIGEST) {
+		EMSG("Digest is not supported for key generation");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	if (alg_class == TEE_OPERATION_ASYMMETRIC_CIPHER ||
+	    alg_class == TEE_OPERATION_ASYMMETRIC_SIGNATURE ||
+	    alg_class == TEE_OPERATION_KEY_DERIVATION)
+		with_private = true;
+
+	objType = TEE_ALG_GET_KEY_TYPE(alg_id, with_private);
+
+	DMSG("alg: %" PRIx32 " obj: %" PRIx32 " size: %" PRIx32, alg_id,
+	     objType, keysize);
+
+	/* Clean in case previous call corrupted it */
+	TA_FreeGen();
+
+	/* Set additional parameters if required */
+	switch (objType) {
+	case TEE_TYPE_RSA_KEYPAIR:
+		if (keysize < 256 || keysize > 4096) {
+			EMSG("RSA key pair size %" PRIx32 " out of bound",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		if (keysize % 64) {
+			EMSG("RSA key pair %" PRIx32 " quanta not respected",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		break;
+
+	case TEE_TYPE_DSA_KEYPAIR:
+		if (keysize < 512 || keysize > 3072) {
+			EMSG("RSA key pair size %" PRIx32 " out of bound",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		if (keysize % 64) {
+			EMSG("RSA key pair %" PRIx32 " quanta not respected",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		/* Use existing data to generate the key */
+		for (n = 0; n < ARRAY_SIZE(dsa_key_types); n++) {
+			if (dsa_key_types[n].key_size_bits != keysize)
+				continue;
+
+			key_gen_attrs[0].attributeID = TEE_ATTR_DSA_PRIME;
+			key_gen_attrs[0].content.ref.buffer =
+				(void *)dsa_key_types[n].prime;
+			key_gen_attrs[0].content.ref.length =
+				dsa_key_types[n].prime_len;
+
+			key_gen_attrs[1].attributeID = TEE_ATTR_DSA_SUBPRIME;
+			key_gen_attrs[1].content.ref.buffer =
+				(void *)dsa_key_types[n].sub_prime;
+			key_gen_attrs[1].content.ref.length =
+				dsa_key_types[n].sub_prime_len;
+
+			key_gen_attrs[2].attributeID = TEE_ATTR_DSA_BASE;
+			key_gen_attrs[2].content.ref.buffer =
+				(void *)dsa_key_types[n].base;
+			key_gen_attrs[2].content.ref.length =
+				dsa_key_types[n].base_len;
+
+			key_gen_nb_attrs = 3;
+			break;
+		}
+
+		break;
+
+	case TEE_TYPE_DH_KEYPAIR:
+		prime_len = keysize / 8;
+		base_len = keysize / 64;
+
+		if (keysize < 256 || keysize > 2048) {
+			EMSG("DH key pair size %" PRIx32 " out of bound",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		/* The prime and base are gereted randomly */
+		TEE_GenerateRandom(dh_prime, prime_len);
+		TEE_GenerateRandom(dh_base, base_len);
+
+		/*
+		 * WARNING if prime is even, PKHA Exponentiation
+		 * generate an error ensure if it will be even
+		 * all the time
+		 */
+		dh_prime[prime_len - 1] |= 1;
+
+		key_gen_attrs[0].attributeID = TEE_ATTR_DH_PRIME;
+		key_gen_attrs[0].content.ref.buffer = (void *)dh_prime;
+		key_gen_attrs[0].content.ref.length = prime_len;
+
+		key_gen_attrs[1].attributeID = TEE_ATTR_DH_BASE;
+		key_gen_attrs[1].content.ref.buffer = (void *)dh_base;
+		key_gen_attrs[1].content.ref.length = base_len;
+
+		key_gen_nb_attrs = 2;
+
+		break;
+
+	case TEE_TYPE_ECDSA_KEYPAIR:
+		if (keysize < 192 || keysize > 521) {
+			EMSG("ECDSA key pair size %" PRIx32 " out of bound",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		switch (alg_id) {
+		case TEE_ALG_ECDSA_P192:
+			curve = TEE_ECC_CURVE_NIST_P192;
+			break;
+
+		case TEE_ALG_ECDSA_P224:
+			curve = TEE_ECC_CURVE_NIST_P224;
+			break;
+
+		case TEE_ALG_ECDSA_P256:
+			curve = TEE_ECC_CURVE_NIST_P256;
+			break;
+
+		case TEE_ALG_ECDSA_P384:
+			curve = TEE_ECC_CURVE_NIST_P384;
+			break;
+
+		case TEE_ALG_ECDSA_P521:
+			curve = TEE_ECC_CURVE_NIST_P521;
+			break;
+
+		default:
+			EMSG("Can't find curve for ECDSA with algo %" PRIx32,
+			     alg_id);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		key_gen_attrs[0].attributeID = TEE_ATTR_ECC_CURVE;
+		key_gen_attrs[0].content.value.b = sizeof(int);
+		key_gen_attrs[0].content.value.a = curve;
+		key_gen_nb_attrs = 1;
+		break;
+
+	case TEE_TYPE_ECDH_KEYPAIR:
+		if (keysize < 192 || keysize > 521) {
+			EMSG("ECDH key pair size %" PRIx32 " out of bound",
+			     keysize);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		switch (alg_id) {
+		case TEE_ALG_ECDH_P192:
+			curve = TEE_ECC_CURVE_NIST_P192;
+			break;
+
+		case TEE_ALG_ECDH_P224:
+			curve = TEE_ECC_CURVE_NIST_P224;
+			break;
+
+		case TEE_ALG_ECDH_P256:
+			curve = TEE_ECC_CURVE_NIST_P256;
+			break;
+
+		case TEE_ALG_ECDH_P384:
+			curve = TEE_ECC_CURVE_NIST_P384;
+			break;
+
+		case TEE_ALG_ECDH_P521:
+			curve = TEE_ECC_CURVE_NIST_P521;
+			break;
+
+		default:
+			EMSG("Cannot find curve for ECDH with algo %" PRIx32,
+			     alg_id);
+			return TEE_ERROR_BAD_PARAMETERS;
+		}
+
+		key_gen_attrs[0].attributeID = TEE_ATTR_ECC_CURVE;
+		key_gen_attrs[0].content.value.b = sizeof(int);
+		key_gen_attrs[0].content.value.a = curve;
+		key_gen_nb_attrs = 1;
+		break;
+
+	default:
+		/*
+		 * All the other type of object are support and do not requires
+		 * additional parameters for generation
+		 */
+		break;
+	}
+
+	res = TEE_AllocateTransientObject(objType, keysize, &hkey_gen);
+	CHECK(res, "TEE_AllocateTransientObject Cipher", {});
+
+	DMSG("hkey_gen %p, keysize %" PRIx32 ", key_gen_nb_attrs %" PRId32,
+	     hkey_gen, keysize, key_gen_nb_attrs);
+
+	return res;
+}
+
+TEE_Result TA_Generate(uint32_t ParamTypes, TEE_Param Params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t keysize = 0;
+	uint32_t exp_ParamTypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
+						  TEE_PARAM_TYPE_NONE,
+						  TEE_PARAM_TYPE_NONE,
+						  TEE_PARAM_TYPE_NONE);
+
+	if (ParamTypes != exp_ParamTypes) {
+		EMSG("Parameter type differ: %8.8x instead of %8.8x",
+		     ParamTypes, exp_ParamTypes);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	keysize = Params[0].value.a;
+
+	TEE_ResetTransientObject(hkey_gen);
+
+	DMSG("hkey_gen %p, keysize %" PRIx32 ", key_gen_nb_attrs %" PRId32,
+	     hkey_gen, keysize, key_gen_nb_attrs);
+
+	res = TEE_GenerateKey(hkey_gen, keysize, key_gen_attrs,
+			      key_gen_nb_attrs);
+	CHECK(res, "TEE_GenerateKey", {});
+
+	return res;
+}
+
+void TA_FreeGen(void)
+{
+	TEE_FreeTransientObject(hkey_gen);
+	hkey_gen = TEE_HANDLE_NULL;
+	memset(key_gen_attrs, 0, sizeof(key_gen_attrs));
+	key_gen_nb_attrs = 0;
+}
diff --git a/ta/mp_sign/Android.mk b/ta/mp_sign/Android.mk
new file mode 100644
index 0000000..1a79860
--- /dev/null
+++ b/ta/mp_sign/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 8aaaf200-2450-11e4-abe20002a5d5c51c.ta
+include $(BUILD_OPTEE_MK)
diff --git a/ta/mp_sign/Makefile b/ta/mp_sign/Makefile
new file mode 100644
index 0000000..566dc26
--- /dev/null
+++ b/ta/mp_sign/Makefile
@@ -0,0 +1,4 @@
+BINARY = 8aaaf200-2450-11e4-abe20002a5d5c51c
+
+include ../ta_common.mk
+
diff --git a/ta/mp_sign/include/ta_manufacturing_protection.h b/ta/mp_sign/include/ta_manufacturing_protection.h
new file mode 100644
index 0000000..db4c08c
--- /dev/null
+++ b/ta/mp_sign/include/ta_manufacturing_protection.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2021 NXP
+ */
+#ifndef TA_MANUFACTURING_PROTECTION_H
+#define TA_MANUFACTURING_PROTECTION_H
+
+/*  TA UUID generated at http://www.itu.int/ITU-T/asn1/uuid.html */
+#define TA_MANUFACTURING_PROTECTION_UUID \
+	{ \
+		0x8aaaf200, 0x2450, 0x11e4, \
+		{ \
+			0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1c \
+		} \
+	}
+
+/* PTA ID implemented in the TA */
+#define TA_MP_CMD_SIGN_DATA   0
+#define TA_MP_CMD_GET_MP_PUBK 1
+
+/*
+ * MP Public key maximum size in bytes
+ * Maximum is 2*66 bytes for the ECDSA P521
+ * Add 1 bytes for the key format
+ */
+#define MP_PUBKEY_SIZE_NAX ((2 * 66) + 1)
+
+/*
+ * Calculate the Maximum size of the MP Public Key size in PEM
+ *         format.
+ * -----BEGIN PUBLIC KEY-----\n
+ * [MP Key in PEM]
+ * -----END PUBLIC KEY-----\n
+ */
+#define MP_PUBKEY_PEM_SIZE_MAX \
+	(sizeof("-----BEGIN PUBLIC KEY-----\n") + \
+	 ((((MP_PUBKEY_SIZE_NAX / 3) + 1) * 4) + 1) + \
+	 sizeof("-----END PUBLIC KEY-----\n"))
+
+#endif /* TA_MANUFACTURING_PROTECTION_H */
diff --git a/ta/mp_sign/include/user_ta_header_defines.h b/ta/mp_sign/include/user_ta_header_defines.h
new file mode 100644
index 0000000..a3ff208
--- /dev/null
+++ b/ta/mp_sign/include/user_ta_header_defines.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+#include <ta_manufacturing_protection.h>
+
+#define TA_UUID TA_MANUFACTURING_PROTECTION_UUID
+
+#define TA_FLAGS      (TA_FLAG_MULTI_SESSION | TA_FLAG_EXEC_DDR)
+#define TA_STACK_SIZE (2 * 1024)
+#define TA_DATA_SIZE  (32 * 1024)
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/ta/mp_sign/manufacturing_protection_ta.c b/ta/mp_sign/manufacturing_protection_ta.c
new file mode 100644
index 0000000..5ded604
--- /dev/null
+++ b/ta/mp_sign/manufacturing_protection_ta.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <string.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <pta_manufact_protec.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/pk.h>
+#include <ta_manufacturing_protection.h>
+
+/*
+ * Define a type buffer to handle data and length
+ */
+struct ptabuf {
+	uint8_t *data;
+	size_t length;
+};
+
+TEE_Result TA_CreateEntryPoint(void)
+{
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types __unused,
+				    TEE_Param params[4] __unused,
+				    void **sess_ctx __unused)
+{
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void *sess_ctx __unused)
+{
+}
+
+/*
+ * Write the public key in PEM format
+ *
+ * Returns TEE_SUCCESS or error code
+ */
+static TEE_Result ta_write_pubkey_pem(const struct ptabuf *pubkey,
+				      struct ptabuf *pubkey_pem)
+{
+	int ret = MBEDTLS_ERR_PK_ALLOC_FAILED;
+	mbedtls_ecp_keypair *ecdsa_keypair = NULL;
+	mbedtls_pk_context ctx = {};
+
+	mbedtls_pk_init(&ctx);
+
+	/* Initialize the context and set the keypair */
+	ret = mbedtls_pk_setup(&ctx,
+			       mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
+	if (ret != 0) {
+		EMSG("mbedtls_pk_setup: failed: 0x%" PRIx32, ret);
+		goto out;
+	}
+
+	ecdsa_keypair = ctx.pk_ctx;
+
+	/* generate the ecdsa context with the P256 curve */
+	ret = mbedtls_ecp_group_load(&ecdsa_keypair->grp,
+				     MBEDTLS_ECP_DP_SECP256R1);
+	if (ret != 0) {
+		EMSG("mbedtls_ecp_group_load (group): failed: 0x%" PRIx32, ret);
+		goto out;
+	}
+
+	/* set the ECP point from public key buffer */
+	ret = mbedtls_ecp_point_read_binary(&ecdsa_keypair->grp,
+					    &ecdsa_keypair->Q, pubkey->data,
+					    pubkey->length);
+	if (ret != 0) {
+		EMSG("mbedtls_ecp_point_write_binary : failed: 0x%" PRIx32,
+		     ret);
+		goto out;
+	}
+
+	/* Write the public key to a PEM string buffer */
+	ret = mbedtls_pk_write_pubkey_pem(&ctx, pubkey_pem->data,
+					  pubkey_pem->length);
+	if (ret != 0) {
+		EMSG("mbedtls_pk_write_pubkey_pem : failed: 0x%" PRIx32, ret);
+		goto out;
+	}
+
+out:
+	mbedtls_pk_free(&ctx);
+
+	return ret ? TEE_ERROR_GENERIC : TEE_SUCCESS;
+}
+
+static TEE_Result sign_message(uint32_t param_types, TEE_Param params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	struct ptabuf message = {};
+	struct ptabuf signature = {};
+	struct ptabuf mpmr = {};
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+						   TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						   TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						   TEE_PARAM_TYPE_NONE);
+	TEE_TASessionHandle session = TEE_HANDLE_NULL;
+	TEE_UUID uuid = PTA_MANUFACT_PROTEC_UUID;
+	uint32_t err_origin = 0;
+	uint32_t sign_param_types = 0;
+	TEE_Param sign_params[4] = {};
+
+	if (param_types != exp_param_types) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	message.data = params[0].memref.buffer;
+	message.length = params[0].memref.size;
+
+	signature.data = params[1].memref.buffer;
+	signature.length = params[1].memref.size;
+
+	mpmr.data = params[2].memref.buffer;
+	mpmr.length = params[2].memref.size;
+
+	/* Open session to PTA */
+	res = TEE_OpenTASession(&uuid, 0, 0, NULL, &session, &err_origin);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE open session failed with code 0x%" PRIx32
+		     " origin 0x%" PRIx32,
+		     res, err_origin);
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	/* Call PTA to sign message */
+	sign_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+					   TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					   TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					   TEE_PARAM_TYPE_NONE);
+	sign_params[0].memref.buffer = message.data;
+	sign_params[0].memref.size = message.length;
+
+	sign_params[1].memref.buffer = signature.data;
+	sign_params[1].memref.size = signature.length;
+
+	sign_params[2].memref.buffer = mpmr.data;
+	sign_params[2].memref.size = mpmr.length;
+
+	res = TEE_InvokeTACommand(session, 0, PTA_MP_CMD_SIGNATURE_MPMR,
+				  sign_param_types, sign_params, &err_origin);
+	signature.length = sign_params[1].memref.size;
+	mpmr.length = sign_params[2].memref.size;
+
+	if (res != TEE_SUCCESS) {
+		EMSG("%s failed with code 0x%" PRIx32,
+		     "PTA_MP_CMD_SIGNATURE_MPMR", res);
+		goto out;
+	}
+
+out:
+	/* Update output lengths */
+	params[1].memref.size = signature.length;
+	params[2].memref.size = mpmr.length;
+
+	TEE_CloseTASession(session);
+	return res;
+}
+
+static TEE_Result get_mp_pubk(uint32_t param_types, TEE_Param params[4])
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	struct ptabuf mp_pubkey = {};
+	struct ptabuf pubkey_raw_pem = {};
+	struct ptabuf mp_pubkey_pem = {};
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						   TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+	TEE_TASessionHandle session = TEE_HANDLE_NULL;
+	TEE_UUID uuid = PTA_MANUFACT_PROTEC_UUID;
+	uint32_t err_origin = 0;
+	uint32_t getmppubk_param_types = 0;
+	TEE_Param getmppubk_params[4] = {};
+
+	if (param_types != exp_param_types) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	mp_pubkey.data = params[0].memref.buffer;
+	mp_pubkey.length = params[0].memref.size;
+
+	mp_pubkey_pem.data = params[1].memref.buffer;
+	mp_pubkey_pem.length = params[1].memref.size;
+
+	/* Open session to PTA */
+	res = TEE_OpenTASession(&uuid, 0, 0, NULL, &session, &err_origin);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE open session failed with code 0x%" PRIx32
+		     " origin 0x%" PRIx32,
+		     res, err_origin);
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	/* Call PTA to retrieve MP public key */
+	getmppubk_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						TEE_PARAM_TYPE_NONE,
+						TEE_PARAM_TYPE_NONE,
+						TEE_PARAM_TYPE_NONE);
+	getmppubk_params[0].memref.buffer = mp_pubkey.data;
+	getmppubk_params[0].memref.size = mp_pubkey.length;
+
+	res = TEE_InvokeTACommand(session, 0, PTA_MP_CMD_GET_PUBLIC_KEY,
+				  getmppubk_param_types, getmppubk_params,
+				  &err_origin);
+	mp_pubkey.length = getmppubk_params[0].memref.size;
+
+	if (res != TEE_SUCCESS) {
+		EMSG("%s failed with code 0x%" PRIx32,
+		     "PTA_MP_CMD_GET_PUBLIC_KEY", res);
+		goto out;
+	}
+
+	/*
+	 * Transform the hex representation of the public key into raw PEM
+	 * This can be done by prepending the byte 0x04 before the public key
+	 *
+	 * We allocate a temporary buffer to pass to mbedtls adding the
+	 * necessary leading byte
+	 */
+	pubkey_raw_pem.length = mp_pubkey.length + 1;
+	pubkey_raw_pem.data = TEE_Malloc(pubkey_raw_pem.length, 0);
+	if (!pubkey_raw_pem.data) {
+		EMSG("Failed allocate mem for RAW PEM");
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+
+	/* RAW PEM */
+	pubkey_raw_pem.data[0] = 0x4;
+	memcpy(&pubkey_raw_pem.data[1], mp_pubkey.data, mp_pubkey.length);
+
+	res = ta_write_pubkey_pem(&pubkey_raw_pem, &mp_pubkey_pem);
+	if (res != TEE_SUCCESS) {
+		EMSG("ta_write_cert failed with code 0x%" PRIx32, res);
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+out:
+	/* Update output lengths */
+	params[0].memref.size = mp_pubkey.length;
+	params[1].memref.size = mp_pubkey_pem.length;
+
+	TEE_Free(pubkey_raw_pem.data);
+	TEE_CloseTASession(session);
+	return res;
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx __unused, uint32_t cmd_id,
+				      uint32_t param_types, TEE_Param params[4])
+{
+	switch (cmd_id) {
+	case TA_MP_CMD_SIGN_DATA:
+		return sign_message(param_types, params);
+	case TA_MP_CMD_GET_MP_PUBK:
+		return get_mp_pubk(param_types, params);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/ta/mp_sign/sub.mk b/ta/mp_sign/sub.mk
new file mode 100644
index 0000000..18c3650
--- /dev/null
+++ b/ta/mp_sign/sub.mk
@@ -0,0 +1,2 @@
+global-incdirs-y += include
+srcs-y += manufacturing_protection_ta.c
