diff --git a/tools/Makefile b/tools/Makefile
index ccd60a5..e487530 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -38,6 +38,7 @@ tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
 tools-$(CONFIG_USES_MINOR) += kernel2minor
 tools-$(CONFIG_USE_SPARSE) += sparse
 tools-y += openssl
+tools-y += aesgcm
 
 # builddir dependencies
 $(curdir)/autoconf/compile := $(curdir)/m4/compile
@@ -76,6 +77,7 @@ $(curdir)/squashfs/compile := $(curdir)/lzma-old/compile
 $(curdir)/squashfskit4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile
 $(curdir)/zlib/compile := $(curdir)/cmake/compile
 $(curdir)/zstd/compile := $(curdir)/cmake/compile
+$(curdir)/aesgcm/compile := $(curdir)/openssl/compile
 
 ifneq ($(HOST_OS),Linux)
   $(curdir)/squashfskit4/compile += $(curdir)/coreutils/compile
diff --git a/tools/aesgcm/Makefile b/tools/aesgcm/Makefile
new file mode 100644
index 0000000..f7ffc53
--- /dev/null
+++ b/tools/aesgcm/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2022 MediaTek Inc. All rights reserved.
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=aesgcm
+PKG_VERSION:=1.0
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+	OPENSSL_INCS_LOCATION=-I$(STAGING_DIR_HOST)/include/openssl-3 \
+	OPENSSL_LIBS_LOCATION=-L$(STAGING_DIR_HOST)/lib/openssl-3
+endef
+
+define Host/Prepare
+	mkdir -p $(HOST_BUILD_DIR)
+	$(CP) -a ./src/* $(HOST_BUILD_DIR)/
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/aesgcm $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/aesgcm/src/Makefile b/tools/aesgcm/src/Makefile
new file mode 100644
index 0000000..18d2e7b
--- /dev/null
+++ b/tools/aesgcm/src/Makefile
@@ -0,0 +1,12 @@
+CFLAGS = $(OPENSSL_INCS_LOCATION)
+LDFLAGS = $(OPENSSL_LIBS_LOCATION) -lssl -lcrypto -ldl -lpthread
+
+all: aesgcm
+
+aesgcm: aesgcm.o
+
+aesgcm:
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+clean:
+	$(RM) aesgcm
diff --git a/tools/aesgcm/src/aesgcm.c b/tools/aesgcm/src/aesgcm.c
new file mode 100644
index 0000000..05aa373
--- /dev/null
+++ b/tools/aesgcm/src/aesgcm.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2022 Mediatek Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * Simple AES GCM authenticated encryption with additional data (AEAD)
+ * demonstration program.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+
+#define MAX_TEXT_LENGTH		4096
+#define MAX_AAD_LENGTH		256
+#define MAX_TAG_LENGTH		32
+
+#define ERR_ENC			1
+#define ERR_DEC			2
+#define ERR_UNK_MOD		3
+
+typedef enum {
+	UNK,
+	ENCRYPT,
+	DECRYPT
+} OPERATION;
+
+/*
+ * A library context and property query can be used to select & filter
+ * algorithm implementations. If they are NULL then the default library
+ * context and properties are used.
+ */
+OSSL_LIB_CTX *libctx = NULL;
+const char *propq = NULL;
+
+int aes_gcm_encrypt(uint8_t *key, uint8_t *iv, long iv_len, uint8_t *aad,
+		    long aad_len, uint8_t *pt, long pt_len, BIO *out)
+{
+	int ret = 0;
+	EVP_CIPHER_CTX *ctx;
+	EVP_CIPHER *cipher = NULL;
+	int outlen, tmplen;
+	uint8_t *outbuf;
+	uint8_t *outtag[16];
+	OSSL_PARAM params[2] = {
+		OSSL_PARAM_END, OSSL_PARAM_END
+	};
+
+	outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
+	if (!outbuf)
+		return 0;
+
+	/* Create a context for the encrypt operation */
+	if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
+		goto err;
+
+	/* Fetch the cipher implementation */
+	if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
+		goto err;
+
+	/* Set IV length if default 96 bits is not appropriate */
+	params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
+						&iv_len);
+	/*
+	 * Initialise an encrypt operation with the cipher/mode, key, IV and
+	 * IV length parameter.
+	 * For demonstration purposes the IV is being set here. In a compliant
+	 * application the IV would be generated internally so the iv passed in
+	 * would be NULL.
+	 */
+	if (!EVP_EncryptInit_ex2(ctx, cipher, key, iv, params))
+		goto err;
+
+	/* Zero or more calls to specify any AAD */
+	if (!EVP_EncryptUpdate(ctx, NULL, &outlen, aad, aad_len))
+		goto err;
+
+	/* Encrypt plaintext */
+	if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, pt, pt_len))
+		goto err;
+
+	/* Finalise: note get no output for GCM */
+	if (!EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))
+		goto err;
+
+	/* Get tag */
+	params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
+						      outtag, 16);
+
+	if (!EVP_CIPHER_CTX_get_params(ctx, params))
+		goto err;
+
+	/* Output IV */
+	if (BIO_write(out, iv, iv_len) <= 0)
+		goto err;
+
+	/* Output tag */
+	if (BIO_write(out, outtag, 16) <= 0)
+		goto err;
+
+	/* Output encrypted block */
+	if (BIO_write(out, outbuf, outlen) <= 0)
+		goto err;
+
+	ret = 1;
+err:
+	if (!ret)
+		ERR_print_errors_fp(stderr);
+
+	free(outbuf);
+	EVP_CIPHER_free(cipher);
+	EVP_CIPHER_CTX_free(ctx);
+
+	return ret;
+}
+
+int aes_gcm_decrypt(uint8_t *key, uint8_t *iv, long iv_len,
+		    uint8_t *aad, long aad_len, uint8_t *ct, long ct_len,
+		    uint8_t *tag, long tag_len, BIO *out)
+{
+	int ret = 0;
+	EVP_CIPHER_CTX *ctx;
+	EVP_CIPHER *cipher = NULL;
+	int outlen, rv;
+	uint8_t *outbuf;
+	OSSL_PARAM params[2] = {
+		OSSL_PARAM_END, OSSL_PARAM_END
+	};
+
+	outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
+	if (!outbuf)
+		return 0;
+
+	if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
+		goto err;
+
+	/* Fetch the cipher implementation */
+	if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
+		goto err;
+
+	/* Set IV length if default 96 bits is not appropriate */
+	params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
+						&iv_len);
+
+	/*
+	 * Initialise an encrypt operation with the cipher/mode, key, IV and
+	 * IV length parameter.
+	 */
+	if (!EVP_DecryptInit_ex2(ctx, cipher, key, iv, params))
+		goto err;
+
+	/* Zero or more calls to specify any AAD */
+	if (!EVP_DecryptUpdate(ctx, NULL, &outlen, aad, aad_len))
+		goto err;
+
+	/* Decrypt plaintext */
+	if (!EVP_DecryptUpdate(ctx, outbuf, &outlen, ct, ct_len))
+		goto err;
+
+	/* Output decrypted block */
+	if (BIO_write(out, outbuf, outlen) <= 0)
+		goto err;
+
+	/* Set expected tag value. */
+	params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
+						      (void *)tag, tag_len);
+
+	if (!EVP_CIPHER_CTX_set_params(ctx, params))
+		goto err;
+
+	/* Finalise: note get no output for GCM */
+	rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen);
+	/*
+	 * Print out return value. If this is not successful authentication
+	 * failed and plaintext is not trustworthy.
+	 */
+	printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!");
+
+	ret = rv > 0 ? 1 : 0;
+err:
+	if (!ret)
+		ERR_print_errors_fp(stderr);
+
+	free(outbuf);
+	EVP_CIPHER_free(cipher);
+	EVP_CIPHER_CTX_free(ctx);
+
+	return ret;
+}
+
+void usage(void)
+{
+	printf(
+		"simple aes-256-gcm tool: \n"
+		"Operations:\n"
+		"-e 		- encrypt\n"
+		"-d 		- decrypt\n"
+		"Common requirement parameters:\n"
+		"-i infile	- input file\n"
+		"-o outfile	- out file\n"
+		"-k key(hex) 	- key in hex\n"
+		"-n iv(hex)	- initial vector in hex\n"
+		"-a aad(hex)	- additional authentication data in hex\n"
+		"Decryption requirement paremters:\n"
+		"-t intagfile 	- tag file as input\n");
+}
+
+int main(int argc, char **argv)
+{
+	int ret = 0, opt, oper = UNK;
+	long key_len = 0, iv_len = 0, aad_len = 0, tag_len = 0, in_len = 0;
+	BIO *in = NULL, *out = NULL, *in_tag = NULL;
+	uint8_t *in_buf;
+	uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
+	uint8_t iv[EVP_MAX_IV_LENGTH] = {0};
+	uint8_t aad[MAX_AAD_LENGTH] = {0};
+	uint8_t tag[MAX_TAG_LENGTH] = {0};
+
+	in_buf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
+	if (!in_buf)
+		return -ENOMEM;
+
+	while ((opt = getopt(argc, argv, "a:dei:g:k:n:o:t:")) > 0) {
+		switch(opt) {
+		case 'a':
+			ret = OPENSSL_hexstr2buf_ex(aad, MAX_AAD_LENGTH,
+						    &aad_len, optarg, '\0');
+			if (!ret) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to read aad\n");
+				goto end;
+			}
+			break;
+		case 'd':
+			if (oper) {
+				ret = -EINVAL;
+				fprintf(stderr, "Duplicate operations\n");
+				goto end;
+			}
+			oper = DECRYPT;
+			break;
+		case 'e':
+			if (oper) {
+				ret = -EINVAL;
+				fprintf(stderr, "Duplicate operations\n");
+				goto end;
+			}
+			oper = ENCRYPT;
+			break;
+		case 'i':
+			in = BIO_new_file(optarg, "rb");
+			if (!in) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to open input file\n");
+				goto end;
+			}
+
+			in_len = BIO_read(in, in_buf, MAX_TEXT_LENGTH);
+			if (in_len <= 0) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to read input file\n");
+				goto end;
+			}
+			break;
+		case 'k':
+			ret = OPENSSL_hexstr2buf_ex(key, EVP_MAX_KEY_LENGTH,
+				    		    &key_len, optarg, '\0');
+			if (!ret) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to read key\n");
+				goto end;
+			}
+			break;
+			case 'n':
+			ret = OPENSSL_hexstr2buf_ex(iv, EVP_MAX_IV_LENGTH,
+				    		    &iv_len, optarg, '\0');
+			if (!ret) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to read iv\n");
+				goto end;
+			}
+			break;
+		case 'o':
+			out = BIO_new_file(optarg, "w");
+			if (!out) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to open output file\n");
+				goto end;
+			}
+			break;
+		case 't':
+			in_tag = BIO_new_file(optarg, "rb");
+			if (!in_tag) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to open tag file\n");
+				goto end;
+			}
+
+			tag_len = BIO_read(in_tag, tag, MAX_TAG_LENGTH);
+			if (tag_len <= 0) {
+				ret = -EINVAL;
+				fprintf(stderr, "Failed to read tag file\n");
+				goto end;
+			}
+			break;
+		default:
+			break;
+		}
+
+	}
+
+	if (!key_len || !iv_len || !aad_len || !in_len || !out) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (oper == ENCRYPT) {
+		ret = aes_gcm_encrypt(key, iv, iv_len, aad, aad_len,
+				      in_buf, in_len, out);
+		if (!ret) {
+			ret = -ERR_ENC;
+			goto end;
+		}
+	} else if (oper == DECRYPT) {
+		if (!tag_len) {
+			ret = -EINVAL;
+			goto end;
+		}
+
+		ret = aes_gcm_decrypt(key, iv, iv_len, aad, aad_len,
+				      in_buf, in_len, tag, tag_len, out);
+		if (!ret) {
+			ret = -ERR_DEC;
+			goto end;
+		}
+	} else {
+		ret = -ERR_UNK_MOD;
+		goto end;
+	}
+
+end:
+	free(in_buf);
+	if (in)
+		BIO_free(in);
+	if (out)
+		BIO_free(out);
+	if (in_tag)
+		BIO_free(in_tag);
+
+	if (ret == -EINVAL)
+		usage();
+
+	return ret;
+}
