blob: 665f417fac433e389eb01b33bafaf5c702d088d2 [file] [log] [blame]
developer23f9f0f2023-06-15 13:06:25 +08001diff --git a/tools/Makefile b/tools/Makefile
2index ccd60a5..e487530 100644
3--- a/tools/Makefile
4+++ b/tools/Makefile
5@@ -38,6 +38,7 @@ tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
6 tools-$(CONFIG_USES_MINOR) += kernel2minor
7 tools-$(CONFIG_USE_SPARSE) += sparse
8 tools-y += openssl
9+tools-y += aesgcm
10
11 # builddir dependencies
12 $(curdir)/autoconf/compile := $(curdir)/m4/compile
13@@ -76,6 +77,7 @@ $(curdir)/squashfs/compile := $(curdir)/lzma-old/compile
14 $(curdir)/squashfskit4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile
15 $(curdir)/zlib/compile := $(curdir)/cmake/compile
16 $(curdir)/zstd/compile := $(curdir)/cmake/compile
17+$(curdir)/aesgcm/compile := $(curdir)/openssl/compile
18
19 ifneq ($(HOST_OS),Linux)
20 $(curdir)/squashfskit4/compile += $(curdir)/coreutils/compile
21diff --git a/tools/aesgcm/Makefile b/tools/aesgcm/Makefile
22new file mode 100644
23index 0000000..f7ffc53
24--- /dev/null
25+++ b/tools/aesgcm/Makefile
26@@ -0,0 +1,29 @@
27+#
28+# Copyright (C) 2022 MediaTek Inc. All rights reserved.
29+#
30+# This is free software, licensed under the GNU General Public License v2.
31+# See /LICENSE for more information.
32+#
33+include $(TOPDIR)/rules.mk
34+
35+PKG_NAME:=aesgcm
36+PKG_VERSION:=1.0
37+
38+include $(INCLUDE_DIR)/host-build.mk
39+
40+define Host/Compile
41+ $(MAKE) -C $(HOST_BUILD_DIR) \
42+ OPENSSL_INCS_LOCATION=-I$(STAGING_DIR_HOST)/include/openssl-3 \
43+ OPENSSL_LIBS_LOCATION=-L$(STAGING_DIR_HOST)/lib/openssl-3
44+endef
45+
46+define Host/Prepare
47+ mkdir -p $(HOST_BUILD_DIR)
48+ $(CP) -a ./src/* $(HOST_BUILD_DIR)/
49+endef
50+
51+define Host/Install
52+ $(CP) $(HOST_BUILD_DIR)/aesgcm $(STAGING_DIR_HOST)/bin/
53+endef
54+
55+$(eval $(call HostBuild))
56diff --git a/tools/aesgcm/src/Makefile b/tools/aesgcm/src/Makefile
57new file mode 100644
58index 0000000..18d2e7b
59--- /dev/null
60+++ b/tools/aesgcm/src/Makefile
61@@ -0,0 +1,12 @@
62+CFLAGS = $(OPENSSL_INCS_LOCATION)
63+LDFLAGS = $(OPENSSL_LIBS_LOCATION) -lssl -lcrypto -ldl -lpthread
64+
65+all: aesgcm
66+
67+aesgcm: aesgcm.o
68+
69+aesgcm:
70+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
71+
72+clean:
73+ $(RM) aesgcm
74diff --git a/tools/aesgcm/src/aesgcm.c b/tools/aesgcm/src/aesgcm.c
75new file mode 100644
76index 0000000..05aa373
77--- /dev/null
78+++ b/tools/aesgcm/src/aesgcm.c
79@@ -0,0 +1,364 @@
80+/*
81+ * Copyright 2022 Mediatek Inc. All Rights Reserved.
82+ *
83+ * Licensed under the Apache License 2.0 (the "License"). You may not use
84+ * this file except in compliance with the License. You can obtain a copy
85+ * in the file LICENSE in the source distribution or at
86+ * https://www.openssl.org/source/license.html
87+ */
88+
89+/*
90+ * Simple AES GCM authenticated encryption with additional data (AEAD)
91+ * demonstration program.
92+ */
93+
94+#include <stdlib.h>
95+#include <stddef.h>
96+#include <string.h>
97+#include <unistd.h>
98+#include <openssl/err.h>
99+#include <openssl/bio.h>
100+#include <openssl/evp.h>
101+#include <openssl/core_names.h>
102+
103+#define MAX_TEXT_LENGTH 4096
104+#define MAX_AAD_LENGTH 256
105+#define MAX_TAG_LENGTH 32
106+
107+#define ERR_ENC 1
108+#define ERR_DEC 2
109+#define ERR_UNK_MOD 3
110+
111+typedef enum {
112+ UNK,
113+ ENCRYPT,
114+ DECRYPT
115+} OPERATION;
116+
117+/*
118+ * A library context and property query can be used to select & filter
119+ * algorithm implementations. If they are NULL then the default library
120+ * context and properties are used.
121+ */
122+OSSL_LIB_CTX *libctx = NULL;
123+const char *propq = NULL;
124+
125+int aes_gcm_encrypt(uint8_t *key, uint8_t *iv, long iv_len, uint8_t *aad,
126+ long aad_len, uint8_t *pt, long pt_len, BIO *out)
127+{
128+ int ret = 0;
129+ EVP_CIPHER_CTX *ctx;
130+ EVP_CIPHER *cipher = NULL;
131+ int outlen, tmplen;
132+ uint8_t *outbuf;
133+ uint8_t *outtag[16];
134+ OSSL_PARAM params[2] = {
135+ OSSL_PARAM_END, OSSL_PARAM_END
136+ };
137+
138+ outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
139+ if (!outbuf)
140+ return 0;
141+
142+ /* Create a context for the encrypt operation */
143+ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
144+ goto err;
145+
146+ /* Fetch the cipher implementation */
147+ if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
148+ goto err;
149+
150+ /* Set IV length if default 96 bits is not appropriate */
151+ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
152+ &iv_len);
153+ /*
154+ * Initialise an encrypt operation with the cipher/mode, key, IV and
155+ * IV length parameter.
156+ * For demonstration purposes the IV is being set here. In a compliant
157+ * application the IV would be generated internally so the iv passed in
158+ * would be NULL.
159+ */
160+ if (!EVP_EncryptInit_ex2(ctx, cipher, key, iv, params))
161+ goto err;
162+
163+ /* Zero or more calls to specify any AAD */
164+ if (!EVP_EncryptUpdate(ctx, NULL, &outlen, aad, aad_len))
165+ goto err;
166+
167+ /* Encrypt plaintext */
168+ if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, pt, pt_len))
169+ goto err;
170+
171+ /* Finalise: note get no output for GCM */
172+ if (!EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))
173+ goto err;
174+
175+ /* Get tag */
176+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
177+ outtag, 16);
178+
179+ if (!EVP_CIPHER_CTX_get_params(ctx, params))
180+ goto err;
181+
182+ /* Output IV */
183+ if (BIO_write(out, iv, iv_len) <= 0)
184+ goto err;
185+
186+ /* Output tag */
187+ if (BIO_write(out, outtag, 16) <= 0)
188+ goto err;
189+
190+ /* Output encrypted block */
191+ if (BIO_write(out, outbuf, outlen) <= 0)
192+ goto err;
193+
194+ ret = 1;
195+err:
196+ if (!ret)
197+ ERR_print_errors_fp(stderr);
198+
199+ free(outbuf);
200+ EVP_CIPHER_free(cipher);
201+ EVP_CIPHER_CTX_free(ctx);
202+
203+ return ret;
204+}
205+
206+int aes_gcm_decrypt(uint8_t *key, uint8_t *iv, long iv_len,
207+ uint8_t *aad, long aad_len, uint8_t *ct, long ct_len,
208+ uint8_t *tag, long tag_len, BIO *out)
209+{
210+ int ret = 0;
211+ EVP_CIPHER_CTX *ctx;
212+ EVP_CIPHER *cipher = NULL;
213+ int outlen, rv;
214+ uint8_t *outbuf;
215+ OSSL_PARAM params[2] = {
216+ OSSL_PARAM_END, OSSL_PARAM_END
217+ };
218+
219+ outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
220+ if (!outbuf)
221+ return 0;
222+
223+ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
224+ goto err;
225+
226+ /* Fetch the cipher implementation */
227+ if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
228+ goto err;
229+
230+ /* Set IV length if default 96 bits is not appropriate */
231+ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
232+ &iv_len);
233+
234+ /*
235+ * Initialise an encrypt operation with the cipher/mode, key, IV and
236+ * IV length parameter.
237+ */
238+ if (!EVP_DecryptInit_ex2(ctx, cipher, key, iv, params))
239+ goto err;
240+
241+ /* Zero or more calls to specify any AAD */
242+ if (!EVP_DecryptUpdate(ctx, NULL, &outlen, aad, aad_len))
243+ goto err;
244+
245+ /* Decrypt plaintext */
246+ if (!EVP_DecryptUpdate(ctx, outbuf, &outlen, ct, ct_len))
247+ goto err;
248+
249+ /* Output decrypted block */
250+ if (BIO_write(out, outbuf, outlen) <= 0)
251+ goto err;
252+
253+ /* Set expected tag value. */
254+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
255+ (void *)tag, tag_len);
256+
257+ if (!EVP_CIPHER_CTX_set_params(ctx, params))
258+ goto err;
259+
260+ /* Finalise: note get no output for GCM */
261+ rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen);
262+ /*
263+ * Print out return value. If this is not successful authentication
264+ * failed and plaintext is not trustworthy.
265+ */
266+ printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!");
267+
268+ ret = rv > 0 ? 1 : 0;
269+err:
270+ if (!ret)
271+ ERR_print_errors_fp(stderr);
272+
273+ free(outbuf);
274+ EVP_CIPHER_free(cipher);
275+ EVP_CIPHER_CTX_free(ctx);
276+
277+ return ret;
278+}
279+
280+void usage(void)
281+{
282+ printf(
283+ "simple aes-256-gcm tool: \n"
284+ "Operations:\n"
285+ "-e - encrypt\n"
286+ "-d - decrypt\n"
287+ "Common requirement parameters:\n"
288+ "-i infile - input file\n"
289+ "-o outfile - out file\n"
290+ "-k key(hex) - key in hex\n"
291+ "-n iv(hex) - initial vector in hex\n"
292+ "-a aad(hex) - additional authentication data in hex\n"
293+ "Decryption requirement paremters:\n"
294+ "-t intagfile - tag file as input\n");
295+}
296+
297+int main(int argc, char **argv)
298+{
299+ int ret = 0, opt, oper = UNK;
300+ long key_len = 0, iv_len = 0, aad_len = 0, tag_len = 0, in_len = 0;
301+ BIO *in = NULL, *out = NULL, *in_tag = NULL;
302+ uint8_t *in_buf;
303+ uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
304+ uint8_t iv[EVP_MAX_IV_LENGTH] = {0};
305+ uint8_t aad[MAX_AAD_LENGTH] = {0};
306+ uint8_t tag[MAX_TAG_LENGTH] = {0};
307+
308+ in_buf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
309+ if (!in_buf)
310+ return -ENOMEM;
311+
312+ while ((opt = getopt(argc, argv, "a:dei:g:k:n:o:t:")) > 0) {
313+ switch(opt) {
314+ case 'a':
315+ ret = OPENSSL_hexstr2buf_ex(aad, MAX_AAD_LENGTH,
316+ &aad_len, optarg, '\0');
317+ if (!ret) {
318+ ret = -EINVAL;
319+ fprintf(stderr, "Failed to read aad\n");
320+ goto end;
321+ }
322+ break;
323+ case 'd':
324+ if (oper) {
325+ ret = -EINVAL;
326+ fprintf(stderr, "Duplicate operations\n");
327+ goto end;
328+ }
329+ oper = DECRYPT;
330+ break;
331+ case 'e':
332+ if (oper) {
333+ ret = -EINVAL;
334+ fprintf(stderr, "Duplicate operations\n");
335+ goto end;
336+ }
337+ oper = ENCRYPT;
338+ break;
339+ case 'i':
340+ in = BIO_new_file(optarg, "rb");
341+ if (!in) {
342+ ret = -EINVAL;
343+ fprintf(stderr, "Failed to open input file\n");
344+ goto end;
345+ }
346+
347+ in_len = BIO_read(in, in_buf, MAX_TEXT_LENGTH);
348+ if (in_len <= 0) {
349+ ret = -EINVAL;
350+ fprintf(stderr, "Failed to read input file\n");
351+ goto end;
352+ }
353+ break;
354+ case 'k':
355+ ret = OPENSSL_hexstr2buf_ex(key, EVP_MAX_KEY_LENGTH,
356+ &key_len, optarg, '\0');
357+ if (!ret) {
358+ ret = -EINVAL;
359+ fprintf(stderr, "Failed to read key\n");
360+ goto end;
361+ }
362+ break;
363+ case 'n':
364+ ret = OPENSSL_hexstr2buf_ex(iv, EVP_MAX_IV_LENGTH,
365+ &iv_len, optarg, '\0');
366+ if (!ret) {
367+ ret = -EINVAL;
368+ fprintf(stderr, "Failed to read iv\n");
369+ goto end;
370+ }
371+ break;
372+ case 'o':
373+ out = BIO_new_file(optarg, "w");
374+ if (!out) {
375+ ret = -EINVAL;
376+ fprintf(stderr, "Failed to open output file\n");
377+ goto end;
378+ }
379+ break;
380+ case 't':
381+ in_tag = BIO_new_file(optarg, "rb");
382+ if (!in_tag) {
383+ ret = -EINVAL;
384+ fprintf(stderr, "Failed to open tag file\n");
385+ goto end;
386+ }
387+
388+ tag_len = BIO_read(in_tag, tag, MAX_TAG_LENGTH);
389+ if (tag_len <= 0) {
390+ ret = -EINVAL;
391+ fprintf(stderr, "Failed to read tag file\n");
392+ goto end;
393+ }
394+ break;
395+ default:
396+ break;
397+ }
398+
399+ }
400+
401+ if (!key_len || !iv_len || !aad_len || !in_len || !out) {
402+ ret = -EINVAL;
403+ goto end;
404+ }
405+
406+ if (oper == ENCRYPT) {
407+ ret = aes_gcm_encrypt(key, iv, iv_len, aad, aad_len,
408+ in_buf, in_len, out);
409+ if (!ret) {
410+ ret = -ERR_ENC;
411+ goto end;
412+ }
413+ } else if (oper == DECRYPT) {
414+ if (!tag_len) {
415+ ret = -EINVAL;
416+ goto end;
417+ }
418+
419+ ret = aes_gcm_decrypt(key, iv, iv_len, aad, aad_len,
420+ in_buf, in_len, tag, tag_len, out);
421+ if (!ret) {
422+ ret = -ERR_DEC;
423+ goto end;
424+ }
425+ } else {
426+ ret = -ERR_UNK_MOD;
427+ goto end;
428+ }
429+
430+end:
431+ free(in_buf);
432+ if (in)
433+ BIO_free(in);
434+ if (out)
435+ BIO_free(out);
436+ if (in_tag)
437+ BIO_free(in_tag);
438+
439+ if (ret == -EINVAL)
440+ usage();
441+
442+ return ret;
443+}