blob: c150d7d00b512c25a0bf076b6503b4d28146b42f [file] [log] [blame]
--- a/Makefile.am
+++ b/Makefile.am
@@ -193,6 +193,16 @@ EXTRA_bin_kcapi_rng_DEPENDENCIES = libto
SCAN_FILES += $(bin_kcapi_rng_SOURCES)
man_MANS += apps/kcapi-rng.1
+
+bin_PROGRAMS += bin/kcapi-drbg
+
+bin_kcapi_drbg_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/lib/
+bin_kcapi_drbg_LDFLAGS = $(COMMON_LDFLAGS)
+bin_kcapi_drbg_LDADD = libkcapi.la
+bin_kcapi_drbg_SOURCES = apps/kcapi-drbg.c apps/app-internal.c
+EXTRA_bin_kcapi_rng_DEPENDENCIES = libtool
+
+SCAN_FILES += $(bin_kcapi_drbg_SOURCES)
endif
if ENABLE_KCAPI_ENCAPP
--- /dev/null
+++ b/apps/kcapi-drbg.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2023, MediaTek Inc. All rights reserved.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <kcapi.h>
+
+#include "app-internal.h"
+
+/* For efficiency reasons, this should be identical to algif_rng.c:MAXSIZE. */
+#define KCAPI_RNG_BUFSIZE 2048
+
+static struct kcapi_handle *rng = NULL;
+static char *rng_name = NULL;
+static bool hexout = false;
+static unsigned char* entropy = NULL;
+static unsigned char* nonce = NULL;
+static unsigned char* per = NULL;
+static unsigned char* additional_1 = NULL;
+static unsigned char* additional_2 = NULL;
+static uint32_t entropy_len = 0;
+static uint32_t nonce_len = 0;
+static uint32_t per_len = 0;
+static uint32_t add1_len = 0;
+static uint32_t add2_len = 0;
+
+
+
+static unsigned char* hextobin(char* hexstr, uint32_t *ret_len) {
+ uint32_t len = strlen(hexstr);
+ size_t i = 0;
+ char *pos = hexstr;
+ unsigned char *ret = (unsigned char*) malloc((len + 1) / 2);
+
+ for (i = 0; i < (len + 1) / 2; i++) {
+ if(i == 0 && (len % 2) == 1) {
+ sscanf(pos, "%1hhx", &ret[i]);
+ pos += 1;
+ } else {
+ sscanf(pos, "%2hhx", &ret[i]);
+ pos += 2;
+ }
+ }
+ *ret_len = (len + 1) / 2;
+
+ return ret;
+}
+
+static void uninit() {
+ memset(entropy, 0, entropy_len);
+ memset(nonce, 0, nonce_len);
+ memset(per, 0, per_len);
+ memset(additional_1, 0, add1_len);
+ memset(additional_2, 0, add2_len);
+ if(entropy)
+ free(entropy);
+ if(nonce)
+ free(nonce);
+ if(per)
+ free(per);
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "\nKernel Crypto API DRBG\n");
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\t-b --bytes <BYTES>\tNumber of bytes to generate (required option)\n");
+ fprintf(stderr, "\t-r --rng name <RNGNAME>\tDRNG name as advertised in /proc/crypto(require option))\n");
+ fprintf(stderr, "\t-e --entropy <RNGNAME>\tDRBG entropy(require option))\n");
+ fprintf(stderr, "\t-n --nonce <RNGNAME>\tDRBG nonce(require option))\n");
+ fprintf(stderr, "\t-p --personaliztion string <RNGNAME>\tDRBG personaliztion string(require option))\n");
+ fprintf(stderr, "\t --hex\t\tThe random number is returned in hexadecimal\n");
+ fprintf(stderr, "\t\t\t\tnotation\n");
+ fprintf(stderr, "\t-h --help\t\tThis help information\n");
+
+ uninit();
+ exit(1);
+}
+
+static int parse_opts(int argc, char *argv[], size_t *outlen)
+{
+ int c = 0;
+ size_t bytes = 0;
+
+ while (1) {
+ int opt_index = 0;
+ static struct option opts[] = {
+ {"entropy", required_argument, 0, 'e'},
+ {"nonce", required_argument, 0, 'n'},
+ {"bytes", required_argument, 0, 'b'},
+ {"rng_name", required_argument, 0, 'r'},
+ {"personal_strng ", required_argument, 0, 'p'},
+ {"help", no_argument, 0, 'h'},
+ {"hex", no_argument, 0, 0},
+ {"additionalinput1 ", required_argument, 0, 'a'},
+ {"additionalinput2 ", required_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, "e:n:b:r:p:ha:c:", opts, &opt_index);
+ if (-1 == c)
+ break;
+ switch (c) {
+ case 0:
+ switch (opt_index) {
+ case 0:
+ entropy = hextobin(optarg, &entropy_len);
+ break;
+ case 1:
+ nonce = hextobin(optarg, &nonce_len);
+ break;
+ case 2:
+ bytes = strtoul(optarg, NULL, 10);
+ if (bytes == ULONG_MAX) {
+ usage();
+ return -EINVAL;
+ }
+ break;
+ case 3:
+ rng_name = optarg;
+ break;
+ case 4:
+ per = hextobin(optarg, &per_len);
+ break;
+ case 5:
+ usage();
+ break;
+ case 6:
+ hexout = true;
+ break;
+ case 7:
+ additional_1 = hextobin(optarg, &add1_len);
+ break;
+ case 8:
+ additional_2 = hextobin(optarg, &add2_len);
+ break;
+ default:
+ usage();
+ }
+ break;
+ case 'e':
+ entropy = hextobin(optarg, &entropy_len);
+ break;
+ case 'n':
+ nonce = hextobin(optarg, &nonce_len);
+ break;
+ case 'b':
+ bytes = strtoul(optarg, NULL, 10);
+ if (bytes == ULONG_MAX) {
+ usage();
+ return -EINVAL;
+ }
+ break;
+ case 'r':
+ rng_name = optarg;
+ break;
+ case 'p':
+ per = hextobin(optarg, &per_len);
+ break;
+ case 'a':
+ additional_1 = hextobin(optarg, &add1_len);
+ break;
+ case 'c':
+ additional_2 = hextobin(optarg, &add2_len);
+ break;
+ default:
+ usage();
+ }
+ }
+ if (!bytes || !nonce || !entropy || !rng_name)
+ usage();
+
+ *outlen = (size_t)bytes;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ ssize_t ret = 0;
+ uint8_t buf[KCAPI_RNG_BUFSIZE] __aligned(KCAPI_APP_ALIGN);
+ uint8_t *seedbuf = buf;
+ uint32_t seedsize = 0;
+ size_t outlen = 0;
+ unsigned char *ent = NULL;
+ int count = 2;
+
+ ret = parse_opts(argc, argv, &outlen);
+ if (ret)
+ return (int)ret;
+
+ ret = kcapi_rng_init(&rng, rng_name, 0);
+ if (ret)
+ return (int)ret;
+
+ seedsize = kcapi_rng_seedsize(rng);
+
+ ent = (unsigned char*)malloc(entropy_len + nonce_len + per_len);
+ memset(ent, 0, entropy_len + nonce_len + per_len);
+ memcpy(ent, entropy, entropy_len);
+ memcpy(ent + entropy_len, nonce, nonce_len);
+ memcpy(ent + entropy_len + nonce_len, per, per_len);
+
+ kcapi_rng_setentropy(rng, ent, entropy_len + nonce_len + per_len);
+
+ ret = kcapi_rng_seed(rng, seedbuf, seedsize);
+ if (ret)
+ goto out;
+
+ while(count --) {
+ size_t len = outlen;
+ while (len) {
+ size_t todo = (len < KCAPI_RNG_BUFSIZE) ?
+ len : KCAPI_RNG_BUFSIZE;
+
+ if(count == 1 && additional_1) {
+ kcapi_rng_setaddtl(rng, additional_1, add1_len);
+ } else if(count == 0 && additional_2 ){
+ kcapi_rng_setaddtl(rng, additional_2, add2_len);
+ }
+
+ ret = kcapi_rng_generate(rng, buf, todo);
+ if (ret < 0)
+ goto out;
+
+ if ((uint32_t)ret == 0) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if(count == 0) {
+ if (hexout) {
+ char hexbuf[2 * KCAPI_RNG_BUFSIZE];
+
+ bin2hex(buf, (size_t)ret, hexbuf, sizeof(hexbuf), 0);
+ fwrite(hexbuf, 2 * (size_t)ret, 1, stdout);
+ } else {
+ fwrite(buf, (size_t)ret, 1, stdout);
+ }
+ }
+ len -= (size_t)ret;
+ }
+ }
+
+ ret = 0;
+out:
+ if (rng)
+ kcapi_rng_destroy(rng);
+ kcapi_memset_secure(buf, 0, sizeof(buf));
+
+ if (seedbuf && (seedbuf != buf)) {
+ kcapi_memset_secure(seedbuf, 0, seedsize);
+ free(seedbuf);
+ }
+
+ uninit();
+ if(!ent)
+ free(ent);
+
+ return (int)ret;
+}