diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
index a30b139b..7cb7bd6b 100644
--- a/Documentation/ndctl/Makefile.am
+++ b/Documentation/ndctl/Makefile.am
@@ -47,7 +47,8 @@ man1_MANS = \
 	ndctl-inject-smart.1 \
 	ndctl-update-firmware.1 \
 	ndctl-list.1 \
-	ndctl-monitor.1
+	ndctl-monitor.1 \
+	ndctl-install-encrypt-key.1
 
 CLEANFILES = $(man1_MANS)
 
diff --git a/Documentation/ndctl/ndctl-install-encrypt-key.txt b/Documentation/ndctl/ndctl-install-encrypt-key.txt
new file mode 100644
index 00000000..d00463e3
--- /dev/null
+++ b/Documentation/ndctl/ndctl-install-encrypt-key.txt
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+ndctl-install-encrypt-key(1)
+============================
+
+NAME
+----
+ndctl-install-encrypt-key - store encryption key name for nvdimm bus
+
+SYNOPSIS
+--------
+[verse]
+'ndctl install-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key] [<options>]
+
+Take the provided master encryption key handle and store it in a file that
+A file would be created for the designated bus provider.
+i.e. /etc/ndctl/keys/nfit_test.0.kek
+The command only succeeds on bus(es) that contain nvdimms with security support.
+
+OPTIONS
+-------
+-k::
+--kek=::
+	Key encryption key (master key) handle. The key handle has the format
+	of <key type>:<key name>. i.e. trusted:nvdimm-master.
+
+-v::
+--verbose::
+	Turn on debug output
+
+include::../copyright.txt[]
diff --git a/configure.ac b/configure.ac
index a02a2d80..61e91e0a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,9 @@ ndctl_monitorconf=monitor.conf
 AC_SUBST([ndctl_monitorconfdir])
 AC_SUBST([ndctl_monitorconf])
 
+ndctl_keysdir=${sysconfdir}/ndctl/keys
+AC_SUBST([ndctl_keysdir])
+
 my_CFLAGS="\
 -Wall \
 -Wchar-subscripts \
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 97de1814..e412dbf7 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -8,6 +8,7 @@ config.h: Makefile.am
 	$(AM_V_GEN) echo "/* Autogenerated by ndctl/Makefile.am */" >$@
 	$(AM_V_GEN) echo '#define NDCTL_CONF_FILE \
 		"$(ndctl_monitorconfdir)/$(ndctl_monitorconf)"' >>$@
+	$(AM_V_GEN) echo '#define NDCTL_KEYS_DIR  "$(ndctl_keysdir)"' >>$@
 
 ndctl_SOURCES = ndctl.c \
 		bus.c \
@@ -23,7 +24,8 @@ ndctl_SOURCES = ndctl.c \
 		util/json-firmware.c \
 		inject-error.c \
 		inject-smart.c \
-		monitor.c
+		monitor.c \
+		kek.c
 
 if ENABLE_DESTRUCTIVE
 ndctl_SOURCES += ../test/blk_namespaces.c \
diff --git a/ndctl/builtin.h b/ndctl/builtin.h
index 17300df0..4af34f04 100644
--- a/ndctl/builtin.h
+++ b/ndctl/builtin.h
@@ -32,4 +32,5 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx);
 #endif
 int cmd_update_firmware(int argc, const char **argv, struct ndctl_ctx *ctx);
 int cmd_inject_smart(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_install_kek(int argc, const char **argv, struct ndctl_ctx *ctx);
 #endif /* _NDCTL_BUILTIN_H_ */
diff --git a/ndctl/kek.c b/ndctl/kek.c
new file mode 100644
index 00000000..1cb1555e
--- /dev/null
+++ b/ndctl/kek.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <util/log.h>
+#include <json-c/json.h>
+#include <ndctl/config.h>
+#include <ndctl/libndctl.h>
+#include <util/parse-options.h>
+#include <ccan/array_size/array_size.h>
+
+#include <ndctl.h>
+
+static struct parameters {
+	const char *kek;
+	bool verbose;
+} param;
+
+static int store_kek(const char *provider, const char *kek)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+	ssize_t rc, wrote = 0;
+	int size = strlen(kek);
+
+	rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR, provider);
+	if (rc < 0) {
+		perror("sprintf kek path failed");
+		return rc;
+	}
+
+	fp = fopen(path, "w+");
+	if (!fp) {
+		fprintf(stderr, "Opening file %s failed: %s\n",
+				path, strerror(errno));
+		return -errno;
+	}
+
+	do {
+		rc = fwrite(kek + wrote, 1, size - wrote, fp);
+		if (rc < 0) {
+			fprintf(stderr, "writing file %s failed: %s\n",
+					path, strerror(errno));
+			fclose(fp);
+			return -errno;
+		}
+		wrote += rc;
+	} while (wrote != size);
+
+	fclose(fp);
+	printf("key handle %s installed to %s\n", kek, path);
+	return 0;
+}
+
+int cmd_install_kek(int argc, const char **argv, struct ndctl_ctx *ctx)
+{
+	const struct option options[] = {
+		OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"),
+		OPT_STRING('k', "kek", &param.kek, "kek",
+				"Key encription key (master)"),
+		OPT_END(),
+	};
+	const char * const u[] = {
+		"ndctl intall-encrypt-key <ndbus0> [<ndbus1>..<ndbusN>] [-k <master encryption key>]",
+		NULL
+	};
+	int i, rc;
+	bool all = false;
+
+	argc = parse_options(argc, argv, options, u, 0);
+
+	if (argc == 0) {
+		usage_with_options(u, options);
+		return -EINVAL;
+	}
+
+	if (!param.kek) {
+		usage_with_options(u, options);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < argc; i++) {
+		if (strcmp(argv[i], "all") == 0) {
+			argv[0] = "all";
+			argc = 1;
+			all = true;
+			break;
+		}
+	}
+
+	if (param.verbose)
+		ndctl_set_log_priority(ctx, LOG_DEBUG);
+
+	for (i = 0; i < argc; i++) {
+		struct ndctl_bus *bus;
+		struct ndctl_dimm *dimm;
+		bool security = false;
+
+		ndctl_bus_foreach(ctx, bus) {
+			if (!util_bus_filter(bus, argv[i]) && !all)
+				continue;
+
+			ndctl_dimm_foreach(bus, dimm) {
+				if (ndctl_dimm_get_security(dimm) >= 0) {
+					security = true;
+					break;
+				}
+			}
+
+			if (!security)
+				continue;
+
+			rc = store_kek(ndctl_bus_get_provider(bus),
+					param.kek);
+			if (rc < 0)
+				fprintf(stderr, "store kek %s for bus %s failed\n",
+						param.kek, ndctl_bus_get_devname(bus));
+
+		}
+	}
+
+	return 0;
+}
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 830b7913..b255eb1b 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -36,6 +36,7 @@
 #include <ndctl/namespace.h>
 #include <daxctl/libdaxctl.h>
 #include <ndctl/libndctl-nfit.h>
