]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
tools: Add firmware authenticated encryption tool
authorSumit Garg <sumit.garg@linaro.org>
Mon, 11 Nov 2019 13:16:36 +0000 (18:46 +0530)
committerSumit Garg <sumit.garg@linaro.org>
Fri, 6 Mar 2020 11:10:37 +0000 (16:40 +0530)
Add firmware authenticated encryption tool which utilizes OpenSSL
library to encrypt firmwares using a key provided via cmdline. Currently
this tool supports AES-GCM as an authenticated encryption algorithm.

Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
Change-Id: I60e296af1b98f1912a19d5f91066be7ea85836e4

Makefile
tools/encrypt_fw/Makefile [new file with mode: 0644]
tools/encrypt_fw/include/cmd_opt.h [new file with mode: 0644]
tools/encrypt_fw/include/debug.h [new file with mode: 0644]
tools/encrypt_fw/include/encrypt.h [new file with mode: 0644]
tools/encrypt_fw/src/cmd_opt.c [new file with mode: 0644]
tools/encrypt_fw/src/encrypt.c [new file with mode: 0644]
tools/encrypt_fw/src/main.c [new file with mode: 0644]

index f7ae5ea506ffa5457824cd749760e6f16d9d24e3..8f50d7c8dbe637f025703e19c1b45717bb0bb7f2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -716,6 +716,10 @@ include lib/stack_protector/stack_protector.mk
 CRTTOOLPATH            ?=      tools/cert_create
 CRTTOOL                        ?=      ${CRTTOOLPATH}/cert_create${BIN_EXT}
 
+# Variables for use with Firmware Encryption Tool
+ENCTOOLPATH            ?=      tools/encrypt_fw
+ENCTOOL                        ?=      ${ENCTOOLPATH}/encrypt_fw${BIN_EXT}
+
 # Variables for use with Firmware Image Package
 FIPTOOLPATH            ?=      tools/fiptool
 FIPTOOL                        ?=      ${FIPTOOLPATH}/fiptool${BIN_EXT}
@@ -935,7 +939,7 @@ endif
 # Build targets
 ################################################################################
 
-.PHONY:        all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc
+.PHONY:        all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc enctool
 .SUFFIXES:
 
 all: msg_start