+#include <ndctl/config.h>
 #include "private.h"
 
 static uuid_t null_uuid;
@@ -620,6 +621,7 @@ static void free_bus(struct ndctl_bus *bus, struct list_head *head)
 	free(bus->bus_buf);
 	free(bus->wait_probe_path);
 	free(bus->scrub_path);
+	free(bus->kek_handle);
 	free(bus);
 }
 
@@ -812,6 +814,28 @@ static void parse_dimm_flags(struct ndctl_dimm *dimm, char *flags)
 				ndctl_dimm_get_devname(dimm), flags);
 }
 
+static int bus_retrieve_kek_handle(struct ndctl_bus *bus)
+{
+	char path[PATH_MAX];
+	FILE *fp;
+	ssize_t rc;
+
+	rc = sprintf(path, "%s/%s.kek", NDCTL_KEYS_DIR,
+			ndctl_bus_get_provider(bus));
+	if (rc < 0)
+		return -errno;
+
+	fp = fopen(path, "r");
+	if (!fp)
+		return -errno;
+
+	if (fscanf(fp, "%ms", &bus->kek_handle) == EOF)
+		return -errno;
+
+	fclose(fp);
+	return 0;
+}
+
 static void *add_bus(void *parent, int id, const char *ctl_base)
 {
 	char buf[SYSFS_ATTR_SIZE];
@@ -890,6 +914,8 @@ static void *add_bus(void *parent, int id, const char *ctl_base)
 			return bus_dup;
 		}
 
+	bus_retrieve_kek_handle(bus);
+
 	list_add(&ctx->busses, &bus->list);
 	free(path);
 
@@ -5396,3 +5422,8 @@ NDCTL_EXPORT struct daxctl_region *ndctl_dax_get_daxctl_region(
 
 	return dax->region;
 }
+
+NDCTL_EXPORT const char *ndctl_bus_get_kek_handle(struct ndctl_bus *bus)
+{
+	return bus->kek_handle;
+}
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 0888c824..6d5e6606 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -391,4 +391,5 @@ global:
 	ndctl_cmd_xlat_firmware_status;
 	ndctl_cmd_submit_xlat;
 	ndctl_dimm_get_security;
+	ndctl_bus_get_kek_handle;
 } LIBNDCTL_18;
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index a387b0b5..a860f0db 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -172,6 +172,7 @@ struct ndctl_bus {
 	char *scrub_path;
 	unsigned long cmd_mask;
 	unsigned long nfit_dsm_mask;
+	char *kek_handle;
 };
 
 /**
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index e228c64f..b0cc4543 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -694,6 +694,7 @@ enum ndctl_security_state {
 };
 
 enum ndctl_security_state ndctl_dimm_get_security(struct ndctl_dimm *dimm);
+const char *ndctl_bus_get_kek_handle(struct ndctl_bus *bus);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index b01594e0..bd11ec03 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -90,6 +90,7 @@ static struct cmd_struct commands[] = {
 	{ "start-scrub", { cmd_start_scrub } },
 	{ "list", { cmd_list } },
 	{ "monitor", { cmd_monitor } },
+	{ "install-encrypt-key", { cmd_install_kek } },
 	{ "help", { cmd_help } },
 	#ifdef ENABLE_TEST
 	{ "test", { cmd_test } },