@@ -1038,6 +1042,7 @@ clean:
        $(call SHELL_REMOVE_DIR,${BUILD_PLAT})
        ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
        ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+       ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} clean
        ${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
 
 realclean distclean:
@@ -1047,6 +1052,7 @@ realclean distclean:
        ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
        ${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean
        ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+       ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean
        ${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
 
 checkcodebase:         locate-checkpatch
@@ -1148,6 +1154,15 @@ doc:
        @echo "  BUILD DOCUMENTATION"
        ${Q}${MAKE} --no-print-directory -C ${DOCS_PATH} html
 
+enctool: ${ENCTOOL}
+
+.PHONY: ${ENCTOOL}
+${ENCTOOL}:
+       ${Q}${MAKE} PLAT=${PLAT} BUILD_INFO=0 --no-print-directory -C ${ENCTOOLPATH}
+       @${ECHO_BLANK_LINE}
+       @echo "Built $@ successfully"
+       @${ECHO_BLANK_LINE}
+
 cscope:
        @echo "  CSCOPE"
        ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
@@ -1184,6 +1199,7 @@ help:
        @echo "  cscope         Generate cscope index"
        @echo "  distclean      Remove all build artifacts for all platforms"
        @echo "  certtool       Build the Certificate generation tool"
+       @echo "  enctool        Build the Firmware encryption tool"
        @echo "  fiptool        Build the Firmware Image Package (FIP) creation tool"
        @echo "  sp             Build the Secure Partition Packages"
        @echo "  sptool         Build the Secure Partition Package creation tool"
diff --git a/tools/encrypt_fw/Makefile b/tools/encrypt_fw/Makefile
new file mode 100644 (file)
index 0000000..cb81d0b
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2019, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PROJECT                := encrypt_fw
+V              ?= 0
+BUILD_INFO     ?= 1
+DEBUG          := 0
+BINARY         := ${PROJECT}${BIN_EXT}
+OPENSSL_DIR    := /usr
+
+OBJECTS := src/encrypt.o \
+           src/cmd_opt.o \
+           src/main.o
+
+HOSTCCFLAGS := -Wall -std=c99
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+ifeq (${BUILD_INFO},1)
+  HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+else
+  HOSTCCFLAGS += -O2 -DLOG_LEVEL=10
+endif
+endif
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INC_DIR := -I ./include -I ../../include/tools_share -I ${OPENSSL_DIR}/include
+LIB_DIR := -L ${OPENSSL_DIR}/lib
+LIB := -lssl -lcrypto
+
+HOSTCC ?= gcc
+
+.PHONY: all clean realclean
+
+all: clean ${BINARY}
+
+${BINARY}: ${OBJECTS} Makefile
+       @echo "  HOSTLD  $@"
+       @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__;' | \
+                ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o
+       ${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@
+
+%.o: %.c
+       @echo "  HOSTCC  $<"
+       ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@
+
+clean:
+       $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
+
+realclean: clean
+       $(call SHELL_DELETE,${BINARY})
diff --git a/tools/encrypt_fw/include/cmd_opt.h b/tools/encrypt_fw/include/cmd_opt.h
new file mode 100644 (file)
index 0000000..bd7d31f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMD_OPT_H
+#define CMD_OPT_H
+
+#include <getopt.h>
+
+#define CMD_OPT_MAX_NUM                        64
+
+/* Supported long command line option types */
+enum {
+       CMD_OPT_FW
+};
+
+/* Structure to define a command line option */
+typedef struct cmd_opt_s {
+       struct option long_opt;
+       const char *help_msg;
+} cmd_opt_t;
+
+/* Exported API*/
+void cmd_opt_add(const cmd_opt_t *cmd_opt);
+const struct option *cmd_opt_get_array(void);
+const char *cmd_opt_get_name(int idx);
+const char *cmd_opt_get_help_msg(int idx);
+
+#endif /* CMD_OPT_H */
diff --git a/tools/encrypt_fw/include/debug.h b/tools/encrypt_fw/include/debug.h
new file mode 100644 (file)
index 0000000..ee8f1f5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/* The log output macros print output to the console. These macros produce
+ * compiled log output only if the LOG_LEVEL defined in the makefile (or the
+ * make command line) is greater or equal than the level required for that
+ * type of log output.
+ * The format expected is the same as for printf(). For example:
+ * INFO("Info %s.\n", "message")    -> INFO:    Info message.
+ * WARN("Warning %s.\n", "message") -> WARNING: Warning message.
+ */
+
+#define LOG_LEVEL_NONE                 0
+#define LOG_LEVEL_ERROR                        10
+#define LOG_LEVEL_NOTICE               20
+#define LOG_LEVEL_WARNING              30
+#define LOG_LEVEL_INFO                 40
+#define LOG_LEVEL_VERBOSE              50
+
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+# define NOTICE(...)   printf("NOTICE:  " __VA_ARGS__)
+#else
+# define NOTICE(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_ERROR
+# define ERROR(...)    printf("ERROR:   " __VA_ARGS__)
+#else
+# define ERROR(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_WARNING
+# define WARN(...)     printf("WARNING: " __VA_ARGS__)
+#else
+# define WARN(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+# define INFO(...)     printf("INFO:    " __VA_ARGS__)
+#else
+# define INFO(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+# define VERBOSE(...)  printf("VERBOSE: " __VA_ARGS__)
+#else
+# define VERBOSE(...)
+#endif
+
+#endif /* DEBUG_H */
diff --git a/tools/encrypt_fw/include/encrypt.h b/tools/encrypt_fw/include/encrypt.h
new file mode 100644 (file)
index 0000000..25d3011
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ENCRYPT_H
+#define ENCRYPT_H
+
+/* Supported key algorithms */
+enum {
+       KEY_ALG_GCM             /* AES-GCM (default) */
+};
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+                char *nonce_string, const char *ip_name, const char *op_name);
+
+#endif /* ENCRYPT_H */
diff --git a/tools/encrypt_fw/src/cmd_opt.c b/tools/encrypt_fw/src/cmd_opt.c
new file mode 100644 (file)
index 0000000..64180d1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cmd_opt.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "debug.h"
+
+/* Command line options */
+static struct option long_opt[CMD_OPT_MAX_NUM+1];
+static const char *help_msg[CMD_OPT_MAX_NUM+1];
+static int num_reg_opt;
+
+void cmd_opt_add(const cmd_opt_t *cmd_opt)
+{
+       assert(cmd_opt != NULL);
+
+       if (num_reg_opt >= CMD_OPT_MAX_NUM) {
+               ERROR("Out of memory. Please increase CMD_OPT_MAX_NUM\n");
+               exit(1);
+       }
+
+       long_opt[num_reg_opt].name = cmd_opt->long_opt.name;
+       long_opt[num_reg_opt].has_arg = cmd_opt->long_opt.has_arg;
+       long_opt[num_reg_opt].flag = 0;
+       long_opt[num_reg_opt].val = cmd_opt->long_opt.val;
+
+       help_msg[num_reg_opt] = cmd_opt->help_msg;
+
+       num_reg_opt++;
+}
+
+const struct option *cmd_opt_get_array(void)
+{
+       return long_opt;
+}
+
+const char *cmd_opt_get_name(int idx)
+{
+       if (idx >= num_reg_opt) {
+               return NULL;
+       }
+
+       return long_opt[idx].name;
+}
+
+const char *cmd_opt_get_help_msg(int idx)
+{
+       if (idx >= num_reg_opt) {
+               return NULL;
+       }
+
+       return help_msg[idx];
+}
diff --git a/tools/encrypt_fw/src/encrypt.c b/tools/encrypt_fw/src/encrypt.c
new file mode 100644 (file)
index 0000000..18a514c
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <firmware_encrypted.h>
+#include <openssl/evp.h>
+#include <stdio.h>
+#include <string.h>
+#include "debug.h"
+#include "encrypt.h"
+
+#define BUFFER_SIZE            256
+#define IV_SIZE                        12
+#define IV_STRING_SIZE         24
+#define TAG_SIZE               16
+#define KEY_SIZE               32
+#define KEY_STRING_SIZE                64
+
+static int gcm_encrypt(unsigned short fw_enc_status, char *key_string,
+                      char *nonce_string, const char *ip_name,
+                      const char *op_name)
+{
+       FILE *ip_file;
+       FILE *op_file;
+       EVP_CIPHER_CTX *ctx;
+       unsigned char data[BUFFER_SIZE], enc_data[BUFFER_SIZE];
+       unsigned char key[KEY_SIZE], iv[IV_SIZE], tag[TAG_SIZE];
+       int bytes, enc_len = 0, i, j, ret = 0;
+       struct fw_enc_hdr header;
+
+       memset(&header, 0, sizeof(struct fw_enc_hdr));
+
+       if (strlen(key_string) != KEY_STRING_SIZE) {
+               ERROR("Unsupported key size: %lu\n", strlen(key_string));
+               return -1;
+       }
+
+       for (i = 0, j = 0; i < KEY_SIZE; i++, j += 2) {
+               if (sscanf(&key_string[j], "%02hhx", &key[i]) != 1) {
+                       ERROR("Incorrect key format\n");
+                       return -1;
+               }
+       }
+
+       if (strlen(nonce_string) != IV_STRING_SIZE) {
+               ERROR("Unsupported IV size: %lu\n", strlen(nonce_string));
+               return -1;
+       }
+
+       for (i = 0, j = 0; i < IV_SIZE; i++, j += 2) {
+               if (sscanf(&nonce_string[j], "%02hhx", &iv[i]) != 1) {
+                       ERROR("Incorrect IV format\n");
+                       return -1;
+               }
+       }
+
+       ip_file = fopen(ip_name, "rb");
+       if (ip_file == NULL) {
+               ERROR("Cannot read %s\n", ip_name);
+               return -1;
+       }
+
+       op_file = fopen(op_name, "wb");
+       if (op_file == NULL) {
+               ERROR("Cannot write %s\n", op_name);
+               fclose(ip_file);
+               return -1;
+       }
+
+       ret = fseek(op_file, sizeof(struct fw_enc_hdr), SEEK_SET);
+       if (ret) {
+               ERROR("fseek failed\n");
+               goto out_file;
+       }
+
+       ctx = EVP_CIPHER_CTX_new();
+       if (ctx == NULL) {
+               ERROR("EVP_CIPHER_CTX_new failed\n");
+               ret = -1;
+               goto out_file;
+       }
+
+       ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+       if (ret != 1) {
+               ERROR("EVP_EncryptInit_ex failed\n");
+               ret = -1;
+               goto out;
+       }
+
+       ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
+       if (ret != 1) {
+               ERROR("EVP_EncryptInit_ex failed\n");
+               goto out;
+       }
+
+       while ((bytes = fread(data, 1, BUFFER_SIZE, ip_file)) != 0) {
+               ret = EVP_EncryptUpdate(ctx, enc_data, &enc_len, data, bytes);
+               if (ret != 1) {
+                       ERROR("EVP_EncryptUpdate failed\n");
+                       ret = -1;
+                       goto out;
+               }
+
+               fwrite(enc_data, 1, enc_len, op_file);
+       }
+
+       ret = EVP_EncryptFinal_ex(ctx, enc_data, &enc_len);
+       if (ret != 1) {
+               ERROR("EVP_EncryptFinal_ex failed\n");
+               ret = -1;
+               goto out;
+       }
+
+       ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag);
+       if (ret != 1) {
+               ERROR("EVP_CIPHER_CTX_ctrl failed\n");
+               ret = -1;
+               goto out;
+       }
+
+       header.magic = ENC_HEADER_MAGIC;
+       header.flags |= fw_enc_status & FW_ENC_STATUS_FLAG_MASK;
+       header.dec_algo = KEY_ALG_GCM;
+       header.iv_len = IV_SIZE;
+       header.tag_len = TAG_SIZE;
+       memcpy(header.iv, iv, IV_SIZE);
+       memcpy(header.tag, tag, TAG_SIZE);
+
+       ret = fseek(op_file, 0, SEEK_SET);
+       if (ret) {
+               ERROR("fseek failed\n");
+               goto out;
+       }
+
+       fwrite(&header, 1, sizeof(struct fw_enc_hdr), op_file);
+
+out:
+       EVP_CIPHER_CTX_free(ctx);
+
+out_file:
+       fclose(ip_file);
+       fclose(op_file);
+
+       /*
+        * EVP_* APIs returns 1 as success but enctool considers
+        * 0 as success.
+        */
+       if (ret == 1)
+               ret = 0;
+
+       return ret;
+}
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+                char *nonce_string, const char *ip_name, const char *op_name)
+{
+       switch (enc_alg) {
+       case KEY_ALG_GCM:
+               return gcm_encrypt(fw_enc_status, key_string, nonce_string,
+                                  ip_name, op_name);
+       default:
+               return -1;
+       }
+}
diff --git a/tools/encrypt_fw/src/main.c b/tools/encrypt_fw/src/main.c
new file mode 100644 (file)
index 0000000..39b7af7
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+
+#include "cmd_opt.h"
+#include "debug.h"
+#include "encrypt.h"
+#include "firmware_encrypted.h"
+
+#define NUM_ELEM(x)                    ((sizeof(x)) / (sizeof(x[0])))
+#define HELP_OPT_MAX_LEN               128
+
+/* Global options */
+
+/* Info messages created in the Makefile */
+extern const char build_msg[];
+
+static char *key_algs_str[] = {
+       [KEY_ALG_GCM] = "gcm",
+};
+
+static void print_help(const char *cmd, const struct option *long_opt)
+{
+       int rem, i = 0;
+       const struct option *opt;
+       char line[HELP_OPT_MAX_LEN];
+       char *p;
+
+       assert(cmd != NULL);
+       assert(long_opt != NULL);
+
+       printf("\n\n");
+       printf("The firmware encryption tool loads the binary image and\n"
+              "outputs encrypted binary image using an encryption key\n"
+              "provided as an input hex string.\n");
+       printf("\n");
+       printf("Usage:\n");
+       printf("\t%s [OPTIONS]\n\n", cmd);
+
+       printf("Available options:\n");
+       opt = long_opt;
+       while (opt->name) {
+               p = line;
+               rem = HELP_OPT_MAX_LEN;
+               if (isalpha(opt->val)) {
+                       /* Short format */
+                       sprintf(p, "-%c,", (char)opt->val);
+                       p += 3;
+                       rem -= 3;
+               }
+               snprintf(p, rem, "--%s %s", opt->name,
+                        (opt->has_arg == required_argument) ? "<arg>" : "");
+               printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
+               opt++;
+               i++;
+       }
+       printf("\n");
+}
+
+static int get_key_alg(const char *key_alg_str)
+{
+       int i;
+
+       for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
+               if (strcmp(key_alg_str, key_algs_str[i]) == 0) {
+                       return i;
+               }
+       }
+
+       return -1;
+}
+
+static void parse_fw_enc_status_flag(const char *arg,
+                                    unsigned short *fw_enc_status)
+{
+       unsigned long flag;
+       char *endptr;
+
+       flag = strtoul(arg, &endptr, 16);
+       if (*endptr != '\0' || flag > FW_ENC_WITH_BSSK) {
+               ERROR("Invalid fw_enc_status flag '%s'\n", arg);
+               exit(1);
+       }
+
+       *fw_enc_status = flag & FW_ENC_STATUS_FLAG_MASK;
+}
+
+/* Common command line options */
+static const cmd_opt_t common_cmd_opt[] = {
+       {
+               { "help", no_argument, NULL, 'h' },
+               "Print this message and exit"
+       },
+       {
+               { "fw-enc-status", required_argument, NULL, 'f' },
+               "Firmware encryption status flag (with SSK=0 or BSSK=1)."
+       },
+       {
+               { "key-alg", required_argument, NULL, 'a' },
+               "Encryption key algorithm: 'gcm' (default)"
+       },
+       {
+               { "key", required_argument, NULL, 'k' },
+               "Encryption key (for supported algorithm)."
+       },
+       {
+               { "nonce", required_argument, NULL, 'n' },
+               "Nonce or Initialization Vector (for supported algorithm)."
+       },
+       {
+               { "in", required_argument, NULL, 'i' },
+               "Input filename to be encrypted."
+       },
+       {
+               { "out", required_argument, NULL, 'o' },
+               "Encrypted output filename."
+       },
+};
+
+int main(int argc, char *argv[])
+{
+       int i, key_alg, ret;
+       int c, opt_idx = 0;
+       const struct option *cmd_opt;
+       char *key = NULL;
+       char *nonce = NULL;
+       char *in_fn = NULL;
+       char *out_fn = NULL;
+       unsigned short fw_enc_status = 0;
+
+       NOTICE("Firmware Encryption Tool: %s\n", build_msg);
+
+       /* Set default options */
+       key_alg = KEY_ALG_GCM;
+
+       /* Add common command line options */
+       for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
+               cmd_opt_add(&common_cmd_opt[i]);
+       }
+
+       /* Get the command line options populated during the initialization */
+       cmd_opt = cmd_opt_get_array();
+
+       while (1) {
+               /* getopt_long stores the option index here. */
+               c = getopt_long(argc, argv, "a:f:hi:k:n:o:", cmd_opt, &opt_idx);
+
+               /* Detect the end of the options. */
+               if (c == -1) {
+                       break;
+               }
+
+               switch (c) {
+               case 'a':
+                       key_alg = get_key_alg(optarg);
+                       if (key_alg < 0) {
+                               ERROR("Invalid key algorithm '%s'\n", optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'f':
+                       parse_fw_enc_status_flag(optarg, &fw_enc_status);
+                       break;
+               case 'k':
+                       key = optarg;
+                       break;
+               case 'i':
+                       in_fn = optarg;
+                       break;
+               case 'o':
+                       out_fn = optarg;
+                       break;
+               case 'n':
+                       nonce = optarg;
+                       break;
+               case 'h':
+                       print_help(argv[0], cmd_opt);
+                       exit(0);
+               case '?':
+               default:
+                       print_help(argv[0], cmd_opt);
+                       exit(1);
+               }
+       }
+
+       if (!key) {
+               ERROR("Key must not be NULL\n");
+               exit(1);
+       }
+
+       if (!nonce) {
+               ERROR("Nonce must not be NULL\n");
+               exit(1);
+       }
+
+       if (!in_fn) {
+               ERROR("Input filename must not be NULL\n");
+               exit(1);
+       }
+
+       if (!out_fn) {
+               ERROR("Output filename must not be NULL\n");
+               exit(1);
+       }
+
+       ret = encrypt_file(fw_enc_status, key_alg, key, nonce, in_fn, out_fn);
+
+       CRYPTO_cleanup_all_ex_data();
+
+       return ret;
+}